neoneo-go/pkg/network/payload/version.go
2018-01-28 11:12:05 +01:00

98 lines
2.5 KiB
Go

package payload
import (
"encoding/binary"
)
const (
minVersionSize = 27
)
// Version payload.
type Version struct {
// currently the version of the protocol is 0
Version uint32
// currently 1
Services uint64
// timestamp
Timestamp uint32
// port this server is listening on
Port uint16
// it's used to distinguish the node from public IP
Nonce uint32
// client id
UserAgent []byte
// Height of the block chain
StartHeight uint32
// Whether to receive and forward
Relay bool
}
// NewVersion returns a pointer to a Version payload.
func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version {
return &Version{
Version: 0,
Services: 1,
Timestamp: 12345,
Port: p,
Nonce: id,
UserAgent: []byte(ua),
StartHeight: 0,
Relay: r,
}
}
// UnmarshalBinary implements the Payloader interface.
func (p *Version) UnmarshalBinary(b []byte) error {
// Length of the user agent should be calculated dynamicaly.
// There is no information about the size or format of this.
// the only thing we know is by looking at the #c source code.
// /NEO:{0}/ => /NEO:2.6.0/
lenUA := len(b) - minVersionSize
p.Version = binary.LittleEndian.Uint32(b[0:4])
p.Services = binary.LittleEndian.Uint64(b[4:12])
p.Timestamp = binary.LittleEndian.Uint32(b[12:16])
// FIXME: port's byteorder should be big endian according to the docs.
// but when connecting to the privnet docker image it's little endian.
p.Port = binary.LittleEndian.Uint16(b[16:18])
p.Nonce = binary.LittleEndian.Uint32(b[18:22])
p.UserAgent = b[22 : 22+lenUA]
curlen := 22 + lenUA
p.StartHeight = binary.LittleEndian.Uint32(b[curlen : curlen+4])
p.Relay = b[len(b)-1 : len(b)][0] == 1
return nil
}
// MarshalBinary implements the Payloader interface.
func (p *Version) MarshalBinary() ([]byte, error) {
b := make([]byte, p.Size())
binary.LittleEndian.PutUint32(b[0:4], p.Version)
binary.LittleEndian.PutUint64(b[4:12], p.Services)
binary.LittleEndian.PutUint32(b[12:16], p.Timestamp)
// FIXME: byte order (little / big)?
binary.LittleEndian.PutUint16(b[16:18], p.Port)
binary.LittleEndian.PutUint32(b[18:22], p.Nonce)
copy(b[22:22+len(p.UserAgent)], p.UserAgent) //
curLen := 22 + len(p.UserAgent)
binary.LittleEndian.PutUint32(b[curLen:curLen+4], p.StartHeight)
// yikes
var bln []byte
if p.Relay {
bln = []byte{1}
} else {
bln = []byte{0}
}
copy(b[curLen+4:len(b)], bln)
return b, nil
}
// Size implements the payloader interface.
func (p *Version) Size() uint32 {
return uint32(minVersionSize + len(p.UserAgent))
}