2018-01-31 08:27:08 +00:00
|
|
|
package network
|
|
|
|
|
|
|
|
import (
|
2019-09-09 14:54:38 +00:00
|
|
|
"net"
|
2020-05-22 09:17:17 +00:00
|
|
|
"strconv"
|
2018-01-31 08:27:08 +00:00
|
|
|
"testing"
|
2020-05-22 09:17:17 +00:00
|
|
|
"time"
|
2018-01-31 19:11:08 +00:00
|
|
|
|
2020-05-22 09:17:17 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/network/capability"
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
2018-03-09 15:55:25 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
2019-11-06 09:39:17 +00:00
|
|
|
"github.com/stretchr/testify/require"
|
2018-01-31 08:27:08 +00:00
|
|
|
)
|
|
|
|
|
2020-11-26 15:53:10 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2018-03-14 09:36:59 +00:00
|
|
|
func TestSendVersion(t *testing.T) {
|
|
|
|
var (
|
2020-05-22 09:17:17 +00:00
|
|
|
s = newTestServer(t, ServerConfig{Port: 0, UserAgent: "/test/"})
|
2020-01-21 14:26:08 +00:00
|
|
|
p = newLocalPeer(t, s)
|
2018-03-14 09:36:59 +00:00
|
|
|
)
|
2020-05-22 09:17:17 +00:00
|
|
|
// 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)
|
2018-03-14 09:36:59 +00:00
|
|
|
p.messageHandler = func(t *testing.T, msg *Message) {
|
2020-05-22 09:17:17 +00:00
|
|
|
// 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)
|
2020-05-19 11:54:51 +00:00
|
|
|
assert.Equal(t, CMDVersion, msg.Command)
|
2018-03-14 09:36:59 +00:00
|
|
|
assert.IsType(t, msg.Payload, &payload.Version{})
|
|
|
|
version := msg.Payload.(*payload.Version)
|
|
|
|
assert.NotZero(t, version.Nonce)
|
2020-05-22 09:17:17 +00:00
|
|
|
assert.Equal(t, 1, len(version.Capabilities))
|
|
|
|
assert.ElementsMatch(t, []capability.Capability{
|
|
|
|
{
|
|
|
|
Type: capability.TCPServer,
|
|
|
|
Data: &capability.Server{
|
|
|
|
Port: uint16(port),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, version.Capabilities)
|
2018-03-14 09:36:59 +00:00
|
|
|
assert.Equal(t, uint32(0), version.Version)
|
|
|
|
assert.Equal(t, []byte("/test/"), version.UserAgent)
|
2018-02-02 10:02:25 +00:00
|
|
|
}
|
|
|
|
|
2020-02-29 15:55:16 +00:00
|
|
|
require.NoError(t, p.SendVersion())
|
2018-02-02 10:02:25 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 09:36:59 +00:00
|
|
|
// Server should reply with a verack after receiving a valid version.
|
|
|
|
func TestVerackAfterHandleVersionCmd(t *testing.T) {
|
|
|
|
var (
|
2020-05-22 09:17:17 +00:00
|
|
|
s = newTestServer(t, ServerConfig{})
|
2020-01-21 14:26:08 +00:00
|
|
|
p = newLocalPeer(t, s)
|
2018-03-14 09:36:59 +00:00
|
|
|
)
|
2019-09-09 14:54:38 +00:00
|
|
|
na, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:3000")
|
|
|
|
p.netaddr = *na
|
2018-03-14 09:36:59 +00:00
|
|
|
|
|
|
|
// Should have a verack
|
|
|
|
p.messageHandler = func(t *testing.T, msg *Message) {
|
2020-05-19 11:54:51 +00:00
|
|
|
assert.Equal(t, CMDVerack, msg.Command)
|
2018-03-14 09:36:59 +00:00
|
|
|
}
|
2020-05-22 09:17:17 +00:00
|
|
|
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)
|
2018-01-31 19:11:08 +00:00
|
|
|
|
2020-02-29 15:55:16 +00:00
|
|
|
require.NoError(t, s.handleVersionCmd(p, version))
|
2018-01-31 19:11:08 +00:00
|
|
|
}
|
|
|
|
|
2018-03-14 09:36:59 +00:00
|
|
|
// Server should not reply with a verack after receiving a
|
|
|
|
// invalid version and disconnects the peer.
|
|
|
|
func TestServerNotSendsVerack(t *testing.T) {
|
|
|
|
var (
|
2020-05-22 09:17:17 +00:00
|
|
|
s = newTestServer(t, ServerConfig{Net: 56753})
|
2020-01-21 14:26:08 +00:00
|
|
|
p = newLocalPeer(t, s)
|
|
|
|
p2 = newLocalPeer(t, s)
|
2018-03-14 09:36:59 +00:00
|
|
|
)
|
|
|
|
s.id = 1
|
2020-04-22 14:43:50 +00:00
|
|
|
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
|
|
|
|
}()
|
2018-03-09 15:55:25 +00:00
|
|
|
|
2019-09-09 14:54:38 +00:00
|
|
|
na, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:3000")
|
|
|
|
p.netaddr = *na
|
2019-11-06 09:39:17 +00:00
|
|
|
p2.netaddr = *na
|
2018-03-14 09:36:59 +00:00
|
|
|
s.register <- p
|
2018-03-09 15:55:25 +00:00
|
|
|
|
2020-05-22 09:17:17 +00:00
|
|
|
capabilities := []capability.Capability{
|
|
|
|
{
|
|
|
|
Type: capability.FullNode,
|
|
|
|
Data: &capability.Node{
|
|
|
|
StartHeight: 0,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
Type: capability.TCPServer,
|
|
|
|
Data: &capability.Server{
|
|
|
|
Port: 3000,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
2018-03-14 09:36:59 +00:00
|
|
|
// identical id's
|
2020-05-22 09:17:17 +00:00
|
|
|
version := payload.NewVersion(56753, 1, "/NEO-GO/", capabilities)
|
2019-10-17 08:19:24 +00:00
|
|
|
err := s.handleVersionCmd(p, version)
|
2018-03-14 09:36:59 +00:00
|
|
|
assert.NotNil(t, err)
|
|
|
|
assert.Equal(t, errIdenticalID, err)
|
2019-11-06 09:39:17 +00:00
|
|
|
|
2020-05-21 10:35:44 +00:00
|
|
|
// Different IDs, but also different magics
|
2019-11-06 09:39:17 +00:00
|
|
|
version.Nonce = 2
|
2020-05-21 10:35:44 +00:00
|
|
|
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
|
2019-11-06 09:39:17 +00:00
|
|
|
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)
|
2018-01-31 08:27:08 +00:00
|
|
|
}
|