github.com/fff-chain/go-fff@v0.0.0-20220726032732-1c84420b8a99/cmd/devp2p/internal/ethtest/eth66_suite.go (about)

     1  // Copyright 2021 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethtest
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/fff-chain/go-fff/common"
    23  	"github.com/fff-chain/go-fff/core/types"
    24  	"github.com/fff-chain/go-fff/crypto"
    25  	"github.com/fff-chain/go-fff/eth/protocols/eth"
    26  	"github.com/fff-chain/go-fff/internal/utesting"
    27  	"github.com/fff-chain/go-fff/p2p"
    28  )
    29  
    30  // Is_66 checks if the node supports the eth66 protocol version,
    31  // and if not, exists the test suite
    32  func (s *Suite) Is_66(t *utesting.T) {
    33  	conn := s.dial66(t)
    34  	conn.handshake(t)
    35  	if conn.negotiatedProtoVersion < 66 {
    36  		t.Fail()
    37  	}
    38  }
    39  
    40  // TestStatus_66 attempts to connect to the given node and exchange
    41  // a status message with it on the eth66 protocol, and then check to
    42  // make sure the chain head is correct.
    43  func (s *Suite) TestStatus_66(t *utesting.T) {
    44  	conn := s.dial66(t)
    45  	defer conn.Close()
    46  	// get protoHandshake
    47  	conn.handshake(t)
    48  	// get status
    49  	switch msg := conn.statusExchange66(t, s.chain).(type) {
    50  	case *Status:
    51  		status := *msg
    52  		if status.ProtocolVersion != uint32(66) {
    53  			t.Fatalf("mismatch in version: wanted 66, got %d", status.ProtocolVersion)
    54  		}
    55  		t.Logf("got status message: %s", pretty.Sdump(msg))
    56  	default:
    57  		t.Fatalf("unexpected: %s", pretty.Sdump(msg))
    58  	}
    59  }
    60  
    61  // TestGetBlockHeaders_66 tests whether the given node can respond to
    62  // an eth66 `GetBlockHeaders` request and that the response is accurate.
    63  func (s *Suite) TestGetBlockHeaders_66(t *utesting.T) {
    64  	conn := s.setupConnection66(t)
    65  	defer conn.Close()
    66  	// get block headers
    67  	req := &eth.GetBlockHeadersPacket66{
    68  		RequestId: 3,
    69  		GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
    70  			Origin: eth.HashOrNumber{
    71  				Hash: s.chain.blocks[1].Hash(),
    72  			},
    73  			Amount:  2,
    74  			Skip:    1,
    75  			Reverse: false,
    76  		},
    77  	}
    78  	// write message
    79  	headers, err := s.getBlockHeaders66(conn, req, req.RequestId)
    80  	if err != nil {
    81  		t.Fatalf("could not get block headers: %v", err)
    82  	}
    83  	// check for correct headers
    84  	if !headersMatch(t, s.chain, headers) {
    85  		t.Fatal("received wrong header(s)")
    86  	}
    87  }
    88  
    89  // TestSimultaneousRequests_66 sends two simultaneous `GetBlockHeader` requests
    90  // with different request IDs and checks to make sure the node responds with the correct
    91  // headers per request.
    92  func (s *Suite) TestSimultaneousRequests_66(t *utesting.T) {
    93  	// create two connections
    94  	conn := s.setupConnection66(t)
    95  	defer conn.Close()
    96  	// create two requests
    97  	req1 := &eth.GetBlockHeadersPacket66{
    98  		RequestId: 111,
    99  		GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
   100  			Origin: eth.HashOrNumber{
   101  				Hash: s.chain.blocks[1].Hash(),
   102  			},
   103  			Amount:  2,
   104  			Skip:    1,
   105  			Reverse: false,
   106  		},
   107  	}
   108  	req2 := &eth.GetBlockHeadersPacket66{
   109  		RequestId: 222,
   110  		GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
   111  			Origin: eth.HashOrNumber{
   112  				Hash: s.chain.blocks[1].Hash(),
   113  			},
   114  			Amount:  4,
   115  			Skip:    1,
   116  			Reverse: false,
   117  		},
   118  	}
   119  	// write first request
   120  	if err := conn.write66(req1, GetBlockHeaders{}.Code()); err != nil {
   121  		t.Fatalf("failed to write to connection: %v", err)
   122  	}
   123  	// write second request
   124  	if err := conn.write66(req2, GetBlockHeaders{}.Code()); err != nil {
   125  		t.Fatalf("failed to write to connection: %v", err)
   126  	}
   127  	// wait for responses
   128  	headers1, err := s.waitForBlockHeadersResponse66(conn, req1.RequestId)
   129  	if err != nil {
   130  		t.Fatalf("error while waiting for block headers: %v", err)
   131  	}
   132  	headers2, err := s.waitForBlockHeadersResponse66(conn, req2.RequestId)
   133  	if err != nil {
   134  		t.Fatalf("error while waiting for block headers: %v", err)
   135  	}
   136  	// check headers of both responses
   137  	if !headersMatch(t, s.chain, headers1) {
   138  		t.Fatalf("wrong header(s) in response to req1: got %v", headers1)
   139  	}
   140  	if !headersMatch(t, s.chain, headers2) {
   141  		t.Fatalf("wrong header(s) in response to req2: got %v", headers2)
   142  	}
   143  }
   144  
   145  // TestBroadcast_66 tests whether a block announcement is correctly
   146  // propagated to the given node's peer(s) on the eth66 protocol.
   147  func (s *Suite) TestBroadcast_66(t *utesting.T) {
   148  	s.sendNextBlock66(t)
   149  }
   150  
   151  // TestGetBlockBodies_66 tests whether the given node can respond to
   152  // a `GetBlockBodies` request and that the response is accurate over
   153  // the eth66 protocol.
   154  func (s *Suite) TestGetBlockBodies_66(t *utesting.T) {
   155  	conn := s.setupConnection66(t)
   156  	defer conn.Close()
   157  	// create block bodies request
   158  	id := uint64(55)
   159  	req := &eth.GetBlockBodiesPacket66{
   160  		RequestId: id,
   161  		GetBlockBodiesPacket: eth.GetBlockBodiesPacket{
   162  			s.chain.blocks[54].Hash(),
   163  			s.chain.blocks[75].Hash(),
   164  		},
   165  	}
   166  	if err := conn.write66(req, GetBlockBodies{}.Code()); err != nil {
   167  		t.Fatalf("could not write to connection: %v", err)
   168  	}
   169  
   170  	reqID, msg := conn.readAndServe66(s.chain, timeout)
   171  	switch msg := msg.(type) {
   172  	case BlockBodies:
   173  		if reqID != req.RequestId {
   174  			t.Fatalf("request ID mismatch: wanted %d, got %d", req.RequestId, reqID)
   175  		}
   176  		t.Logf("received %d block bodies", len(msg))
   177  	default:
   178  		t.Fatalf("unexpected: %s", pretty.Sdump(msg))
   179  	}
   180  }
   181  
   182  // TestLargeAnnounce_66 tests the announcement mechanism with a large block.
   183  func (s *Suite) TestLargeAnnounce_66(t *utesting.T) {
   184  	nextBlock := len(s.chain.blocks)
   185  	blocks := []*NewBlock{
   186  		{
   187  			Block: largeBlock(),
   188  			TD:    s.fullChain.TD(nextBlock + 1),
   189  		},
   190  		{
   191  			Block: s.fullChain.blocks[nextBlock],
   192  			TD:    largeNumber(2),
   193  		},
   194  		{
   195  			Block: largeBlock(),
   196  			TD:    largeNumber(2),
   197  		},
   198  		{
   199  			Block: s.fullChain.blocks[nextBlock],
   200  			TD:    s.fullChain.TD(nextBlock + 1),
   201  		},
   202  	}
   203  
   204  	for i, blockAnnouncement := range blocks[0:3] {
   205  		t.Logf("Testing malicious announcement: %v\n", i)
   206  		sendConn := s.setupConnection66(t)
   207  		if err := sendConn.Write(blockAnnouncement); err != nil {
   208  			t.Fatalf("could not write to connection: %v", err)
   209  		}
   210  		// Invalid announcement, check that peer disconnected
   211  		switch msg := sendConn.ReadAndServe(s.chain, time.Second*8).(type) {
   212  		case *Disconnect:
   213  		case *Error:
   214  			break
   215  		default:
   216  			t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg))
   217  		}
   218  		sendConn.Close()
   219  	}
   220  	// Test the last block as a valid block
   221  	s.sendNextBlock66(t)
   222  }
   223  
   224  func (s *Suite) TestOldAnnounce_66(t *utesting.T) {
   225  	sendConn, recvConn := s.setupConnection66(t), s.setupConnection66(t)
   226  	defer sendConn.Close()
   227  	defer recvConn.Close()
   228  
   229  	s.oldAnnounce(t, sendConn, recvConn)
   230  }
   231  
   232  // TestMaliciousHandshake_66 tries to send malicious data during the handshake.
   233  func (s *Suite) TestMaliciousHandshake_66(t *utesting.T) {
   234  	conn := s.dial66(t)
   235  	defer conn.Close()
   236  	// write hello to client
   237  	pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:]
   238  	handshakes := []*Hello{
   239  		{
   240  			Version: 5,
   241  			Caps: []p2p.Cap{
   242  				{Name: largeString(2), Version: 66},
   243  			},
   244  			ID: pub0,
   245  		},
   246  		{
   247  			Version: 5,
   248  			Caps: []p2p.Cap{
   249  				{Name: "eth", Version: 64},
   250  				{Name: "eth", Version: 65},
   251  				{Name: "eth", Version: 66},
   252  			},
   253  			ID: append(pub0, byte(0)),
   254  		},
   255  		{
   256  			Version: 5,
   257  			Caps: []p2p.Cap{
   258  				{Name: "eth", Version: 64},
   259  				{Name: "eth", Version: 65},
   260  				{Name: "eth", Version: 66},
   261  			},
   262  			ID: append(pub0, pub0...),
   263  		},
   264  		{
   265  			Version: 5,
   266  			Caps: []p2p.Cap{
   267  				{Name: "eth", Version: 64},
   268  				{Name: "eth", Version: 65},
   269  				{Name: "eth", Version: 66},
   270  			},
   271  			ID: largeBuffer(2),
   272  		},
   273  		{
   274  			Version: 5,
   275  			Caps: []p2p.Cap{
   276  				{Name: largeString(2), Version: 66},
   277  			},
   278  			ID: largeBuffer(2),
   279  		},
   280  	}
   281  	for i, handshake := range handshakes {
   282  		t.Logf("Testing malicious handshake %v\n", i)
   283  		// Init the handshake
   284  		if err := conn.Write(handshake); err != nil {
   285  			t.Fatalf("could not write to connection: %v", err)
   286  		}
   287  		// check that the peer disconnected
   288  		timeout := 20 * time.Second
   289  		// Discard one hello
   290  		for i := 0; i < 2; i++ {
   291  			switch msg := conn.ReadAndServe(s.chain, timeout).(type) {
   292  			case *Disconnect:
   293  			case *Error:
   294  			case *Hello:
   295  				// Hello's are sent concurrently, so ignore them
   296  				continue
   297  			default:
   298  				t.Fatalf("unexpected: %s", pretty.Sdump(msg))
   299  			}
   300  		}
   301  		// Dial for the next round
   302  		conn = s.dial66(t)
   303  	}
   304  }
   305  
   306  // TestMaliciousStatus_66 sends a status package with a large total difficulty.
   307  func (s *Suite) TestMaliciousStatus_66(t *utesting.T) {
   308  	conn := s.dial66(t)
   309  	defer conn.Close()
   310  	// get protoHandshake
   311  	conn.handshake(t)
   312  	status := &Status{
   313  		ProtocolVersion: uint32(66),
   314  		NetworkID:       s.chain.chainConfig.ChainID.Uint64(),
   315  		TD:              largeNumber(2),
   316  		Head:            s.chain.blocks[s.chain.Len()-1].Hash(),
   317  		Genesis:         s.chain.blocks[0].Hash(),
   318  		ForkID:          s.chain.ForkID(),
   319  	}
   320  	// get status
   321  	switch msg := conn.statusExchange(t, s.chain, status).(type) {
   322  	case *Status:
   323  		t.Logf("%+v\n", msg)
   324  	default:
   325  		t.Fatalf("expected status, got: %#v ", msg)
   326  	}
   327  	// wait for disconnect
   328  	switch msg := conn.ReadAndServe(s.chain, timeout).(type) {
   329  	case *Disconnect:
   330  	case *Error:
   331  		return
   332  	default:
   333  		t.Fatalf("expected disconnect, got: %s", pretty.Sdump(msg))
   334  	}
   335  }
   336  
   337  func (s *Suite) TestTransaction_66(t *utesting.T) {
   338  	tests := []*types.Transaction{
   339  		getNextTxFromChain(t, s),
   340  		unknownTx(t, s),
   341  	}
   342  	for i, tx := range tests {
   343  		t.Logf("Testing tx propagation: %v\n", i)
   344  		sendSuccessfulTx66(t, s, tx)
   345  	}
   346  }
   347  
   348  func (s *Suite) TestMaliciousTx_66(t *utesting.T) {
   349  	badTxs := []*types.Transaction{
   350  		getOldTxFromChain(t, s),
   351  		invalidNonceTx(t, s),
   352  		hugeAmount(t, s),
   353  		hugeGasPrice(t, s),
   354  		hugeData(t, s),
   355  	}
   356  	sendConn := s.setupConnection66(t)
   357  	defer sendConn.Close()
   358  	// set up receiving connection before sending txs to make sure
   359  	// no announcements are missed
   360  	recvConn := s.setupConnection66(t)
   361  	defer recvConn.Close()
   362  
   363  	for i, tx := range badTxs {
   364  		t.Logf("Testing malicious tx propagation: %v\n", i)
   365  		if err := sendConn.Write(&Transactions{tx}); err != nil {
   366  			t.Fatalf("could not write to connection: %v", err)
   367  		}
   368  
   369  	}
   370  	// check to make sure bad txs aren't propagated
   371  	waitForTxPropagation(t, s, badTxs, recvConn)
   372  }
   373  
   374  // TestZeroRequestID_66 checks that a request ID of zero is still handled
   375  // by the node.
   376  func (s *Suite) TestZeroRequestID_66(t *utesting.T) {
   377  	conn := s.setupConnection66(t)
   378  	defer conn.Close()
   379  
   380  	req := &eth.GetBlockHeadersPacket66{
   381  		RequestId: 0,
   382  		GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
   383  			Origin: eth.HashOrNumber{
   384  				Number: 0,
   385  			},
   386  			Amount: 2,
   387  		},
   388  	}
   389  	headers, err := s.getBlockHeaders66(conn, req, req.RequestId)
   390  	if err != nil {
   391  		t.Fatalf("could not get block headers: %v", err)
   392  	}
   393  	if !headersMatch(t, s.chain, headers) {
   394  		t.Fatal("received wrong header(s)")
   395  	}
   396  }
   397  
   398  // TestSameRequestID_66 sends two requests with the same request ID
   399  // concurrently to a single node.
   400  func (s *Suite) TestSameRequestID_66(t *utesting.T) {
   401  	conn := s.setupConnection66(t)
   402  	// create two requests with the same request ID
   403  	reqID := uint64(1234)
   404  	request1 := &eth.GetBlockHeadersPacket66{
   405  		RequestId: reqID,
   406  		GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
   407  			Origin: eth.HashOrNumber{
   408  				Number: 1,
   409  			},
   410  			Amount: 2,
   411  		},
   412  	}
   413  	request2 := &eth.GetBlockHeadersPacket66{
   414  		RequestId: reqID,
   415  		GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
   416  			Origin: eth.HashOrNumber{
   417  				Number: 33,
   418  			},
   419  			Amount: 2,
   420  		},
   421  	}
   422  	// write the first request
   423  	err := conn.write66(request1, GetBlockHeaders{}.Code())
   424  	if err != nil {
   425  		t.Fatalf("could not write to connection: %v", err)
   426  	}
   427  	// perform second request
   428  	headers2, err := s.getBlockHeaders66(conn, request2, reqID)
   429  	if err != nil {
   430  		t.Fatalf("could not get block headers: %v", err)
   431  		return
   432  	}
   433  	// wait for response to first request
   434  	headers1, err := s.waitForBlockHeadersResponse66(conn, reqID)
   435  	if err != nil {
   436  		t.Fatalf("could not get BlockHeaders response: %v", err)
   437  	}
   438  	// check if headers match
   439  	if !headersMatch(t, s.chain, headers1) || !headersMatch(t, s.chain, headers2) {
   440  		t.Fatal("received wrong header(s)")
   441  	}
   442  }
   443  
   444  // TestLargeTxRequest_66 tests whether a node can fulfill a large GetPooledTransactions
   445  // request.
   446  func (s *Suite) TestLargeTxRequest_66(t *utesting.T) {
   447  	// send the next block to ensure the node is no longer syncing and is able to accept
   448  	// txs
   449  	s.sendNextBlock66(t)
   450  	// send 2000 transactions to the node
   451  	hashMap, txs := generateTxs(t, s, 2000)
   452  	sendConn := s.setupConnection66(t)
   453  	defer sendConn.Close()
   454  
   455  	sendMultipleSuccessfulTxs(t, s, sendConn, txs)
   456  	// set up connection to receive to ensure node is peered with the receiving connection
   457  	// before tx request is sent
   458  	recvConn := s.setupConnection66(t)
   459  	defer recvConn.Close()
   460  	// create and send pooled tx request
   461  	hashes := make([]common.Hash, 0)
   462  	for _, hash := range hashMap {
   463  		hashes = append(hashes, hash)
   464  	}
   465  	getTxReq := &eth.GetPooledTransactionsPacket66{
   466  		RequestId:                   1234,
   467  		GetPooledTransactionsPacket: hashes,
   468  	}
   469  	if err := recvConn.write66(getTxReq, GetPooledTransactions{}.Code()); err != nil {
   470  		t.Fatalf("could not write to conn: %v", err)
   471  	}
   472  	// check that all received transactions match those that were sent to node
   473  	switch msg := recvConn.waitForResponse(s.chain, timeout, getTxReq.RequestId).(type) {
   474  	case PooledTransactions:
   475  		for _, gotTx := range msg {
   476  			if _, exists := hashMap[gotTx.Hash()]; !exists {
   477  				t.Fatalf("unexpected tx received: %v", gotTx.Hash())
   478  			}
   479  		}
   480  	default:
   481  		t.Fatalf("unexpected %s", pretty.Sdump(msg))
   482  	}
   483  }
   484  
   485  // TestNewPooledTxs_66 tests whether a node will do a GetPooledTransactions
   486  // request upon receiving a NewPooledTransactionHashes announcement.
   487  func (s *Suite) TestNewPooledTxs_66(t *utesting.T) {
   488  	// send the next block to ensure the node is no longer syncing and is able to accept
   489  	// txs
   490  	s.sendNextBlock66(t)
   491  	// generate 50 txs
   492  	hashMap, _ := generateTxs(t, s, 50)
   493  	// create new pooled tx hashes announcement
   494  	hashes := make([]common.Hash, 0)
   495  	for _, hash := range hashMap {
   496  		hashes = append(hashes, hash)
   497  	}
   498  	announce := NewPooledTransactionHashes(hashes)
   499  	// send announcement
   500  	conn := s.setupConnection66(t)
   501  	defer conn.Close()
   502  	if err := conn.Write(announce); err != nil {
   503  		t.Fatalf("could not write to connection: %v", err)
   504  	}
   505  	// wait for GetPooledTxs request
   506  	for {
   507  		_, msg := conn.readAndServe66(s.chain, timeout)
   508  		switch msg := msg.(type) {
   509  		case GetPooledTransactions:
   510  			if len(msg) != len(hashes) {
   511  				t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg))
   512  			}
   513  			return
   514  		case *NewPooledTransactionHashes, *NewBlock, *NewBlockHashes:
   515  			// ignore propagated txs and blocks from old tests
   516  			continue
   517  		default:
   518  			t.Fatalf("unexpected %s", pretty.Sdump(msg))
   519  		}
   520  	}
   521  }