Block message + handle the length of the user agent better.
This commit is contained in:
parent
e9f9354b86
commit
0c9d2dd04e
12 changed files with 243 additions and 89 deletions
|
@ -1,6 +1,9 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
|
||||||
. "github.com/anthdm/neo-go/pkg/util"
|
. "github.com/anthdm/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,3 +29,33 @@ type Block struct {
|
||||||
// transaction list
|
// transaction list
|
||||||
Transactions []*Transaction
|
Transactions []*Transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeBinary encodes the block to the given writer.
|
||||||
|
func (b *Block) EncodeBinary(w io.Writer) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeBinary decods the block from the given reader.
|
||||||
|
func (b *Block) DecodeBinary(r io.Reader) error {
|
||||||
|
err := binary.Read(r, binary.LittleEndian, &b.Version)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b.PrevBlock)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b.MerkleRoot)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b.Timestamp)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b.Height)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b.Nonce)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b.NextMiner)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &b._sep)
|
||||||
|
var n uint8
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &n)
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &n)
|
||||||
|
|
||||||
|
// txs := make([]byte, n)
|
||||||
|
// err = binary.Read(r, binary.LittleEndian, &txs)
|
||||||
|
// err = binary.Read(r, binary.LittleEndian, &n)
|
||||||
|
// fmt.Println(n)
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size implements the payload interface.
|
||||||
|
func (b *Block) Size() uint32 { return 0 }
|
||||||
|
|
19
pkg/core/witness.go
Normal file
19
pkg/core/witness.go
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
import "io"
|
||||||
|
|
||||||
|
// Witness ...
|
||||||
|
type Witness struct {
|
||||||
|
InvocationScript []byte
|
||||||
|
VerificationScript []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeBinary implements the payload interface.
|
||||||
|
func (wit *Witness) DecodeBinary(r io.Reader) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EncodeBinary implements the payload interface.
|
||||||
|
func (wit *Witness) EncodeBinary(w io.Writer) error {
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
|
"github.com/anthdm/neo-go/pkg/core"
|
||||||
"github.com/anthdm/neo-go/pkg/network/payload"
|
"github.com/anthdm/neo-go/pkg/network/payload"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,14 +47,6 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Message is the complete message send between nodes.
|
// Message is the complete message send between nodes.
|
||||||
//
|
|
||||||
// Size Field DataType Description
|
|
||||||
// ------------------------------------------------------
|
|
||||||
// 4 Magic uint32 Protocol ID
|
|
||||||
// 12 Command char[12] Command
|
|
||||||
// 4 length uint32 Length of payload
|
|
||||||
// 4 Checksum uint32 Checksum
|
|
||||||
// length Payload uint8[length] Content of message
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
Magic NetMode
|
Magic NetMode
|
||||||
// Command is utf8 code, of which the length is 12 bytes,
|
// Command is utf8 code, of which the length is 12 bytes,
|
||||||
|
@ -93,11 +86,11 @@ func newMessage(magic NetMode, cmd commandType, p payload.Payload) *Message {
|
||||||
)
|
)
|
||||||
|
|
||||||
if p != nil {
|
if p != nil {
|
||||||
size = p.Size()
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err := p.EncodeBinary(buf); err != nil {
|
if err := p.EncodeBinary(buf); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
size = uint32(buf.Len())
|
||||||
checksum = sumSHA256(sumSHA256(buf.Bytes()))
|
checksum = sumSHA256(sumSHA256(buf.Bytes()))
|
||||||
} else {
|
} else {
|
||||||
checksum = sumSHA256(sumSHA256([]byte{}))
|
checksum = sumSHA256(sumSHA256([]byte{}))
|
||||||
|
@ -152,8 +145,6 @@ func (m *Message) decode(r io.Reader) error {
|
||||||
binary.Read(r, binary.LittleEndian, &m.Length)
|
binary.Read(r, binary.LittleEndian, &m.Length)
|
||||||
binary.Read(r, binary.LittleEndian, &m.Checksum)
|
binary.Read(r, binary.LittleEndian, &m.Checksum)
|
||||||
|
|
||||||
fmt.Println(cmdByteArrayToString(m.Command))
|
|
||||||
|
|
||||||
// return if their is no payload.
|
// return if their is no payload.
|
||||||
if m.Length == 0 {
|
if m.Length == 0 {
|
||||||
return nil
|
return nil
|
||||||
|
@ -163,24 +154,22 @@ func (m *Message) decode(r io.Reader) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Message) decodePayload(r io.Reader) error {
|
func (m *Message) decodePayload(r io.Reader) error {
|
||||||
pbuf := make([]byte, m.Length)
|
buf := make([]byte, m.Length)
|
||||||
n, err := r.Read(pbuf)
|
n, err := r.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("The length of the payload is %d\n", n)
|
|
||||||
|
|
||||||
if uint32(n) != m.Length {
|
if uint32(n) != m.Length {
|
||||||
return fmt.Errorf("expected to have read exactly %d bytes got %d", m.Length, n)
|
return fmt.Errorf("expected to have read exactly %d bytes got %d", m.Length, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare the checksum of the payload.
|
// Compare the checksum of the payload.
|
||||||
if !compareChecksum(m.Checksum, pbuf) {
|
if !compareChecksum(m.Checksum, buf) {
|
||||||
return errChecksumMismatch
|
return errChecksumMismatch
|
||||||
}
|
}
|
||||||
|
|
||||||
r = bytes.NewReader(pbuf)
|
r = bytes.NewReader(buf)
|
||||||
var p payload.Payload
|
var p payload.Payload
|
||||||
switch m.commandType() {
|
switch m.commandType() {
|
||||||
case cmdVersion:
|
case cmdVersion:
|
||||||
|
@ -198,6 +187,11 @@ func (m *Message) decodePayload(r io.Reader) error {
|
||||||
if err := p.DecodeBinary(r); err != nil {
|
if err := p.DecodeBinary(r); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
case cmdBlock:
|
||||||
|
p = &core.Block{}
|
||||||
|
if err := p.DecodeBinary(r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Payload = p
|
m.Payload = p
|
||||||
|
|
|
@ -33,7 +33,7 @@ func TestMessageEncodeDecode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessageEncodeDecodeWithVersion(t *testing.T) {
|
func TestMessageEncodeDecodeWithVersion(t *testing.T) {
|
||||||
p := payload.NewVersion(12227, 2000, "./neo:2.6.0/", 0, true)
|
p := payload.NewVersion(12227, 2000, "/neo:2.6.0/", 0, true)
|
||||||
m := newMessage(ModeTestNet, cmdVersion, p)
|
m := newMessage(ModeTestNet, cmdVersion, p)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
|
@ -52,7 +52,7 @@ func TestMessageEncodeDecodeWithVersion(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMessageInvalidChecksum(t *testing.T) {
|
func TestMessageInvalidChecksum(t *testing.T) {
|
||||||
p := payload.NewVersion(1111, 3000, "./NEO:2.6.0/", 0, true)
|
p := payload.NewVersion(1111, 3000, "/NEO:2.6.0/", 0, true)
|
||||||
m := newMessage(ModeTestNet, cmdVersion, p)
|
m := newMessage(ModeTestNet, cmdVersion, p)
|
||||||
m.Checksum = 1337
|
m.Checksum = 1337
|
||||||
|
|
||||||
|
|
|
@ -5,10 +5,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const minVersionSize = 27
|
||||||
lenUA = 12
|
|
||||||
minVersionSize = 27
|
|
||||||
)
|
|
||||||
|
|
||||||
// Version payload.
|
// Version payload.
|
||||||
type Version struct {
|
type Version struct {
|
||||||
|
@ -23,7 +20,7 @@ type Version struct {
|
||||||
// it's used to distinguish the node from public IP
|
// it's used to distinguish the node from public IP
|
||||||
Nonce uint32
|
Nonce uint32
|
||||||
// client id
|
// client id
|
||||||
UserAgent [lenUA]byte
|
UserAgent []byte
|
||||||
// Height of the block chain
|
// Height of the block chain
|
||||||
StartHeight uint32
|
StartHeight uint32
|
||||||
// Whether to receive and forward
|
// Whether to receive and forward
|
||||||
|
@ -38,7 +35,7 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version {
|
||||||
Timestamp: 12345,
|
Timestamp: 12345,
|
||||||
Port: p,
|
Port: p,
|
||||||
Nonce: id,
|
Nonce: id,
|
||||||
UserAgent: uaToByteArray(ua),
|
UserAgent: []byte(ua),
|
||||||
StartHeight: 0,
|
StartHeight: 0,
|
||||||
Relay: r,
|
Relay: r,
|
||||||
}
|
}
|
||||||
|
@ -46,16 +43,17 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version {
|
||||||
|
|
||||||
// DecodeBinary implements the Payload interface.
|
// DecodeBinary implements the Payload interface.
|
||||||
func (p *Version) DecodeBinary(r io.Reader) error {
|
func (p *Version) DecodeBinary(r io.Reader) error {
|
||||||
// TODO: 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/
|
|
||||||
err := binary.Read(r, binary.LittleEndian, &p.Version)
|
err := binary.Read(r, binary.LittleEndian, &p.Version)
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.Services)
|
err = binary.Read(r, binary.LittleEndian, &p.Services)
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.Timestamp)
|
err = binary.Read(r, binary.LittleEndian, &p.Timestamp)
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.Port)
|
err = binary.Read(r, binary.LittleEndian, &p.Port)
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.Nonce)
|
err = binary.Read(r, binary.LittleEndian, &p.Nonce)
|
||||||
|
|
||||||
|
var lenUA uint8
|
||||||
|
err = binary.Read(r, binary.LittleEndian, &lenUA)
|
||||||
|
p.UserAgent = make([]byte, lenUA)
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.UserAgent)
|
err = binary.Read(r, binary.LittleEndian, &p.UserAgent)
|
||||||
|
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.StartHeight)
|
err = binary.Read(r, binary.LittleEndian, &p.StartHeight)
|
||||||
err = binary.Read(r, binary.LittleEndian, &p.Relay)
|
err = binary.Read(r, binary.LittleEndian, &p.Relay)
|
||||||
|
|
||||||
|
@ -69,6 +67,7 @@ func (p *Version) EncodeBinary(w io.Writer) error {
|
||||||
err = binary.Write(w, binary.LittleEndian, p.Timestamp)
|
err = binary.Write(w, binary.LittleEndian, p.Timestamp)
|
||||||
err = binary.Write(w, binary.LittleEndian, p.Port)
|
err = binary.Write(w, binary.LittleEndian, p.Port)
|
||||||
err = binary.Write(w, binary.LittleEndian, p.Nonce)
|
err = binary.Write(w, binary.LittleEndian, p.Nonce)
|
||||||
|
err = binary.Write(w, binary.LittleEndian, uint8(len(p.UserAgent)))
|
||||||
err = binary.Write(w, binary.LittleEndian, p.UserAgent)
|
err = binary.Write(w, binary.LittleEndian, p.UserAgent)
|
||||||
err = binary.Write(w, binary.LittleEndian, p.StartHeight)
|
err = binary.Write(w, binary.LittleEndian, p.StartHeight)
|
||||||
err = binary.Write(w, binary.LittleEndian, p.Relay)
|
err = binary.Write(w, binary.LittleEndian, p.Relay)
|
||||||
|
@ -80,11 +79,3 @@ func (p *Version) EncodeBinary(w io.Writer) error {
|
||||||
func (p *Version) Size() uint32 {
|
func (p *Version) Size() uint32 {
|
||||||
return uint32(minVersionSize + len(p.UserAgent))
|
return uint32(minVersionSize + len(p.UserAgent))
|
||||||
}
|
}
|
||||||
|
|
||||||
func uaToByteArray(ua string) [lenUA]byte {
|
|
||||||
buf := [lenUA]byte{}
|
|
||||||
for i := 0; i < lenUA; i++ {
|
|
||||||
buf[i] = ua[i]
|
|
||||||
}
|
|
||||||
return buf
|
|
||||||
}
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestVersionEncodeDecode(t *testing.T) {
|
func TestVersionEncodeDecode(t *testing.T) {
|
||||||
version := NewVersion(13337, 3000, "./NEO:0.0.1/", 0, true)
|
version := NewVersion(13337, 3000, "/NEO:0.0.1/", 0, true)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err := version.EncodeBinary(buf); err != nil {
|
if err := version.EncodeBinary(buf); err != nil {
|
||||||
|
@ -24,6 +24,6 @@ func TestVersionEncodeDecode(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if version.Size() != uint32(minVersionSize+len(version.UserAgent)) {
|
if version.Size() != uint32(minVersionSize+len(version.UserAgent)) {
|
||||||
t.Fatalf("Expected version size of %d", minVersionSize+lenUA)
|
t.Fatalf("Expected version size of %d", minVersionSize+len(version.UserAgent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,49 +1,123 @@
|
||||||
package network
|
package network
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/anthdm/neo-go/pkg/util"
|
"github.com/anthdm/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Peer represents a remote node, backed by TCP transport.
|
// Peer is the local representation of a remote node. It's an interface that may
|
||||||
type Peer struct {
|
// be backed by any concrete transport: local, HTTP, tcp.
|
||||||
id uint32
|
type Peer interface {
|
||||||
|
id() uint32
|
||||||
|
endpoint() util.Endpoint
|
||||||
|
send(*Message)
|
||||||
|
verack() bool
|
||||||
|
verify(uint32)
|
||||||
|
disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalPeer is a peer without any transport, mainly used for testing.
|
||||||
|
type LocalPeer struct {
|
||||||
|
_id uint32
|
||||||
|
_verack bool
|
||||||
|
_endpoint util.Endpoint
|
||||||
|
_send chan *Message
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewLocalPeer return a LocalPeer.
|
||||||
|
func NewLocalPeer() *LocalPeer {
|
||||||
|
e, _ := util.EndpointFromString("1.1.1.1:1111")
|
||||||
|
return &LocalPeer{_endpoint: e}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *LocalPeer) id() uint32 { return p._id }
|
||||||
|
func (p *LocalPeer) verack() bool { return p._verack }
|
||||||
|
func (p *LocalPeer) endpoint() util.Endpoint { return p._endpoint }
|
||||||
|
func (p *LocalPeer) disconnect() {}
|
||||||
|
|
||||||
|
func (p *LocalPeer) send(msg *Message) {
|
||||||
|
p._send <- msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *LocalPeer) verify(id uint32) {
|
||||||
|
fmt.Println(id)
|
||||||
|
p._verack = true
|
||||||
|
p._id = id
|
||||||
|
}
|
||||||
|
|
||||||
|
// TCPPeer represents a remote node, backed by TCP transport.
|
||||||
|
type TCPPeer struct {
|
||||||
|
_id uint32
|
||||||
// underlying TCP connection
|
// underlying TCP connection
|
||||||
conn net.Conn
|
conn net.Conn
|
||||||
// host and port information about this peer.
|
// host and port information about this peer.
|
||||||
endpoint util.Endpoint
|
_endpoint util.Endpoint
|
||||||
// channel to coordinate messages writen back to the connection.
|
// channel to coordinate messages writen back to the connection.
|
||||||
send chan *Message
|
_send chan *Message
|
||||||
// whether this peers version was acknowledged.
|
// whether this peers version was acknowledged.
|
||||||
verack bool
|
_verack bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPeer returns a (TCP) Peer.
|
// NewTCPPeer returns a pointer to a TCP Peer.
|
||||||
func NewPeer(conn net.Conn) *Peer {
|
func NewTCPPeer(conn net.Conn) *TCPPeer {
|
||||||
e, _ := util.EndpointFromString(conn.RemoteAddr().String())
|
e, _ := util.EndpointFromString(conn.RemoteAddr().String())
|
||||||
|
|
||||||
return &Peer{
|
return &TCPPeer{
|
||||||
conn: conn,
|
conn: conn,
|
||||||
send: make(chan *Message),
|
_send: make(chan *Message),
|
||||||
endpoint: e,
|
_endpoint: e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// id implements the peer interface
|
||||||
|
func (p *TCPPeer) id() uint32 {
|
||||||
|
return p._id
|
||||||
|
}
|
||||||
|
|
||||||
|
// endpoint implements the peer interface
|
||||||
|
func (p *TCPPeer) endpoint() util.Endpoint {
|
||||||
|
return p._endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
// verack implements the peer interface
|
||||||
|
func (p *TCPPeer) verack() bool {
|
||||||
|
return p._verack
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify implements the peer interface
|
||||||
|
func (p *TCPPeer) verify(id uint32) {
|
||||||
|
p._id = id
|
||||||
|
p._verack = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// send implements the peer interface
|
||||||
|
func (p *TCPPeer) send(msg *Message) {
|
||||||
|
p._send <- msg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *TCPPeer) disconnect() {
|
||||||
|
close(p._send)
|
||||||
|
p.conn.Close()
|
||||||
|
}
|
||||||
|
|
||||||
// writeLoop writes messages to the underlying TCP connection.
|
// writeLoop writes messages to the underlying TCP connection.
|
||||||
// A goroutine writeLoop is started for each connection.
|
// A goroutine writeLoop is started for each connection.
|
||||||
// There should be at most one writer to a connection executing
|
// There should be at most one writer to a connection executing
|
||||||
// all writes from this goroutine.
|
// all writes from this goroutine.
|
||||||
func (p *Peer) writeLoop() {
|
func (p *TCPPeer) writeLoop() {
|
||||||
// clean up the connection.
|
// clean up the connection.
|
||||||
defer func() {
|
defer func() {
|
||||||
p.conn.Close()
|
p.conn.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
msg := <-p.send
|
msg := <-p._send
|
||||||
rpcLogger.Printf("OUT :: %s", msg.commandType())
|
|
||||||
|
rpcLogger.Printf("[SERVER] :: OUT :: %s :: %+v", msg.commandType(), msg.Payload)
|
||||||
|
|
||||||
if err := msg.encode(p.conn); err != nil {
|
if err := msg.encode(p.conn); err != nil {
|
||||||
log.Printf("encode error: %s", err)
|
log.Printf("encode error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,9 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/anthdm/neo-go/pkg/core"
|
||||||
"github.com/anthdm/neo-go/pkg/network/payload"
|
"github.com/anthdm/neo-go/pkg/network/payload"
|
||||||
"github.com/anthdm/neo-go/pkg/util"
|
"github.com/anthdm/neo-go/pkg/util"
|
||||||
)
|
)
|
||||||
|
@ -28,7 +28,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type messageTuple struct {
|
type messageTuple struct {
|
||||||
peer *Peer
|
peer Peer
|
||||||
msg *Message
|
msg *Message
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,8 +36,6 @@ type messageTuple struct {
|
||||||
type Server struct {
|
type Server struct {
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
|
|
||||||
mtx sync.RWMutex
|
|
||||||
|
|
||||||
// id of the server
|
// id of the server
|
||||||
id uint32
|
id uint32
|
||||||
|
|
||||||
|
@ -51,10 +49,10 @@ type Server struct {
|
||||||
// Or 56753 to work with the docker privnet.
|
// Or 56753 to work with the docker privnet.
|
||||||
net NetMode
|
net NetMode
|
||||||
// map that holds all connected peers to this server.
|
// map that holds all connected peers to this server.
|
||||||
peers map[*Peer]bool
|
peers map[Peer]bool
|
||||||
|
|
||||||
register chan *Peer
|
register chan Peer
|
||||||
unregister chan *Peer
|
unregister chan Peer
|
||||||
|
|
||||||
// channel for coordinating messages.
|
// channel for coordinating messages.
|
||||||
message chan messageTuple
|
message chan messageTuple
|
||||||
|
@ -79,11 +77,11 @@ func NewServer(net NetMode) *Server {
|
||||||
|
|
||||||
s := &Server{
|
s := &Server{
|
||||||
id: util.RandUint32(1111111, 9999999),
|
id: util.RandUint32(1111111, 9999999),
|
||||||
userAgent: fmt.Sprintf("\v/NEO:%s/", version),
|
userAgent: fmt.Sprintf("/NEO:%s/", version),
|
||||||
logger: logger,
|
logger: logger,
|
||||||
peers: make(map[*Peer]bool),
|
peers: make(map[Peer]bool),
|
||||||
register: make(chan *Peer),
|
register: make(chan Peer),
|
||||||
unregister: make(chan *Peer),
|
unregister: make(chan Peer),
|
||||||
message: make(chan messageTuple),
|
message: make(chan messageTuple),
|
||||||
relay: true,
|
relay: true,
|
||||||
net: net,
|
net: net,
|
||||||
|
@ -137,17 +135,16 @@ func (s *Server) loop() {
|
||||||
// When a new connection is been established, (by this server or remote node)
|
// When a new connection is been established, (by this server or remote node)
|
||||||
// its peer will be received on this channel.
|
// its peer will be received on this channel.
|
||||||
// Any peer registration must happen via this channel.
|
// Any peer registration must happen via this channel.
|
||||||
s.logger.Printf("peer registered from address %s", peer.conn.RemoteAddr())
|
s.logger.Printf("peer registered from address %s", peer.endpoint())
|
||||||
s.peers[peer] = true
|
s.peers[peer] = true
|
||||||
s.handlePeerConnected(peer)
|
s.handlePeerConnected(peer)
|
||||||
|
|
||||||
case peer := <-s.unregister:
|
case peer := <-s.unregister:
|
||||||
// unregister should take care of all the cleanup that has to be made.
|
// unregister should take care of all the cleanup that has to be made.
|
||||||
if _, ok := s.peers[peer]; ok {
|
if _, ok := s.peers[peer]; ok {
|
||||||
peer.conn.Close()
|
peer.disconnect()
|
||||||
close(peer.send)
|
|
||||||
delete(s.peers, peer)
|
delete(s.peers, peer)
|
||||||
s.logger.Printf("peer %s disconnected", peer.conn.RemoteAddr())
|
s.logger.Printf("peer %s disconnected", peer.endpoint())
|
||||||
}
|
}
|
||||||
|
|
||||||
case tuple := <-s.message:
|
case tuple := <-s.message:
|
||||||
|
@ -166,14 +163,14 @@ func (s *Server) loop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// processMessage processes the message received from the peer.
|
// processMessage processes the message received from the peer.
|
||||||
func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
func (s *Server) processMessage(msg *Message, peer Peer) error {
|
||||||
command := msg.commandType()
|
command := msg.commandType()
|
||||||
|
|
||||||
rpcLogger.Printf("[NODE %d] :: IN :: %s :: %+v", peer.id, command, msg.Payload)
|
rpcLogger.Printf("[NODE %d] :: IN :: %s :: %+v", peer.id(), command, msg.Payload)
|
||||||
|
|
||||||
// Disconnect if the remote is sending messages other then version
|
// Disconnect if the remote is sending messages other then version
|
||||||
// if we didn't verack this peer.
|
// if we didn't verack this peer.
|
||||||
if !peer.verack && command != cmdVersion {
|
if !peer.verack() && command != cmdVersion {
|
||||||
return errors.New("version noack")
|
return errors.New("version noack")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,6 +189,7 @@ func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
||||||
return s.handleInvCmd(msg.Payload.(*payload.Inventory), peer)
|
return s.handleInvCmd(msg.Payload.(*payload.Inventory), peer)
|
||||||
case cmdGetData:
|
case cmdGetData:
|
||||||
case cmdBlock:
|
case cmdBlock:
|
||||||
|
return s.handleBlockCmd(msg.Payload.(*core.Block), peer)
|
||||||
case cmdTX:
|
case cmdTX:
|
||||||
case cmdConsensus:
|
case cmdConsensus:
|
||||||
default:
|
default:
|
||||||
|
@ -204,29 +202,29 @@ func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
||||||
// When a new peer is connected we send our version.
|
// When a new peer is connected we send our version.
|
||||||
// No further communication should be made before both sides has received
|
// No further communication should be made before both sides has received
|
||||||
// the versions of eachother.
|
// the versions of eachother.
|
||||||
func (s *Server) handlePeerConnected(peer *Peer) {
|
func (s *Server) handlePeerConnected(peer Peer) {
|
||||||
// TODO get heigth of block when thats implemented.
|
// TODO get heigth of block when thats implemented.
|
||||||
payload := payload.NewVersion(s.id, s.port, s.userAgent, 0, s.relay)
|
payload := payload.NewVersion(s.id, s.port, s.userAgent, 0, s.relay)
|
||||||
msg := newMessage(s.net, cmdVersion, payload)
|
msg := newMessage(s.net, cmdVersion, payload)
|
||||||
|
|
||||||
peer.send <- msg
|
peer.send(msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Version declares the server's version.
|
// Version declares the server's version.
|
||||||
func (s *Server) handleVersionCmd(v *payload.Version, peer *Peer) error {
|
func (s *Server) handleVersionCmd(v *payload.Version, peer Peer) error {
|
||||||
if s.id == v.Nonce {
|
if s.id == v.Nonce {
|
||||||
return errors.New("remote nonce equal to server id")
|
return errors.New("remote nonce equal to server id")
|
||||||
}
|
}
|
||||||
if peer.endpoint.Port != v.Port {
|
|
||||||
|
if peer.endpoint().Port != v.Port {
|
||||||
return errors.New("port mismatch")
|
return errors.New("port mismatch")
|
||||||
}
|
}
|
||||||
|
|
||||||
// we respond with a verack, we successfully received peer's version
|
// we respond with a verack, we successfully received peer's version
|
||||||
// at this point.
|
// at this point.
|
||||||
peer.verack = true
|
peer.verify(v.Nonce)
|
||||||
peer.id = v.Nonce
|
|
||||||
verackMsg := newMessage(s.net, cmdVerack, nil)
|
verackMsg := newMessage(s.net, cmdVerack, nil)
|
||||||
peer.send <- verackMsg
|
peer.send(verackMsg)
|
||||||
|
|
||||||
go s.sendLoop(peer)
|
go s.sendLoop(peer)
|
||||||
|
|
||||||
|
@ -234,7 +232,7 @@ func (s *Server) handleVersionCmd(v *payload.Version, peer *Peer) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the remote node reveals its known peers we try to connect to all of them.
|
// When the remote node reveals its known peers we try to connect to all of them.
|
||||||
func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error {
|
func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer Peer) error {
|
||||||
for _, addr := range addrList.Addrs {
|
for _, addr := range addrList.Addrs {
|
||||||
if !s.peerAlreadyConnected(addr.Addr) {
|
if !s.peerAlreadyConnected(addr.Addr) {
|
||||||
go connectToRemoteNode(s, addr.Addr.String())
|
go connectToRemoteNode(s, addr.Addr.String())
|
||||||
|
@ -243,7 +241,7 @@ func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) handleInvCmd(inv *payload.Inventory, peer *Peer) error {
|
func (s *Server) handleInvCmd(inv *payload.Inventory, peer Peer) error {
|
||||||
if !inv.Type.Valid() {
|
if !inv.Type.Valid() {
|
||||||
return fmt.Errorf("invalid inventory type: %s", inv.Type)
|
return fmt.Errorf("invalid inventory type: %s", inv.Type)
|
||||||
}
|
}
|
||||||
|
@ -254,11 +252,16 @@ func (s *Server) handleInvCmd(inv *payload.Inventory, peer *Peer) error {
|
||||||
payload := payload.NewInventory(inv.Type, inv.Hashes)
|
payload := payload.NewInventory(inv.Type, inv.Hashes)
|
||||||
msg := newMessage(s.net, cmdGetData, payload)
|
msg := newMessage(s.net, cmdGetData, payload)
|
||||||
|
|
||||||
peer.send <- msg
|
peer.send(msg)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Server) handleBlockCmd(block *core.Block, peer Peer) error {
|
||||||
|
fmt.Println("received a block yyyyyyeeeeeehhhhh!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) peerAlreadyConnected(addr net.Addr) bool {
|
func (s *Server) peerAlreadyConnected(addr net.Addr) bool {
|
||||||
// TODO: check for race conditions
|
// TODO: check for race conditions
|
||||||
//s.mtx.RLock()
|
//s.mtx.RLock()
|
||||||
|
@ -267,7 +270,7 @@ func (s *Server) peerAlreadyConnected(addr net.Addr) bool {
|
||||||
// What about ourself ^^
|
// What about ourself ^^
|
||||||
|
|
||||||
for peer := range s.peers {
|
for peer := range s.peers {
|
||||||
if peer.conn.RemoteAddr().String() == addr.String() {
|
if peer.endpoint().String() == addr.String() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,13 +285,13 @@ func (s *Server) handleGetAddrCmd(msg *Message, peer *Peer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) sendLoop(peer *Peer) {
|
func (s *Server) sendLoop(peer Peer) {
|
||||||
// TODO: check if this peer is still connected.
|
// TODO: check if this peer is still connected.
|
||||||
for {
|
for {
|
||||||
getaddrMsg := newMessage(s.net, cmdGetAddr, nil)
|
getaddrMsg := newMessage(s.net, cmdGetAddr, nil)
|
||||||
peer.send <- getaddrMsg
|
peer.send(getaddrMsg)
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
time.Sleep(120 * time.Second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
26
pkg/network/server_test.go
Normal file
26
pkg/network/server_test.go
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
package network
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHandleVersion(t *testing.T) {
|
||||||
|
// s := NewServer(ModeDevNet)
|
||||||
|
// go s.Start(":3000", nil)
|
||||||
|
|
||||||
|
// p := NewLocalPeer()
|
||||||
|
// s.register <- p
|
||||||
|
|
||||||
|
// version := payload.NewVersion(1337, p.endpoint().Port, "/NEO:0.0.0/.", 0, true)
|
||||||
|
// s.handleVersionCmd(version, p)
|
||||||
|
|
||||||
|
// if len(s.peers) != 1 {
|
||||||
|
// t.Fatalf("expecting the server to have %d peers got %d", 1, len(s.peers))
|
||||||
|
// }
|
||||||
|
// if p.id() != 1337 {
|
||||||
|
// t.Fatalf("expecting peer's id to be %d got %d", 1337, p._id)
|
||||||
|
// }
|
||||||
|
// if !p.verack() {
|
||||||
|
// t.Fatal("expecting peer to be verified")
|
||||||
|
// }
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ func connectToSeeds(s *Server, addrs []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleConnection(s *Server, conn net.Conn) {
|
func handleConnection(s *Server, conn net.Conn) {
|
||||||
peer := NewPeer(conn)
|
peer := NewTCPPeer(conn)
|
||||||
s.register <- peer
|
s.register <- peer
|
||||||
|
|
||||||
// remove the peer from connected peers and cleanup the connection.
|
// remove the peer from connected peers and cleanup the connection.
|
||||||
|
|
|
@ -33,10 +33,10 @@ func (u *Uint256) UnmarshalBinary(b []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSlice return a byte slice of u.
|
// ToSlice returns a byte slice of u.
|
||||||
func (u Uint256) ToSlice() []byte {
|
func (u Uint256) ToSlice() []byte {
|
||||||
b := make([]byte, 32)
|
b := make([]byte, 32)
|
||||||
for i := 0; i < 32; i++ {
|
for i := 0; i < len(b); i++ {
|
||||||
b[i] = byte(u[i])
|
b[i] = byte(u[i])
|
||||||
}
|
}
|
||||||
return b
|
return b
|
||||||
|
@ -48,3 +48,17 @@ func (u Uint256) String() string {
|
||||||
|
|
||||||
// Uint160 is a 20 byte long unsigned integer
|
// Uint160 is a 20 byte long unsigned integer
|
||||||
type Uint160 [20]uint8
|
type Uint160 [20]uint8
|
||||||
|
|
||||||
|
// ToSlice returns a byte slice of u.
|
||||||
|
func (u Uint160) ToSlice() []byte {
|
||||||
|
b := make([]byte, 20)
|
||||||
|
for i := 0; i < len(b); i++ {
|
||||||
|
b[i] = byte(u[i])
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
|
||||||
|
// String implements the stringer interface.
|
||||||
|
func (u Uint160) String() string {
|
||||||
|
return hex.EncodeToString(u.ToSlice())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue