forked from TrueCloudLab/neoneo-go
4aa1a37f3f
Blockcache size is 2000, while max request size is 500. Try to fetch blocks in chunks starting from current height. Lower height has priority.
198 lines
5.4 KiB
Go
198 lines
5.4 KiB
Go
package network
|
|
|
|
import (
|
|
"net"
|
|
"strconv"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestGetBlocksByIndex(t *testing.T) {
|
|
s := newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
|
ps := make([]*localPeer, 10)
|
|
expectsCmd := make([]CommandType, 10)
|
|
expectedHeight := make([][]uint32, 10)
|
|
start := s.chain.BlockHeight()
|
|
for i := range ps {
|
|
i := i
|
|
ps[i] = newLocalPeer(t, s)
|
|
ps[i].messageHandler = func(t *testing.T, msg *Message) {
|
|
require.Equal(t, expectsCmd[i], msg.Command)
|
|
if expectsCmd[i] == CMDGetBlockByIndex {
|
|
p, ok := msg.Payload.(*payload.GetBlockByIndex)
|
|
require.True(t, ok)
|
|
require.Contains(t, expectedHeight[i], p.IndexStart)
|
|
expectsCmd[i] = CMDPong
|
|
} else if expectsCmd[i] == CMDPong {
|
|
expectsCmd[i] = CMDGetBlockByIndex
|
|
}
|
|
}
|
|
expectsCmd[i] = CMDGetBlockByIndex
|
|
expectedHeight[i] = []uint32{start + 1}
|
|
}
|
|
go s.transport.Accept()
|
|
|
|
nonce := uint32(0)
|
|
checkPingRespond := func(t *testing.T, peerIndex int, peerHeight uint32, hs ...uint32) {
|
|
nonce++
|
|
expectedHeight[peerIndex] = hs
|
|
require.NoError(t, s.handlePing(ps[peerIndex], payload.NewPing(peerHeight, nonce)))
|
|
}
|
|
|
|
// Send all requests for all chunks.
|
|
checkPingRespond(t, 0, 5000, 1)
|
|
checkPingRespond(t, 1, 5000, 1+payload.MaxHashesCount)
|
|
checkPingRespond(t, 2, 5000, 1+2*payload.MaxHashesCount)
|
|
checkPingRespond(t, 3, 5000, 1+3*payload.MaxHashesCount)
|
|
|
|
// Receive some blocks.
|
|
s.chain.(*testChain).blockheight = 2123
|
|
|
|
// Minimum chunk has priority.
|
|
checkPingRespond(t, 5, 5000, 2124)
|
|
checkPingRespond(t, 6, 5000, 2624)
|
|
// Request minimal height for peers behind.
|
|
checkPingRespond(t, 7, 3100, 2124)
|
|
checkPingRespond(t, 8, 5000, 3124)
|
|
checkPingRespond(t, 9, 5000, 3624)
|
|
// Request random height after that.
|
|
checkPingRespond(t, 1, 5000, 2124, 2624, 3124, 3624)
|
|
checkPingRespond(t, 2, 5000, 2124, 2624, 3124, 3624)
|
|
checkPingRespond(t, 3, 5000, 2124, 2624, 3124, 3624)
|
|
}
|
|
|
|
func TestSendVersion(t *testing.T) {
|
|
var (
|
|
s = newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
|
p = newLocalPeer(t, s)
|
|
)
|
|
// we need to set listener at least to handle dynamic port correctly
|
|
go s.transport.Accept()
|
|
require.Eventually(t, func() bool { return s.transport.Address() != "" }, time.Second, 10*time.Millisecond)
|
|
p.messageHandler = func(t *testing.T, msg *Message) {
|
|
// listener is already set, so Address() gives us proper address with port
|
|
_, p, err := net.SplitHostPort(s.transport.Address())
|
|
assert.NoError(t, err)
|
|
port, err := strconv.ParseUint(p, 10, 16)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, CMDVersion, msg.Command)
|
|
assert.IsType(t, msg.Payload, &payload.Version{})
|
|
version := msg.Payload.(*payload.Version)
|
|
assert.NotZero(t, version.Nonce)
|
|
assert.Equal(t, 1, len(version.Capabilities))
|
|
assert.ElementsMatch(t, []capability.Capability{
|
|
{
|
|
Type: capability.TCPServer,
|
|
Data: &capability.Server{
|
|
Port: uint16(port),
|
|
},
|
|
},
|
|
}, version.Capabilities)
|
|
assert.Equal(t, uint32(0), version.Version)
|
|
assert.Equal(t, []byte("/test/"), version.UserAgent)
|
|
}
|
|
|
|
require.NoError(t, p.SendVersion())
|
|
}
|
|
|
|
// Server should reply with a verack after receiving a valid version.
|
|
func TestVerackAfterHandleVersionCmd(t *testing.T) {
|
|
var (
|
|
s = newTestServer(t, ServerConfig{})
|
|
p = newLocalPeer(t, s)
|
|
)
|
|
na, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:3000")
|
|
p.netaddr = *na
|
|
|
|
// Should have a verack
|
|
p.messageHandler = func(t *testing.T, msg *Message) {
|
|
assert.Equal(t, CMDVerack, msg.Command)
|
|
}
|
|
capabilities := []capability.Capability{
|
|
{
|
|
Type: capability.FullNode,
|
|
Data: &capability.Node{
|
|
StartHeight: 0,
|
|
},
|
|
},
|
|
{
|
|
Type: capability.TCPServer,
|
|
Data: &capability.Server{
|
|
Port: 3000,
|
|
},
|
|
},
|
|
}
|
|
version := payload.NewVersion(0, 1337, "/NEO-GO/", capabilities)
|
|
|
|
require.NoError(t, s.handleVersionCmd(p, version))
|
|
}
|
|
|
|
// Server should not reply with a verack after receiving a
|
|
// invalid version and disconnects the peer.
|
|
func TestServerNotSendsVerack(t *testing.T) {
|
|
var (
|
|
s = newTestServer(t, ServerConfig{Net: 56753})
|
|
p = newLocalPeer(t, s)
|
|
p2 = newLocalPeer(t, s)
|
|
)
|
|
s.id = 1
|
|
finished := make(chan struct{})
|
|
go func() {
|
|
s.run()
|
|
close(finished)
|
|
}()
|
|
defer func() {
|
|
// close via quit as server was started via `run()`, not `Start()`
|
|
close(s.quit)
|
|
<-finished
|
|
}()
|
|
|
|
na, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:3000")
|
|
p.netaddr = *na
|
|
p2.netaddr = *na
|
|
s.register <- p
|
|
|
|
capabilities := []capability.Capability{
|
|
{
|
|
Type: capability.FullNode,
|
|
Data: &capability.Node{
|
|
StartHeight: 0,
|
|
},
|
|
},
|
|
{
|
|
Type: capability.TCPServer,
|
|
Data: &capability.Server{
|
|
Port: 3000,
|
|
},
|
|
},
|
|
}
|
|
// identical id's
|
|
version := payload.NewVersion(56753, 1, "/NEO-GO/", capabilities)
|
|
err := s.handleVersionCmd(p, version)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, errIdenticalID, err)
|
|
|
|
// Different IDs, but also different magics
|
|
version.Nonce = 2
|
|
version.Magic = 56752
|
|
err = s.handleVersionCmd(p, version)
|
|
assert.NotNil(t, err)
|
|
assert.Equal(t, errInvalidNetwork, err)
|
|
|
|
// Different IDs and same network, make handshake pass.
|
|
version.Magic = 56753
|
|
require.NoError(t, s.handleVersionCmd(p, version))
|
|
require.NoError(t, p.HandleVersionAck())
|
|
require.Equal(t, true, p.Handshaked())
|
|
|
|
// Second handshake from the same peer should fail.
|
|
s.register <- p2
|
|
err = s.handleVersionCmd(p2, version)
|
|
assert.NotNil(t, err)
|
|
require.Equal(t, errAlreadyConnected, err)
|
|
}
|