github.com/nspcc-dev/neo-go@v0.105.2-0.20240517133400-6be757af3eba/pkg/network/server_test.go (about)

     1  package network
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math/big"
     7  	"net"
     8  	"strconv"
     9  	"sync"
    10  	"sync/atomic"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/nspcc-dev/neo-go/internal/fakechain"
    15  	"github.com/nspcc-dev/neo-go/internal/random"
    16  	"github.com/nspcc-dev/neo-go/pkg/config"
    17  	"github.com/nspcc-dev/neo-go/pkg/consensus"
    18  	"github.com/nspcc-dev/neo-go/pkg/core"
    19  	"github.com/nspcc-dev/neo-go/pkg/core/block"
    20  	"github.com/nspcc-dev/neo-go/pkg/core/interop"
    21  	"github.com/nspcc-dev/neo-go/pkg/core/mpt"
    22  	"github.com/nspcc-dev/neo-go/pkg/core/transaction"
    23  	"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
    24  	"github.com/nspcc-dev/neo-go/pkg/network/capability"
    25  	"github.com/nspcc-dev/neo-go/pkg/network/payload"
    26  	"github.com/nspcc-dev/neo-go/pkg/util"
    27  	"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
    28  	"github.com/stretchr/testify/assert"
    29  	"github.com/stretchr/testify/require"
    30  	"go.uber.org/zap/zaptest"
    31  )
    32  
    33  type fakeConsensus struct {
    34  	started  atomic.Bool
    35  	stopped  atomic.Bool
    36  	payloads []*payload.Extensible
    37  	txlock   sync.Mutex
    38  	txs      []*transaction.Transaction
    39  }
    40  
    41  var _ consensus.Service = (*fakeConsensus)(nil)
    42  
    43  func (f *fakeConsensus) Name() string { return "fake" }
    44  func (f *fakeConsensus) Start()       { f.started.Store(true) }
    45  func (f *fakeConsensus) Shutdown()    { f.stopped.Store(true) }
    46  func (f *fakeConsensus) OnPayload(p *payload.Extensible) error {
    47  	f.payloads = append(f.payloads, p)
    48  	return nil
    49  }
    50  func (f *fakeConsensus) OnTransaction(tx *transaction.Transaction) {
    51  	f.txlock.Lock()
    52  	defer f.txlock.Unlock()
    53  	f.txs = append(f.txs, tx)
    54  }
    55  func (f *fakeConsensus) GetPayload(h util.Uint256) *payload.Extensible { panic("implement me") }
    56  
    57  func TestNewServer(t *testing.T) {
    58  	bc := &fakechain.FakeChain{Blockchain: config.Blockchain{
    59  		ProtocolConfiguration: config.ProtocolConfiguration{
    60  			P2PStateExchangeExtensions: true,
    61  			StateRootInHeader:          true,
    62  		}}}
    63  	s, err := newServerFromConstructors(ServerConfig{}, bc, new(fakechain.FakeStateSync), nil, newFakeTransp, newTestDiscovery)
    64  	require.Error(t, err)
    65  
    66  	t.Run("set defaults", func(t *testing.T) {
    67  		s = newTestServer(t, ServerConfig{MinPeers: -1})
    68  
    69  		require.True(t, s.ID() != 0)
    70  		require.Equal(t, defaultMinPeers, s.ServerConfig.MinPeers)
    71  		require.Equal(t, defaultMaxPeers, s.ServerConfig.MaxPeers)
    72  		require.Equal(t, defaultAttemptConnPeers, s.ServerConfig.AttemptConnPeers)
    73  	})
    74  	t.Run("don't defaults", func(t *testing.T) {
    75  		cfg := ServerConfig{
    76  			MinPeers:         1,
    77  			MaxPeers:         2,
    78  			AttemptConnPeers: 3,
    79  		}
    80  		s = newTestServer(t, cfg)
    81  
    82  		require.True(t, s.ID() != 0)
    83  		require.Equal(t, 1, s.ServerConfig.MinPeers)
    84  		require.Equal(t, 2, s.ServerConfig.MaxPeers)
    85  		require.Equal(t, 3, s.ServerConfig.AttemptConnPeers)
    86  	})
    87  }
    88  
    89  func TestServerStartAndShutdown(t *testing.T) {
    90  	t.Run("no consensus", func(t *testing.T) {
    91  		s := newTestServer(t, ServerConfig{})
    92  
    93  		s.Start()
    94  		p := newLocalPeer(t, s)
    95  		s.register <- p
    96  		require.Eventually(t, func() bool { return 1 == s.PeerCount() }, time.Second, time.Millisecond*10)
    97  
    98  		require.True(t, s.started.Load())
    99  		require.Eventually(t, func() bool {
   100  			return s.transports[0].(*fakeTransp).started.Load()
   101  		}, 2*time.Second, 200*time.Millisecond)
   102  		assert.Nil(t, s.txCallback)
   103  
   104  		s.Shutdown()
   105  
   106  		require.False(t, s.started.Load())
   107  		require.True(t, s.transports[0].(*fakeTransp).closed.Load())
   108  		err, ok := p.droppedWith.Load().(error)
   109  		require.True(t, ok)
   110  		require.ErrorIs(t, err, errServerShutdown)
   111  	})
   112  	t.Run("with consensus", func(t *testing.T) {
   113  		s := newTestServer(t, ServerConfig{})
   114  		cons := new(fakeConsensus)
   115  		s.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
   116  
   117  		s.Start()
   118  		p := newLocalPeer(t, s)
   119  		s.register <- p
   120  		require.Eventually(t, func() bool { return 1 == s.PeerCount() }, time.Second, time.Millisecond*10)
   121  
   122  		assert.True(t, s.services["fake"].(*fakeConsensus).started.Load())
   123  		require.True(t, s.started.Load())
   124  
   125  		s.Shutdown()
   126  
   127  		require.False(t, s.started.Load())
   128  		require.True(t, s.services["fake"].(*fakeConsensus).stopped.Load())
   129  	})
   130  	t.Run("double start", func(t *testing.T) {
   131  		s := newTestServer(t, ServerConfig{})
   132  		startWithCleanup(t, s)
   133  
   134  		// Attempt to start the server again.
   135  		s.Start()
   136  
   137  		require.True(t, s.started.Load(), "server should still be marked as started after second Start call")
   138  	})
   139  	t.Run("double shutdown", func(t *testing.T) {
   140  		s := newTestServer(t, ServerConfig{})
   141  		s.Start()
   142  		require.True(t, s.started.Load(), "server should still be marked as started after second Start call")
   143  		s.Shutdown()
   144  
   145  		require.False(t, s.started.Load(), "server should be marked as not started after second Shutdown call")
   146  		// Attempt to shutdown the server again.
   147  		s.Shutdown()
   148  		// Verify the server state remains unchanged and is still considered shutdown.
   149  		require.False(t, s.started.Load(), "server should remain shutdown after second call")
   150  	})
   151  }
   152  
   153  func TestServerRegisterPeer(t *testing.T) {
   154  	const peerCount = 3
   155  
   156  	s := newTestServer(t, ServerConfig{MaxPeers: 2})
   157  	ps := make([]*localPeer, peerCount)
   158  	for i := range ps {
   159  		ps[i] = newLocalPeer(t, s)
   160  		ps[i].netaddr.Port = i + 1
   161  		ps[i].version = &payload.Version{Nonce: uint32(i), UserAgent: []byte("fake")}
   162  	}
   163  
   164  	startWithCleanup(t, s)
   165  
   166  	s.register <- ps[0]
   167  	require.Eventually(t, func() bool { return 1 == s.PeerCount() }, time.Second, time.Millisecond*10)
   168  	s.handshake <- ps[0]
   169  
   170  	s.register <- ps[1]
   171  	s.handshake <- ps[1]
   172  	require.Eventually(t, func() bool { return 2 == s.PeerCount() }, time.Second, time.Millisecond*10)
   173  
   174  	require.Equal(t, 0, len(s.discovery.UnconnectedPeers()))
   175  	s.register <- ps[2]
   176  	require.Eventually(t, func() bool { return len(s.discovery.UnconnectedPeers()) > 0 }, time.Second, time.Millisecond*100)
   177  
   178  	index := -1
   179  	addrs := s.discovery.UnconnectedPeers()
   180  	for _, addr := range addrs {
   181  		for j := range ps {
   182  			if ps[j].PeerAddr().String() == addr {
   183  				index = j
   184  				break
   185  			}
   186  		}
   187  	}
   188  	require.True(t, index >= 0)
   189  	err, ok := ps[index].droppedWith.Load().(error)
   190  	require.True(t, ok)
   191  	require.ErrorIs(t, err, errMaxPeers)
   192  
   193  	index = (index + 1) % peerCount
   194  	s.unregister <- peerDrop{ps[index], errIdenticalID}
   195  	require.Eventually(t, func() bool {
   196  		bad := s.BadPeers()
   197  		for i := range bad {
   198  			if bad[i] == ps[index].PeerAddr().String() {
   199  				return true
   200  			}
   201  		}
   202  		return false
   203  	}, time.Second, time.Millisecond*50)
   204  }
   205  
   206  func TestGetBlocksByIndex(t *testing.T) {
   207  	testGetBlocksByIndex(t, CMDGetBlockByIndex)
   208  }
   209  
   210  func testGetBlocksByIndex(t *testing.T, cmd CommandType) {
   211  	s := newTestServer(t, ServerConfig{UserAgent: "/test/"})
   212  	start := s.chain.BlockHeight()
   213  	if cmd == CMDGetHeaders {
   214  		start = s.chain.HeaderHeight()
   215  		s.stateSync.(*fakechain.FakeStateSync).RequestHeaders.Store(true)
   216  	}
   217  	ps := make([]*localPeer, 10)
   218  	expectsCmd := make([]CommandType, 10)
   219  	expectedHeight := make([][]uint32, 10)
   220  	for i := range ps {
   221  		i := i
   222  		ps[i] = newLocalPeer(t, s)
   223  		ps[i].messageHandler = func(t *testing.T, msg *Message) {
   224  			require.Equal(t, expectsCmd[i], msg.Command)
   225  			if expectsCmd[i] == cmd {
   226  				p, ok := msg.Payload.(*payload.GetBlockByIndex)
   227  				require.True(t, ok)
   228  				require.Contains(t, expectedHeight[i], p.IndexStart)
   229  				expectsCmd[i] = CMDPong
   230  			} else if expectsCmd[i] == CMDPong {
   231  				expectsCmd[i] = cmd
   232  			}
   233  		}
   234  		expectsCmd[i] = cmd
   235  		expectedHeight[i] = []uint32{start + 1}
   236  	}
   237  	go s.transports[0].Accept()
   238  
   239  	nonce := uint32(0)
   240  	checkPingRespond := func(t *testing.T, peerIndex int, peerHeight uint32, hs ...uint32) {
   241  		nonce++
   242  		expectedHeight[peerIndex] = hs
   243  		require.NoError(t, s.handlePing(ps[peerIndex], payload.NewPing(peerHeight, nonce)))
   244  	}
   245  
   246  	// Send all requests for all chunks.
   247  	checkPingRespond(t, 0, 5000, 1)
   248  	checkPingRespond(t, 1, 5000, 1+payload.MaxHashesCount)
   249  	checkPingRespond(t, 2, 5000, 1+2*payload.MaxHashesCount)
   250  	checkPingRespond(t, 3, 5000, 1+3*payload.MaxHashesCount)
   251  
   252  	// Receive some blocks.
   253  	s.chain.(*fakechain.FakeChain).Blockheight.Store(2123)
   254  
   255  	// Minimum chunk has priority.
   256  	checkPingRespond(t, 5, 5000, 2124)
   257  	checkPingRespond(t, 6, 5000, 2624)
   258  	// Request minimal height for peers behind.
   259  	checkPingRespond(t, 7, 3100, 2124)
   260  	checkPingRespond(t, 8, 5000, 3124)
   261  	checkPingRespond(t, 9, 5000, 3624)
   262  	// Request random height after that.
   263  	checkPingRespond(t, 1, 5000, 2124, 2624, 3124, 3624)
   264  	checkPingRespond(t, 2, 5000, 2124, 2624, 3124, 3624)
   265  	checkPingRespond(t, 3, 5000, 2124, 2624, 3124, 3624)
   266  }
   267  
   268  func TestSendVersion(t *testing.T) {
   269  	var (
   270  		s = newTestServer(t, ServerConfig{UserAgent: "/test/"})
   271  		p = newLocalPeer(t, s)
   272  	)
   273  	// we need to set listener at least to handle dynamic port correctly
   274  	s.transports[0].Accept()
   275  	p.messageHandler = func(t *testing.T, msg *Message) {
   276  		// listener is already set, so Addresses(nil) gives us proper address with port
   277  		_, prt := s.transports[0].HostPort()
   278  		port, err := strconv.ParseUint(prt, 10, 16)
   279  		assert.NoError(t, err)
   280  		assert.Equal(t, CMDVersion, msg.Command)
   281  		assert.IsType(t, msg.Payload, &payload.Version{})
   282  		version := msg.Payload.(*payload.Version)
   283  		assert.NotZero(t, version.Nonce)
   284  		assert.Equal(t, 1, len(version.Capabilities))
   285  		assert.ElementsMatch(t, []capability.Capability{
   286  			{
   287  				Type: capability.TCPServer,
   288  				Data: &capability.Server{
   289  					Port: uint16(port),
   290  				},
   291  			},
   292  		}, version.Capabilities)
   293  		assert.Equal(t, uint32(0), version.Version)
   294  		assert.Equal(t, []byte("/test/"), version.UserAgent)
   295  	}
   296  
   297  	require.NoError(t, p.SendVersion())
   298  }
   299  
   300  // Server should reply with a verack after receiving a valid version.
   301  func TestVerackAfterHandleVersionCmd(t *testing.T) {
   302  	var (
   303  		s = newTestServer(t, ServerConfig{})
   304  		p = newLocalPeer(t, s)
   305  	)
   306  	na, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:3000")
   307  	p.netaddr = *na
   308  
   309  	// Should have a verack
   310  	p.messageHandler = func(t *testing.T, msg *Message) {
   311  		assert.Equal(t, CMDVerack, msg.Command)
   312  	}
   313  	capabilities := []capability.Capability{
   314  		{
   315  			Type: capability.FullNode,
   316  			Data: &capability.Node{
   317  				StartHeight: 0,
   318  			},
   319  		},
   320  		{
   321  			Type: capability.TCPServer,
   322  			Data: &capability.Server{
   323  				Port: 3000,
   324  			},
   325  		},
   326  	}
   327  	version := payload.NewVersion(0, 1337, "/NEO-GO/", capabilities)
   328  
   329  	require.NoError(t, s.handleVersionCmd(p, version))
   330  }
   331  
   332  // Server should not reply with a verack after receiving a
   333  // invalid version and disconnects the peer.
   334  func TestServerNotSendsVerack(t *testing.T) {
   335  	var (
   336  		s  = newTestServer(t, ServerConfig{MaxPeers: 10, Net: 56753})
   337  		p  = newLocalPeer(t, s)
   338  		p2 = newLocalPeer(t, s)
   339  	)
   340  	s.id = 1
   341  	startWithCleanup(t, s)
   342  
   343  	na, _ := net.ResolveTCPAddr("tcp", "0.0.0.0:3000")
   344  	p.netaddr = *na
   345  	p2.netaddr = *na
   346  	s.register <- p
   347  
   348  	capabilities := []capability.Capability{
   349  		{
   350  			Type: capability.FullNode,
   351  			Data: &capability.Node{
   352  				StartHeight: 0,
   353  			},
   354  		},
   355  		{
   356  			Type: capability.TCPServer,
   357  			Data: &capability.Server{
   358  				Port: 3000,
   359  			},
   360  		},
   361  	}
   362  	// identical id's
   363  	version := payload.NewVersion(56753, 1, "/NEO-GO/", capabilities)
   364  	err := s.handleVersionCmd(p, version)
   365  	assert.NotNil(t, err)
   366  	assert.Equal(t, errIdenticalID, err)
   367  
   368  	// Different IDs, but also different magics
   369  	version.Nonce = 2
   370  	version.Magic = 56752
   371  	err = s.handleVersionCmd(p, version)
   372  	assert.NotNil(t, err)
   373  	assert.Equal(t, errInvalidNetwork, err)
   374  
   375  	// Different IDs and same network, make handshake pass.
   376  	version.Magic = 56753
   377  	require.NoError(t, s.handleVersionCmd(p, version))
   378  	require.NoError(t, p.HandleVersionAck())
   379  	require.Equal(t, true, p.Handshaked())
   380  
   381  	// Second handshake from the same peer should fail.
   382  	s.register <- p2
   383  	err = s.handleVersionCmd(p2, version)
   384  	assert.NotNil(t, err)
   385  	require.Equal(t, errAlreadyConnected, err)
   386  }
   387  
   388  func (s *Server) testHandleMessage(t *testing.T, p Peer, cmd CommandType, pl payload.Payload) *Server {
   389  	if p == nil {
   390  		p = newLocalPeer(t, s)
   391  		p.(*localPeer).handshaked = 1
   392  	}
   393  	msg := NewMessage(cmd, pl)
   394  	require.NoError(t, s.handleMessage(p, msg))
   395  	return s
   396  }
   397  
   398  func startTestServer(t *testing.T, protocolCfg ...func(*config.Blockchain)) *Server {
   399  	var s *Server
   400  	srvCfg := ServerConfig{UserAgent: "/test/"}
   401  	if protocolCfg != nil {
   402  		s = newTestServerWithCustomCfg(t, srvCfg, protocolCfg[0])
   403  	} else {
   404  		s = newTestServer(t, srvCfg)
   405  	}
   406  	startWithCleanup(t, s)
   407  	return s
   408  }
   409  
   410  func startWithCleanup(t *testing.T, s *Server) {
   411  	s.Start()
   412  	t.Cleanup(func() {
   413  		s.Shutdown()
   414  	})
   415  }
   416  
   417  func TestBlock(t *testing.T) {
   418  	s := startTestServer(t)
   419  
   420  	s.chain.(*fakechain.FakeChain).Blockheight.Store(12344)
   421  	require.Equal(t, uint32(12344), s.chain.BlockHeight())
   422  
   423  	b := block.New(false)
   424  	b.Index = 12345
   425  	s.testHandleMessage(t, nil, CMDBlock, b)
   426  	require.Eventually(t, func() bool { return s.chain.BlockHeight() == 12345 }, 2*time.Second, time.Millisecond*500)
   427  }
   428  
   429  func TestConsensus(t *testing.T) {
   430  	s := newTestServer(t, ServerConfig{})
   431  	cons := new(fakeConsensus)
   432  	s.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
   433  	startWithCleanup(t, s)
   434  
   435  	s.chain.(*fakechain.FakeChain).Blockheight.Store(4)
   436  	p := newLocalPeer(t, s)
   437  	p.handshaked = 1
   438  	s.register <- p
   439  	require.Eventually(t, func() bool { return 1 == s.PeerCount() }, time.Second, time.Millisecond*10)
   440  
   441  	newConsensusMessage := func(start, end uint32) *Message {
   442  		pl := payload.NewExtensible()
   443  		pl.Category = payload.ConsensusCategory
   444  		pl.ValidBlockStart = start
   445  		pl.ValidBlockEnd = end
   446  		return NewMessage(CMDExtensible, pl)
   447  	}
   448  
   449  	s.chain.(*fakechain.FakeChain).VerifyWitnessF = func() (int64, error) { return 0, errors.New("invalid") }
   450  	msg := newConsensusMessage(0, s.chain.BlockHeight()+1)
   451  	require.Error(t, s.handleMessage(p, msg))
   452  
   453  	s.chain.(*fakechain.FakeChain).VerifyWitnessF = func() (int64, error) { return 0, nil }
   454  	require.NoError(t, s.handleMessage(p, msg))
   455  	require.Contains(t, s.services["fake"].(*fakeConsensus).payloads, msg.Payload.(*payload.Extensible))
   456  
   457  	t.Run("small ValidUntilBlockEnd", func(t *testing.T) {
   458  		t.Run("current height", func(t *testing.T) {
   459  			msg := newConsensusMessage(0, s.chain.BlockHeight())
   460  			require.NoError(t, s.handleMessage(p, msg))
   461  			require.NotContains(t, s.services["fake"].(*fakeConsensus).payloads, msg.Payload.(*payload.Extensible))
   462  		})
   463  		t.Run("invalid", func(t *testing.T) {
   464  			msg := newConsensusMessage(0, s.chain.BlockHeight()-1)
   465  			require.Error(t, s.handleMessage(p, msg))
   466  		})
   467  	})
   468  	t.Run("big ValidUntiLBlockStart", func(t *testing.T) {
   469  		msg := newConsensusMessage(s.chain.BlockHeight()+1, s.chain.BlockHeight()+2)
   470  		require.Error(t, s.handleMessage(p, msg))
   471  	})
   472  }
   473  
   474  func TestTransaction(t *testing.T) {
   475  	s := newTestServer(t, ServerConfig{})
   476  	cons := new(fakeConsensus)
   477  	s.AddConsensusService(cons, cons.OnPayload, cons.OnTransaction)
   478  	startWithCleanup(t, s)
   479  
   480  	t.Run("good", func(t *testing.T) {
   481  		tx := newDummyTx()
   482  		s.RequestTx(tx.Hash())
   483  		p := newLocalPeer(t, s)
   484  		p.isFullNode = true
   485  		p.messageHandler = func(t *testing.T, msg *Message) {
   486  			if msg.Command == CMDInv {
   487  				inv := msg.Payload.(*payload.Inventory)
   488  				require.Equal(t, payload.TXType, inv.Type)
   489  				require.Equal(t, []util.Uint256{tx.Hash()}, inv.Hashes)
   490  			}
   491  		}
   492  		s.register <- p
   493  
   494  		s.testHandleMessage(t, nil, CMDTX, tx)
   495  		require.Eventually(t, func() bool {
   496  			var fake = s.services["fake"].(*fakeConsensus)
   497  			fake.txlock.Lock()
   498  			defer fake.txlock.Unlock()
   499  			for _, t := range fake.txs {
   500  				if t == tx {
   501  					return true
   502  				}
   503  			}
   504  			return false
   505  		}, 2*time.Second, time.Millisecond*500)
   506  	})
   507  	t.Run("bad", func(t *testing.T) {
   508  		tx := newDummyTx()
   509  		s.RequestTx(tx.Hash())
   510  		s.chain.(*fakechain.FakeChain).PoolTxF = func(*transaction.Transaction) error { return core.ErrInsufficientFunds }
   511  		s.testHandleMessage(t, nil, CMDTX, tx)
   512  		require.Eventually(t, func() bool {
   513  			var fake = s.services["fake"].(*fakeConsensus)
   514  			fake.txlock.Lock()
   515  			defer fake.txlock.Unlock()
   516  			for _, t := range fake.txs {
   517  				if t == tx {
   518  					return true
   519  				}
   520  			}
   521  			return false
   522  		}, 2*time.Second, time.Millisecond*500)
   523  	})
   524  }
   525  
   526  func (s *Server) testHandleGetData(t *testing.T, invType payload.InventoryType, hs, notFound []util.Uint256, found payload.Payload) {
   527  	var recvResponse atomic.Bool
   528  	var recvNotFound atomic.Bool
   529  
   530  	p := newLocalPeer(t, s)
   531  	p.handshaked = 1
   532  	p.messageHandler = func(t *testing.T, msg *Message) {
   533  		switch msg.Command {
   534  		case CMDTX, CMDBlock, CMDExtensible, CMDP2PNotaryRequest:
   535  			require.Equal(t, found, msg.Payload)
   536  			recvResponse.Store(true)
   537  		case CMDNotFound:
   538  			require.Equal(t, notFound, msg.Payload.(*payload.Inventory).Hashes)
   539  			recvNotFound.Store(true)
   540  		}
   541  	}
   542  
   543  	s.testHandleMessage(t, p, CMDGetData, payload.NewInventory(invType, hs))
   544  
   545  	require.Eventually(t, func() bool { return recvResponse.Load() }, 2*time.Second, time.Millisecond)
   546  	require.Eventually(t, func() bool { return recvNotFound.Load() }, 2*time.Second, time.Millisecond)
   547  }
   548  
   549  func TestGetData(t *testing.T) {
   550  	s := startTestServer(t)
   551  	s.chain.(*fakechain.FakeChain).UtilityTokenBalance = big.NewInt(1000000)
   552  
   553  	t.Run("block", func(t *testing.T) {
   554  		b := newDummyBlock(2, 0)
   555  		hs := []util.Uint256{random.Uint256(), b.Hash(), random.Uint256()}
   556  		s.chain.(*fakechain.FakeChain).PutBlock(b)
   557  		notFound := []util.Uint256{hs[0], hs[2]}
   558  		s.testHandleGetData(t, payload.BlockType, hs, notFound, b)
   559  	})
   560  	t.Run("transaction", func(t *testing.T) {
   561  		tx := newDummyTx()
   562  		hs := []util.Uint256{random.Uint256(), tx.Hash(), random.Uint256()}
   563  		s.chain.(*fakechain.FakeChain).PutTx(tx)
   564  		notFound := []util.Uint256{hs[0], hs[2]}
   565  		s.testHandleGetData(t, payload.TXType, hs, notFound, tx)
   566  	})
   567  	t.Run("p2pNotaryRequest", func(t *testing.T) {
   568  		mainTx := &transaction.Transaction{
   569  			Attributes:      []transaction.Attribute{{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 1}}},
   570  			Script:          []byte{0, 1, 2},
   571  			ValidUntilBlock: 123,
   572  			Signers:         []transaction.Signer{{Account: random.Uint160()}},
   573  			Scripts:         []transaction.Witness{{InvocationScript: []byte{1, 2, 3}, VerificationScript: []byte{1, 2, 3}}},
   574  		}
   575  		mainTx.Size()
   576  		mainTx.Hash()
   577  		fallbackTx := &transaction.Transaction{
   578  			Script:          []byte{1, 2, 3},
   579  			ValidUntilBlock: 123,
   580  			Attributes: []transaction.Attribute{
   581  				{Type: transaction.NotValidBeforeT, Value: &transaction.NotValidBefore{Height: 123}},
   582  				{Type: transaction.ConflictsT, Value: &transaction.Conflicts{Hash: mainTx.Hash()}},
   583  				{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: 0}},
   584  			},
   585  			Signers: []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}},
   586  			Scripts: []transaction.Witness{{InvocationScript: append([]byte{byte(opcode.PUSHDATA1), keys.SignatureLen}, make([]byte, keys.SignatureLen)...), VerificationScript: make([]byte, 0)}, {InvocationScript: []byte{}, VerificationScript: []byte{}}},
   587  		}
   588  		fallbackTx.Size()
   589  		fallbackTx.Hash()
   590  		r := &payload.P2PNotaryRequest{
   591  			MainTransaction:     mainTx,
   592  			FallbackTransaction: fallbackTx,
   593  			Witness: transaction.Witness{
   594  				InvocationScript:   []byte{1, 2, 3},
   595  				VerificationScript: []byte{1, 2, 3},
   596  			},
   597  		}
   598  		r.Hash()
   599  		require.NoError(t, s.notaryRequestPool.Add(r.FallbackTransaction, s.chain, r))
   600  		hs := []util.Uint256{random.Uint256(), r.FallbackTransaction.Hash(), random.Uint256()}
   601  		notFound := []util.Uint256{hs[0], hs[2]}
   602  		s.testHandleGetData(t, payload.P2PNotaryRequestType, hs, notFound, r)
   603  	})
   604  }
   605  
   606  func initGetBlocksTest(t *testing.T) (*Server, []*block.Block) {
   607  	s := startTestServer(t)
   608  
   609  	var blocks []*block.Block
   610  	for i := uint32(12); i <= 15; i++ {
   611  		b := newDummyBlock(i, 3)
   612  		s.chain.(*fakechain.FakeChain).PutBlock(b)
   613  		blocks = append(blocks, b)
   614  	}
   615  	return s, blocks
   616  }
   617  
   618  func TestGetBlocks(t *testing.T) {
   619  	s, blocks := initGetBlocksTest(t)
   620  
   621  	expected := make([]util.Uint256, len(blocks))
   622  	for i := range blocks {
   623  		expected[i] = blocks[i].Hash()
   624  	}
   625  	var actual []util.Uint256
   626  	p := newLocalPeer(t, s)
   627  	p.handshaked = 1
   628  	p.messageHandler = func(t *testing.T, msg *Message) {
   629  		if msg.Command == CMDInv {
   630  			actual = msg.Payload.(*payload.Inventory).Hashes
   631  		}
   632  	}
   633  
   634  	t.Run("2", func(t *testing.T) {
   635  		s.testHandleMessage(t, p, CMDGetBlocks, &payload.GetBlocks{HashStart: expected[0], Count: 2})
   636  		require.Equal(t, expected[1:3], actual)
   637  	})
   638  	t.Run("-1", func(t *testing.T) {
   639  		s.testHandleMessage(t, p, CMDGetBlocks, &payload.GetBlocks{HashStart: expected[0], Count: -1})
   640  		require.Equal(t, expected[1:], actual)
   641  	})
   642  	t.Run("invalid start", func(t *testing.T) {
   643  		msg := NewMessage(CMDGetBlocks, &payload.GetBlocks{HashStart: util.Uint256{}, Count: -1})
   644  		require.Error(t, s.handleMessage(p, msg))
   645  	})
   646  }
   647  
   648  func TestGetBlockByIndex(t *testing.T) {
   649  	s, blocks := initGetBlocksTest(t)
   650  
   651  	var expected []*block.Block
   652  	var actual []*block.Block
   653  	p := newLocalPeer(t, s)
   654  	p.handshaked = 1
   655  	p.messageHandler = func(t *testing.T, msg *Message) {
   656  		if msg.Command == CMDBlock {
   657  			actual = append(actual, msg.Payload.(*block.Block))
   658  			if len(actual) == len(expected) {
   659  				require.Equal(t, expected, actual)
   660  			}
   661  		}
   662  	}
   663  
   664  	t.Run("2", func(t *testing.T) {
   665  		actual = nil
   666  		expected = blocks[:2]
   667  		s.testHandleMessage(t, p, CMDGetBlockByIndex, &payload.GetBlockByIndex{IndexStart: blocks[0].Index, Count: 2})
   668  	})
   669  	t.Run("-1", func(t *testing.T) {
   670  		actual = nil
   671  		expected = blocks
   672  		s.testHandleMessage(t, p, CMDGetBlockByIndex, &payload.GetBlockByIndex{IndexStart: blocks[0].Index, Count: -1})
   673  	})
   674  	t.Run("-1, last header", func(t *testing.T) {
   675  		s.chain.(*fakechain.FakeChain).PutHeader(newDummyBlock(16, 2))
   676  		actual = nil
   677  		expected = blocks
   678  		s.testHandleMessage(t, p, CMDGetBlockByIndex, &payload.GetBlockByIndex{IndexStart: blocks[0].Index, Count: -1})
   679  	})
   680  }
   681  
   682  func TestGetHeaders(t *testing.T) {
   683  	s, blocks := initGetBlocksTest(t)
   684  
   685  	expected := make([]*block.Header, len(blocks))
   686  	for i := range blocks {
   687  		expected[i] = &blocks[i].Header
   688  	}
   689  
   690  	var actual *payload.Headers
   691  	p := newLocalPeer(t, s)
   692  	p.handshaked = 1
   693  	p.messageHandler = func(t *testing.T, msg *Message) {
   694  		if msg.Command == CMDHeaders {
   695  			actual = msg.Payload.(*payload.Headers)
   696  		}
   697  	}
   698  
   699  	t.Run("2", func(t *testing.T) {
   700  		actual = nil
   701  		s.testHandleMessage(t, p, CMDGetHeaders, &payload.GetBlockByIndex{IndexStart: blocks[0].Index, Count: 2})
   702  		require.Equal(t, expected[:2], actual.Hdrs)
   703  	})
   704  	t.Run("more, than we have", func(t *testing.T) {
   705  		actual = nil
   706  		s.testHandleMessage(t, p, CMDGetHeaders, &payload.GetBlockByIndex{IndexStart: blocks[0].Index, Count: 10})
   707  		require.Equal(t, expected, actual.Hdrs)
   708  	})
   709  	t.Run("-1", func(t *testing.T) {
   710  		actual = nil
   711  		s.testHandleMessage(t, p, CMDGetHeaders, &payload.GetBlockByIndex{IndexStart: blocks[0].Index, Count: -1})
   712  		require.Equal(t, expected, actual.Hdrs)
   713  	})
   714  	t.Run("no headers", func(t *testing.T) {
   715  		actual = nil
   716  		s.testHandleMessage(t, p, CMDGetHeaders, &payload.GetBlockByIndex{IndexStart: 123, Count: -1})
   717  		require.Nil(t, actual)
   718  	})
   719  	t.Run("distribute requests between peers", func(t *testing.T) {
   720  		testGetBlocksByIndex(t, CMDGetHeaders)
   721  	})
   722  }
   723  
   724  func TestInv(t *testing.T) {
   725  	s := startTestServer(t)
   726  	s.chain.(*fakechain.FakeChain).UtilityTokenBalance = big.NewInt(10000000)
   727  
   728  	var actual []util.Uint256
   729  	p := newLocalPeer(t, s)
   730  	p.handshaked = 1
   731  	p.messageHandler = func(t *testing.T, msg *Message) {
   732  		if msg.Command == CMDGetData {
   733  			actual = msg.Payload.(*payload.Inventory).Hashes
   734  		}
   735  	}
   736  
   737  	t.Run("blocks", func(t *testing.T) {
   738  		b := newDummyBlock(10, 3)
   739  		s.chain.(*fakechain.FakeChain).PutBlock(b)
   740  		hs := []util.Uint256{random.Uint256(), b.Hash(), random.Uint256()}
   741  		s.testHandleMessage(t, p, CMDInv, &payload.Inventory{
   742  			Type:   payload.BlockType,
   743  			Hashes: hs,
   744  		})
   745  		require.Equal(t, []util.Uint256{hs[0], hs[2]}, actual)
   746  	})
   747  	t.Run("transaction", func(t *testing.T) {
   748  		tx := newDummyTx()
   749  		require.NoError(t, s.chain.GetMemPool().Add(tx, s.chain))
   750  		hs := []util.Uint256{random.Uint256(), tx.Hash(), random.Uint256()}
   751  		s.testHandleMessage(t, p, CMDInv, &payload.Inventory{
   752  			Type:   payload.TXType,
   753  			Hashes: hs,
   754  		})
   755  		require.Equal(t, []util.Uint256{hs[0], hs[2]}, actual)
   756  	})
   757  	t.Run("extensible", func(t *testing.T) {
   758  		ep := payload.NewExtensible()
   759  		s.chain.(*fakechain.FakeChain).VerifyWitnessF = func() (int64, error) { return 0, nil }
   760  		ep.ValidBlockEnd = s.chain.(*fakechain.FakeChain).BlockHeight() + 1
   761  		ok, err := s.extensiblePool.Add(ep)
   762  		require.NoError(t, err)
   763  		require.True(t, ok)
   764  		s.testHandleMessage(t, p, CMDInv, &payload.Inventory{
   765  			Type:   payload.ExtensibleType,
   766  			Hashes: []util.Uint256{ep.Hash()},
   767  		})
   768  	})
   769  	t.Run("p2pNotaryRequest", func(t *testing.T) {
   770  		fallbackTx := transaction.New(random.Bytes(100), 123)
   771  		fallbackTx.Signers = []transaction.Signer{{Account: random.Uint160()}, {Account: random.Uint160()}}
   772  		fallbackTx.Size()
   773  		fallbackTx.Hash()
   774  		r := &payload.P2PNotaryRequest{
   775  			MainTransaction:     newDummyTx(),
   776  			FallbackTransaction: fallbackTx,
   777  		}
   778  		require.NoError(t, s.notaryRequestPool.Add(r.FallbackTransaction, s.chain, r))
   779  		hs := []util.Uint256{random.Uint256(), r.FallbackTransaction.Hash(), random.Uint256()}
   780  		s.testHandleMessage(t, p, CMDInv, &payload.Inventory{
   781  			Type:   payload.P2PNotaryRequestType,
   782  			Hashes: hs,
   783  		})
   784  		require.Equal(t, []util.Uint256{hs[0], hs[2]}, actual)
   785  	})
   786  }
   787  
   788  func TestHandleGetMPTData(t *testing.T) {
   789  	t.Run("P2PStateExchange extensions off", func(t *testing.T) {
   790  		s := startTestServer(t)
   791  		p := newLocalPeer(t, s)
   792  		p.handshaked = 1
   793  		msg := NewMessage(CMDGetMPTData, &payload.MPTInventory{
   794  			Hashes: []util.Uint256{{1, 2, 3}},
   795  		})
   796  		require.Error(t, s.handleMessage(p, msg))
   797  	})
   798  
   799  	check := func(t *testing.T, s *Server) {
   800  		var recvResponse atomic.Bool
   801  		r1 := random.Uint256()
   802  		r2 := random.Uint256()
   803  		r3 := random.Uint256()
   804  		node := []byte{1, 2, 3}
   805  		s.stateSync.(*fakechain.FakeStateSync).TraverseFunc = func(root util.Uint256, process func(node mpt.Node, nodeBytes []byte) bool) error {
   806  			if !(root.Equals(r1) || root.Equals(r2)) {
   807  				t.Fatal("unexpected root")
   808  			}
   809  			require.False(t, process(mpt.NewHashNode(r3), node))
   810  			return nil
   811  		}
   812  		found := &payload.MPTData{
   813  			Nodes: [][]byte{node}, // no duplicates expected
   814  		}
   815  		p := newLocalPeer(t, s)
   816  		p.handshaked = 1
   817  		p.messageHandler = func(t *testing.T, msg *Message) {
   818  			switch msg.Command {
   819  			case CMDMPTData:
   820  				require.Equal(t, found, msg.Payload)
   821  				recvResponse.Store(true)
   822  			}
   823  		}
   824  		hs := []util.Uint256{r1, r2}
   825  		s.testHandleMessage(t, p, CMDGetMPTData, payload.NewMPTInventory(hs))
   826  
   827  		require.Eventually(t, recvResponse.Load, time.Second, time.Millisecond)
   828  	}
   829  	t.Run("KeepOnlyLatestState on", func(t *testing.T) {
   830  		s := startTestServer(t, func(c *config.Blockchain) {
   831  			c.P2PStateExchangeExtensions = true
   832  			c.Ledger.KeepOnlyLatestState = true
   833  		})
   834  		check(t, s)
   835  	})
   836  
   837  	t.Run("good", func(t *testing.T) {
   838  		s := startTestServer(t, func(c *config.Blockchain) {
   839  			c.P2PStateExchangeExtensions = true
   840  		})
   841  		check(t, s)
   842  	})
   843  }
   844  
   845  func TestHandleMPTData(t *testing.T) {
   846  	t.Run("P2PStateExchange extensions off", func(t *testing.T) {
   847  		s := startTestServer(t)
   848  		p := newLocalPeer(t, s)
   849  		p.handshaked = 1
   850  		msg := NewMessage(CMDMPTData, &payload.MPTData{
   851  			Nodes: [][]byte{{1, 2, 3}},
   852  		})
   853  		require.Error(t, s.handleMessage(p, msg))
   854  	})
   855  
   856  	t.Run("good", func(t *testing.T) {
   857  		expected := [][]byte{{1, 2, 3}, {2, 3, 4}}
   858  		s := newTestServer(t, ServerConfig{UserAgent: "/test/"})
   859  		s.config.P2PStateExchangeExtensions = true
   860  		s.stateSync = &fakechain.FakeStateSync{
   861  			AddMPTNodesFunc: func(nodes [][]byte) error {
   862  				require.Equal(t, expected, nodes)
   863  				return nil
   864  			},
   865  		}
   866  		startWithCleanup(t, s)
   867  
   868  		p := newLocalPeer(t, s)
   869  		p.handshaked = 1
   870  		msg := NewMessage(CMDMPTData, &payload.MPTData{
   871  			Nodes: expected,
   872  		})
   873  		require.NoError(t, s.handleMessage(p, msg))
   874  	})
   875  }
   876  
   877  func TestRequestMPTNodes(t *testing.T) {
   878  	s := startTestServer(t)
   879  
   880  	var actual []util.Uint256
   881  	p := newLocalPeer(t, s)
   882  	p.handshaked = 1
   883  	p.messageHandler = func(t *testing.T, msg *Message) {
   884  		if msg.Command == CMDGetMPTData {
   885  			actual = append(actual, msg.Payload.(*payload.MPTInventory).Hashes...)
   886  		}
   887  	}
   888  	s.register <- p
   889  	s.register <- p // ensure previous send was handled
   890  
   891  	t.Run("no hashes, no message", func(t *testing.T) {
   892  		actual = nil
   893  		require.NoError(t, s.requestMPTNodes(p, nil))
   894  		require.Nil(t, actual)
   895  	})
   896  	t.Run("good, small", func(t *testing.T) {
   897  		actual = nil
   898  		expected := []util.Uint256{random.Uint256(), random.Uint256()}
   899  		require.NoError(t, s.requestMPTNodes(p, expected))
   900  		require.Equal(t, expected, actual)
   901  	})
   902  	t.Run("good, exactly one chunk", func(t *testing.T) {
   903  		actual = nil
   904  		expected := make([]util.Uint256, payload.MaxMPTHashesCount)
   905  		for i := range expected {
   906  			expected[i] = random.Uint256()
   907  		}
   908  		require.NoError(t, s.requestMPTNodes(p, expected))
   909  		require.Equal(t, expected, actual)
   910  	})
   911  	t.Run("good, too large chunk", func(t *testing.T) {
   912  		actual = nil
   913  		expected := make([]util.Uint256, payload.MaxMPTHashesCount+1)
   914  		for i := range expected {
   915  			expected[i] = random.Uint256()
   916  		}
   917  		require.NoError(t, s.requestMPTNodes(p, expected))
   918  		require.Equal(t, expected[:payload.MaxMPTHashesCount], actual)
   919  	})
   920  }
   921  
   922  func TestRequestTx(t *testing.T) {
   923  	s := startTestServer(t)
   924  
   925  	var actual []util.Uint256
   926  	p := newLocalPeer(t, s)
   927  	p.handshaked = 1
   928  	p.messageHandler = func(t *testing.T, msg *Message) {
   929  		if msg.Command == CMDGetData {
   930  			actual = append(actual, msg.Payload.(*payload.Inventory).Hashes...)
   931  		}
   932  	}
   933  	s.register <- p
   934  	s.register <- p // ensure previous send was handled
   935  
   936  	t.Run("no hashes, no message", func(t *testing.T) {
   937  		actual = nil
   938  		s.RequestTx()
   939  		require.Nil(t, actual)
   940  	})
   941  	t.Run("good, small", func(t *testing.T) {
   942  		actual = nil
   943  		expected := []util.Uint256{random.Uint256(), random.Uint256()}
   944  		s.RequestTx(expected...)
   945  		require.Equal(t, expected, actual)
   946  	})
   947  	t.Run("good, exactly one chunk", func(t *testing.T) {
   948  		actual = nil
   949  		expected := make([]util.Uint256, payload.MaxHashesCount)
   950  		for i := range expected {
   951  			expected[i] = random.Uint256()
   952  		}
   953  		s.RequestTx(expected...)
   954  		require.Equal(t, expected, actual)
   955  	})
   956  	t.Run("good, multiple chunks", func(t *testing.T) {
   957  		actual = nil
   958  		expected := make([]util.Uint256, payload.MaxHashesCount*2+payload.MaxHashesCount/2)
   959  		for i := range expected {
   960  			expected[i] = random.Uint256()
   961  		}
   962  		s.RequestTx(expected...)
   963  		require.Equal(t, expected, actual)
   964  	})
   965  }
   966  
   967  func TestAddrs(t *testing.T) {
   968  	s := startTestServer(t)
   969  
   970  	ips := make([][16]byte, 4)
   971  	copy(ips[0][:], net.IPv4(1, 2, 3, 4))
   972  	copy(ips[1][:], net.IPv4(7, 8, 9, 0))
   973  	for i := range ips[2] {
   974  		ips[2][i] = byte(i)
   975  	}
   976  
   977  	p := newLocalPeer(t, s)
   978  	p.handshaked = 1
   979  	p.getAddrSent = 1
   980  	pl := &payload.AddressList{
   981  		Addrs: []*payload.AddressAndTime{
   982  			{
   983  				IP: ips[0],
   984  				Capabilities: capability.Capabilities{{
   985  					Type: capability.TCPServer,
   986  					Data: &capability.Server{Port: 12},
   987  				}},
   988  			},
   989  			{
   990  				IP:           ips[1],
   991  				Capabilities: capability.Capabilities{},
   992  			},
   993  			{
   994  				IP: ips[2],
   995  				Capabilities: capability.Capabilities{{
   996  					Type: capability.TCPServer,
   997  					Data: &capability.Server{Port: 42},
   998  				}},
   999  			},
  1000  		},
  1001  	}
  1002  	s.testHandleMessage(t, p, CMDAddr, pl)
  1003  
  1004  	addrs := s.discovery.(*testDiscovery).backfill
  1005  	require.Equal(t, 2, len(addrs))
  1006  	require.Equal(t, "1.2.3.4:12", addrs[0])
  1007  	require.Equal(t, net.JoinHostPort(net.IP(ips[2][:]).String(), "42"), addrs[1])
  1008  
  1009  	t.Run("CMDAddr not requested", func(t *testing.T) {
  1010  		msg := NewMessage(CMDAddr, pl)
  1011  		require.Error(t, s.handleMessage(p, msg))
  1012  	})
  1013  }
  1014  
  1015  type feerStub struct {
  1016  	blockHeight uint32
  1017  }
  1018  
  1019  func (f feerStub) FeePerByte() int64                            { return 1 }
  1020  func (f feerStub) GetUtilityTokenBalance(util.Uint160) *big.Int { return big.NewInt(100000000) }
  1021  func (f feerStub) BlockHeight() uint32                          { return f.blockHeight }
  1022  func (f feerStub) GetBaseExecFee() int64                        { return interop.DefaultBaseExecFee }
  1023  
  1024  func TestMemPool(t *testing.T) {
  1025  	s := startTestServer(t)
  1026  
  1027  	var actual []util.Uint256
  1028  	p := newLocalPeer(t, s)
  1029  	p.handshaked = 1
  1030  	p.messageHandler = func(t *testing.T, msg *Message) {
  1031  		if msg.Command == CMDInv {
  1032  			actual = append(actual, msg.Payload.(*payload.Inventory).Hashes...)
  1033  		}
  1034  	}
  1035  
  1036  	bc := s.chain.(*fakechain.FakeChain)
  1037  	expected := make([]util.Uint256, 4)
  1038  	for i := range expected {
  1039  		tx := newDummyTx()
  1040  		require.NoError(t, bc.Pool.Add(tx, &feerStub{blockHeight: 10}))
  1041  		expected[i] = tx.Hash()
  1042  	}
  1043  
  1044  	s.testHandleMessage(t, p, CMDMempool, payload.NullPayload{})
  1045  	require.ElementsMatch(t, expected, actual)
  1046  }
  1047  
  1048  func TestVerifyNotaryRequest(t *testing.T) {
  1049  	bc := fakechain.NewFakeChain()
  1050  	bc.MaxVerificationGAS = 10
  1051  	bc.NotaryContractScriptHash = util.Uint160{1, 2, 3}
  1052  	s, err := newServerFromConstructors(ServerConfig{Addresses: []config.AnnounceableAddress{{Address: ":0"}}}, bc, new(fakechain.FakeStateSync), zaptest.NewLogger(t), newFakeTransp, newTestDiscovery)
  1053  	require.NoError(t, err)
  1054  	newNotaryRequest := func() *payload.P2PNotaryRequest {
  1055  		return &payload.P2PNotaryRequest{
  1056  			MainTransaction: &transaction.Transaction{
  1057  				Script:  []byte{0, 1, 2},
  1058  				Signers: []transaction.Signer{{Account: random.Uint160()}},
  1059  			},
  1060  			FallbackTransaction: &transaction.Transaction{
  1061  				ValidUntilBlock: 321,
  1062  				Signers:         []transaction.Signer{{Account: bc.NotaryContractScriptHash}, {Account: random.Uint160()}},
  1063  			},
  1064  			Witness: transaction.Witness{},
  1065  		}
  1066  	}
  1067  
  1068  	t.Run("bad payload witness", func(t *testing.T) {
  1069  		bc.VerifyWitnessF = func() (int64, error) { return 0, errors.New("bad witness") }
  1070  		require.Error(t, s.verifyNotaryRequest(nil, newNotaryRequest()))
  1071  	})
  1072  
  1073  	t.Run("bad fallback sender", func(t *testing.T) {
  1074  		bc.VerifyWitnessF = func() (int64, error) { return 0, nil }
  1075  		r := newNotaryRequest()
  1076  		r.FallbackTransaction.Signers[0] = transaction.Signer{Account: util.Uint160{7, 8, 9}}
  1077  		require.Error(t, s.verifyNotaryRequest(nil, r))
  1078  	})
  1079  
  1080  	t.Run("bad main sender", func(t *testing.T) {
  1081  		bc.VerifyWitnessF = func() (int64, error) { return 0, nil }
  1082  		r := newNotaryRequest()
  1083  		r.MainTransaction.Signers[0] = transaction.Signer{Account: bc.NotaryContractScriptHash}
  1084  		require.Error(t, s.verifyNotaryRequest(nil, r))
  1085  	})
  1086  
  1087  	t.Run("expired deposit", func(t *testing.T) {
  1088  		r := newNotaryRequest()
  1089  		bc.NotaryDepositExpiration = r.FallbackTransaction.ValidUntilBlock
  1090  		require.Error(t, s.verifyNotaryRequest(nil, r))
  1091  	})
  1092  
  1093  	t.Run("good", func(t *testing.T) {
  1094  		r := newNotaryRequest()
  1095  		bc.NotaryDepositExpiration = r.FallbackTransaction.ValidUntilBlock + 1
  1096  		require.NoError(t, s.verifyNotaryRequest(nil, r))
  1097  	})
  1098  }
  1099  
  1100  func TestTryInitStateSync(t *testing.T) {
  1101  	t.Run("module inactive", func(t *testing.T) {
  1102  		s := startTestServer(t)
  1103  		s.tryInitStateSync()
  1104  	})
  1105  
  1106  	t.Run("module already initialized", func(t *testing.T) {
  1107  		s := startTestServer(t)
  1108  		ss := &fakechain.FakeStateSync{}
  1109  		ss.IsActiveFlag.Store(true)
  1110  		ss.IsInitializedFlag.Store(true)
  1111  		s.stateSync = ss
  1112  		s.tryInitStateSync()
  1113  	})
  1114  
  1115  	t.Run("good", func(t *testing.T) {
  1116  		s := startTestServer(t)
  1117  		for _, h := range []uint32{10, 8, 7, 4, 11, 4} {
  1118  			p := newLocalPeer(t, s)
  1119  			p.handshaked = 1
  1120  			p.lastBlockIndex = h
  1121  			s.register <- p
  1122  		}
  1123  		p := newLocalPeer(t, s)
  1124  		p.handshaked = 0 // one disconnected peer to check it won't be taken into attention
  1125  		p.lastBlockIndex = 5
  1126  		s.register <- p
  1127  		require.Eventually(t, func() bool { return 7 == s.PeerCount() }, time.Second, time.Millisecond*10)
  1128  
  1129  		var expectedH uint32 = 8 // median peer
  1130  		ss := &fakechain.FakeStateSync{InitFunc: func(h uint32) error {
  1131  			if h != expectedH {
  1132  				return fmt.Errorf("invalid height: expected %d, got %d", expectedH, h)
  1133  			}
  1134  			return nil
  1135  		}}
  1136  		ss.IsActiveFlag.Store(true)
  1137  		s.stateSync = ss
  1138  		s.tryInitStateSync()
  1139  	})
  1140  }
  1141  
  1142  func TestServer_Port(t *testing.T) {
  1143  	s := newTestServer(t, ServerConfig{
  1144  		Addresses: []config.AnnounceableAddress{
  1145  			{Address: "1.2.3.4:10"},                           // some random address
  1146  			{Address: ":1"},                                   // listen all IPs
  1147  			{Address: "127.0.0.1:2"},                          // address without announced port
  1148  			{Address: "123.123.0.123:3", AnnouncedPort: 123}}, // address with announced port
  1149  	})
  1150  
  1151  	// Default addr => first port available
  1152  	actual, err := s.Port(nil)
  1153  	require.NoError(t, err)
  1154  	require.Equal(t, uint16(10), actual)
  1155  
  1156  	// Specified address with direct match => port of matched address
  1157  	actual, err = s.Port(&net.TCPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 123})
  1158  	require.NoError(t, err)
  1159  	require.Equal(t, uint16(2), actual)
  1160  
  1161  	// No address match => 0.0.0.0's port
  1162  	actual, err = s.Port(&net.TCPAddr{IP: net.IPv4(5, 6, 7, 8), Port: 123})
  1163  	require.NoError(t, err)
  1164  	require.Equal(t, uint16(1), actual)
  1165  
  1166  	// Specified address with match on announceable address => announced port
  1167  	actual, err = s.Port(&net.TCPAddr{IP: net.IPv4(123, 123, 0, 123), Port: 123})
  1168  	require.NoError(t, err)
  1169  	require.Equal(t, uint16(123), actual)
  1170  }