go-libp2p-core
go-libp2p-core copied to clipboard
Unable to marshal / unmarshal AddrInfo within my struct
I need to unicast messages to other peers on my network. I want to store the AddrInfo struct on my message so I have the nodes addr who unicast me so I can send a response back.
func init() {
gob.Register(&Message{})
}
// Message stores a type of message and a body.
// The message is the data that gets passed between nodes when they communicate.
type Message struct {
ID string `json:"id"`
Body []byte `json:"body"` // the actual payload.
OriginNode peer.AddrInfo `json:"origin_node"` // the node that sent the message
}
// NewMessage builds up a new message.
func NewMessage(b []byte, o peer.AddrInfo) Message {
return Message{
ID: uuid.New().String(),
Body: b,
OriginNode: o,
}
}
// Marshal takes a node message and marshals it into an array of bytes.
func (m Message) Marshal() []byte {
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
if err := enc.Encode(m); err != nil {
zap.S().Fatal(err)
}
return buf.Bytes()
}
// UnmarshalMessage takes a slice of bytes and a returns a message struct.
func UnmarshalMessage(input []byte) (Message, error) {
msg := Message{}
buf := bytes.NewBuffer(input)
dec := gob.NewDecoder(buf)
if err := dec.Decode(&msg); err != nil {
return Message{}, err
}
return msg, nil
}
When I marshal my message struct and then attempt to unmarshal I receive the following error:
panic: interface conversion: interface is nil, not encoding.BinaryUnmarshaler [recovered] panic: interface conversion: interface is nil, not encoding.BinaryUnmarshaler UnmarshalMessage(0xc0001c7200, 0x454, 0x480, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, .
Is there something I need to do to be able to marshal and unmarshal my struct that contains the peer.AddrInfo
?
cc @Stebalien @marten-seemann
This seems to be a problem with encoding/gob
, not in our stack. If I just use encoding/json
everything works fine:
// Message stores a type of message and a body.
// The message is the data that gets passed between nodes when they communicate.
type Message struct {
ID string `json:"id"`
Body []byte `json:"body"` // the actual payload.
OriginNode peer.AddrInfo `json:"origin_node"` // the node that sent the message
}
// NewMessage builds up a new message.
func NewMessage(b []byte, o peer.AddrInfo) Message {
return Message{
ID: "identifier",
Body: b,
OriginNode: o,
}
}
// Marshal takes a node message and marshals it into an array of bytes.
func (m Message) Marshal() ([]byte, error) {
return json.Marshal(m)
}
// UnmarshalMessage takes a slice of bytes and a returns a message struct.
func UnmarshalMessage(input []byte) (Message, error) {
msg := Message{}
return msg, json.Unmarshal(input, &msg)
}
I'm not really familiar with encoding/gob
to be honest, but here's the relevant part of the stack trace:
panic(0x131e400, 0xc00009de60)
/usr/local/Cellar/go/1.15.7_1/libexec/src/runtime/panic.go:969 +0x1b9
encoding/gob.catchError(0xc00012c0f0)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/error.go:38 +0x85
panic(0x131e400, 0xc00009de60)
/usr/local/Cellar/go/1.15.7_1/libexec/src/runtime/panic.go:969 +0x1b9
encoding/gob.(*Decoder).decodeGobDecoder(0xc00012c080, 0xc0000cdcc0, 0xc0000b1760, 0x1342be0, 0xc000099fb0, 0x194)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:736 +0x1fd
encoding/gob.(*Decoder).gobDecodeOpFor.func1(0xc0001481c0, 0xc0000b1760, 0x1342be0, 0xc000099fb0, 0x194)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:960 +0x7a
encoding/gob.(*Decoder).decodeArrayHelper(0xc00012c080, 0xc0000b1760, 0x1303b60, 0xc0000e4268, 0x197, 0xc0000b1960, 0x1, 0x14df3e0, 0xc000099fa0, 0x0)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:530 +0x179
encoding/gob.(*Decoder).decodeSlice(0xc00012c080, 0xc0000b1760, 0x1303b60, 0xc0000e4268, 0x197, 0xc0000b1960, 0x14df3e0, 0xc000099fa0, 0x0)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:630 +0x23c
encoding/gob.(*Decoder).decOpFor.func3(0xc0000ce8f8, 0xc0000b1760, 0x1303b60, 0xc0000e4268, 0x197)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:848 +0x78
encoding/gob.(*Decoder).decodeStruct(0xc00012c080, 0xc0000b1920, 0x133a2e0, 0xc0000e4258, 0x199)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:471 +0xe6
encoding/gob.(*Decoder).decOpFor.func4(0xc0000bc800, 0xc0000b1740, 0x133a2e0, 0xc0000e4258, 0x199)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:860 +0x54
encoding/gob.(*Decoder).decodeStruct(0xc00012c080, 0xc0000b1900, 0x133fda0, 0xc0000e4230, 0x199)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:471 +0xe6
encoding/gob.(*Decoder).decodeValue(0xc00012c080, 0x41, 0x1316d40, 0xc0000e4230, 0x16)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decode.go:1205 +0x2c5
encoding/gob.(*Decoder).DecodeValue(0xc00012c080, 0x1316d40, 0xc0000e4230, 0x16, 0x0, 0x0)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decoder.go:213 +0x146
encoding/gob.(*Decoder).Decode(0xc00012c080, 0x1316d40, 0xc0000e4230, 0xc000099c40, 0x1)
/usr/local/Cellar/go/1.15.7_1/libexec/src/encoding/gob/decoder.go:188 +0x173
github.com/libp2p/go-libp2p-core/cmd.UnmarshalMessage(0xc00013e000, 0xd2, 0x17c, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
It looks like we need to implement BinaryUnmarshal.
But I'm not sure how to actually do this unless we want to define a custom "binary" format for address info objects.