neoneo-go/pkg/network/payload/version.go

105 lines
2.5 KiB
Go
Raw Normal View History

2018-01-27 15:00:28 +00:00
package payload
import (
"bytes"
"encoding/binary"
"io"
)
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 currently 6 bytes \v/NEO:2.6.0/
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(p uint16, ua string, h uint32, r bool) *Version {
return &Version{
Version: 0,
Services: 1,
Timestamp: 12345,
Port: p,
Nonce: 19110,
UserAgent: []byte(ua),
StartHeight: 0,
Relay: r,
}
}
// Size ..
func (p *Version) Size() uint32 {
n := minVersionSize + len(p.UserAgent)
return uint32(n)
}
// Decode ..
func (p *Version) Decode(r io.Reader) error {
buf := new(bytes.Buffer)
if _, err := buf.ReadFrom(r); err != nil {
return err
}
b := buf.Bytes()
// 27 bytes for the fixed size fields + the length of the user agent
// which is kinda variable, according to the docs.
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
}
// Encode ..
func (p *Version) Encode(w io.Writer) error {
buf := make([]byte, p.Size())
binary.LittleEndian.PutUint32(buf[0:4], p.Version)
binary.LittleEndian.PutUint64(buf[4:12], p.Services)
binary.LittleEndian.PutUint32(buf[12:16], p.Timestamp)
// FIXME: byte order (little / big)?
binary.LittleEndian.PutUint16(buf[16:18], p.Port)
binary.LittleEndian.PutUint32(buf[18:22], p.Nonce)
copy(buf[22:22+len(p.UserAgent)], p.UserAgent) //
curLen := 22 + len(p.UserAgent)
binary.LittleEndian.PutUint32(buf[curLen:curLen+4], p.StartHeight)
// yikes
var b []byte
if p.Relay {
b = []byte{1}
} else {
b = []byte{0}
}
copy(buf[curLen+4:len(buf)], b)
_, err := w.Write(buf)
return err
}