Commit c5b08706 authored by Levin Zimmermann's avatar Levin Zimmermann

go/neo/proto/msgpack: Fix decoding of unset IdTime

The data type of IdTime is 'Optional[float]' [1], [2]. Before this patch the
msgpack decoder could only decode 'IdTime' in case its data type was
'float'. Now it also supports the decoding of IdTime in case it is NIL.

Without this patch, NEO/go client tests fail [3].

[1] See here, the fifth argument is IdTime:

    https://lab.nexedi.com/nexedi/neoppod/-/blob/3ddb6663/neo/master/handlers/identification.py#L26-27

    This is found to be 'Optional[float]':

    https://lab.nexedi.com/nexedi/neoppod/-/blob/3ddb6663/neo/tests/protocol#L98

[2] This seems to be true for both, pre-msgpack and post-msgpack
    protocol, because in the pre-msgpack NEO/go there is already this
    note:

    https://lab.nexedi.com/kirr/neo/-/blob/1ad088c8/go/neo/proto/proto.go#L352-357

[3] When running NEO/go client tests without this patch, we can see in the NEO/go log file:

```
I0820 13:05:23.813992 1138432 connect.go:115] C?: talk master(127.0.0.1:29203): dial 127.0.0.1:29203 (MASTER): [
I0820 13:05:23.816456 1138432 connect.go:122] C?: talk master(127.0.0.1:29203): dial 127.0.0.1:29203 (MASTER): dialed ok; requesting identification...
I0820 13:05:23.817337 1138432 connect.go:180] C?: talk master(127.0.0.1:29203): dial 127.0.0.1:29203 (MASTER): identification accepted
I0820 13:05:23.817346 1138432 connect.go:181] C?: talk master(127.0.0.1:29203): dial 127.0.0.1:29203 (MASTER): ]
I0820 13:05:23.817369 1138432 mastered.go:187] C?: talk M1: [
I0820 13:05:23.817401 1138432 mastered.go:195] C?: talk M1: ] (after identification: expect nodeTab: 127.0.0.1:41678 - 127.0.0.1:29203 .0: decode: decode: M: NotifyNodeInformation.IdTime: msgp: attempted to decode type "nil" with method for "float64")
W0820 13:05:23.817429 1138432 mastered.go:127] C?: talk master(127.0.0.1:29203): C?: talk M1: after identification: expect nodeTab: 127.0.0.1:41678 - 127.0.0.1:29203 .0: decode: decode: M: NotifyNodeInformation.IdTime: msgp: attempted to decode type "nil" with method for "float64"
```
parent afe76d47
......@@ -313,6 +313,7 @@ package proto
import (
"encoding/binary"
"math"
"reflect"
"sort"
......@@ -1137,7 +1138,7 @@ func (d *decoderM) genBasic(assignto string, typ *types.Basic, userType types.Ty
}
// mgetfloat emits mgetfloat<size>
mgetfloat := func(size int) {
mgetfloat := func(size int, optionalValue string) {
// delving into msgp - flush/prepare next site for overflow check
d.overflowCheck()
d.resetPos()
......@@ -1146,7 +1147,22 @@ func (d *decoderM) genBasic(assignto string, typ *types.Basic, userType types.Ty
d.emit("{")
d.emit("v, tail, err := msgp.ReadFloat%dBytes(data)", size)
d.emit("if err != nil {")
d.emit(" return 0, mdecodeErr(%q, err)", d.pathName(assignto))
if optionalValue != "" {
// ReadFloat%dBytes returns 'ErrShortBytes' in case prefix is
// correct float, but data is too short - catch this to return
// 'ErrDecodeOverflow' instead of type error.
d.emit(" err = mdecodeErr(%q, err)", d.pathName(assignto))
d.emit(" if err == ErrDecodeOverflow {")
d.emit(" return 0, err")
d.emit(" }")
d.emit(" tail, err = msgp.ReadNilBytes(data)")
d.emit(" if err != nil {")
d.emit(" return 0, mdecodeErr(%q, err)", d.pathName(assignto))
d.emit(" }")
d.emit(" v = %v", optionalValue)
} else {
d.emit(" return 0, mdecodeErr(%q, err)", d.pathName(assignto))
}
d.emit("}")
d.emit("%s= %s", assignto, v)
d.emit("%v += uint64(len(data) - len(tail))", d.var_("nread"))
......@@ -1154,6 +1170,14 @@ func (d *decoderM) genBasic(assignto string, typ *types.Basic, userType types.Ty
d.emit("}")
}
// IdTime can be nil ('None' in py), in this case we use
// infinite -1, see
// https://lab.nexedi.com/kirr/neo/-/blob/1ad088c8/go/neo/proto/proto.go#L352-357
if typeName(userType) == "IdTime" {
mgetfloat(64, "math.Inf(-1)")
return
}
switch typ.Kind() {
case types.Bool:
d.emit("switch op := msgpack.Op(data[%v]); op {", d.n)
......@@ -1175,7 +1199,7 @@ func (d *decoderM) genBasic(assignto string, typ *types.Basic, userType types.Ty
case types.Uint32: mgetint("u", 32)
case types.Uint64: mgetint("u", 64)
case types.Float64: mgetfloat(64)
case types.Float64: mgetfloat(64, "")
}
}
......
......@@ -6,6 +6,7 @@ package proto
import (
"encoding/binary"
"math"
"reflect"
"sort"
......@@ -418,7 +419,15 @@ func (p *RequestIdentification) neoMsgDecodeM(data []byte) (int, error) {
{
v, tail, err := msgp.ReadFloat64Bytes(data)
if err != nil {
return 0, mdecodeErr("RequestIdentification.IdTime", err)
err = mdecodeErr("RequestIdentification.IdTime", err)
if err == ErrDecodeOverflow {
return 0, err
}
tail, err = msgp.ReadNilBytes(data)
if err != nil {
return 0, mdecodeErr("RequestIdentification.IdTime", err)
}
v = math.Inf(-1)
}
p.IdTime = IdTime(v)
nread += uint64(len(data) - len(tail))
......@@ -1114,7 +1123,15 @@ func (p *NotifyNodeInformation) neoMsgDecodeM(data []byte) (int, error) {
{
v, tail, err := msgp.ReadFloat64Bytes(data)
if err != nil {
return 0, mdecodeErr("NotifyNodeInformation.IdTime", err)
err = mdecodeErr("NotifyNodeInformation.IdTime", err)
if err == ErrDecodeOverflow {
return 0, err
}
tail, err = msgp.ReadNilBytes(data)
if err != nil {
return 0, mdecodeErr("NotifyNodeInformation.IdTime", err)
}
v = math.Inf(-1)
}
p.IdTime = IdTime(v)
nread += uint64(len(data) - len(tail))
......@@ -1210,7 +1227,15 @@ func (p *NotifyNodeInformation) neoMsgDecodeM(data []byte) (int, error) {
{
v, tail, err := msgp.ReadFloat64Bytes(data)
if err != nil {
return 0, mdecodeErr("NotifyNodeInformation.IdTime", err)
err = mdecodeErr("NotifyNodeInformation.IdTime", err)
if err == ErrDecodeOverflow {
return 0, err
}
tail, err = msgp.ReadNilBytes(data)
if err != nil {
return 0, mdecodeErr("NotifyNodeInformation.IdTime", err)
}
v = math.Inf(-1)
}
(*a).IdTime = IdTime(v)
nread += uint64(len(data) - len(tail))
......@@ -6692,7 +6717,15 @@ func (p *AnswerNodeList) neoMsgDecodeM(data []byte) (int, error) {
{
v, tail, err := msgp.ReadFloat64Bytes(data)
if err != nil {
return 0, mdecodeErr("AnswerNodeList.IdTime", err)
err = mdecodeErr("AnswerNodeList.IdTime", err)
if err == ErrDecodeOverflow {
return 0, err
}
tail, err = msgp.ReadNilBytes(data)
if err != nil {
return 0, mdecodeErr("AnswerNodeList.IdTime", err)
}
v = math.Inf(-1)
}
(*a).IdTime = IdTime(v)
nread += uint64(len(data) - len(tail))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment