github.com/theQRL/go-zond@v0.1.1/cmd/devp2p/internal/ethtest/suite.go (about)

     1  // Copyright 2020 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU 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  // go-ethereum 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 General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package ethtest
    18  
    19  import (
    20  	"time"
    21  
    22  	"github.com/theQRL/go-zond/common"
    23  	"github.com/theQRL/go-zond/internal/utesting"
    24  	"github.com/theQRL/go-zond/p2p/enode"
    25  	"github.com/theQRL/go-zond/zond/protocols/zond"
    26  )
    27  
    28  // Suite represents a structure used to test a node's conformance
    29  // to the zond protocol.
    30  type Suite struct {
    31  	Dest *enode.Node
    32  
    33  	chain     *Chain
    34  	fullChain *Chain
    35  }
    36  
    37  // NewSuite creates and returns a new zond-test suite that can
    38  // be used to test the given node against the given blockchain
    39  // data.
    40  func NewSuite(dest *enode.Node, chainfile string, genesisfile string) (*Suite, error) {
    41  	chain, err := loadChain(chainfile, genesisfile)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  	return &Suite{
    46  		Dest:      dest,
    47  		chain:     chain.Shorten(1000),
    48  		fullChain: chain,
    49  	}, nil
    50  }
    51  
    52  func (s *Suite) EthTests() []utesting.Test {
    53  	return []utesting.Test{
    54  		// status
    55  		{Name: "TestStatus", Fn: s.TestStatus},
    56  		// get block headers
    57  		{Name: "TestGetBlockHeaders", Fn: s.TestGetBlockHeaders},
    58  		{Name: "TestSimultaneousRequests", Fn: s.TestSimultaneousRequests},
    59  		{Name: "TestSameRequestID", Fn: s.TestSameRequestID},
    60  		{Name: "TestZeroRequestID", Fn: s.TestZeroRequestID},
    61  		// get block bodies
    62  		{Name: "TestGetBlockBodies", Fn: s.TestGetBlockBodies},
    63  		// broadcast
    64  		{Name: "TestBroadcast", Fn: s.TestBroadcast},
    65  		{Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce},
    66  		{Name: "TestOldAnnounce", Fn: s.TestOldAnnounce},
    67  		{Name: "TestBlockHashAnnounce", Fn: s.TestBlockHashAnnounce},
    68  		// malicious handshakes + status
    69  		{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake},
    70  		{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus},
    71  		// test transactions
    72  		{Name: "TestTransaction", Fn: s.TestTransaction},
    73  		{Name: "TestMaliciousTx", Fn: s.TestMaliciousTx},
    74  		{Name: "TestLargeTxRequest", Fn: s.TestLargeTxRequest},
    75  		{Name: "TestNewPooledTxs", Fn: s.TestNewPooledTxs},
    76  	}
    77  }
    78  
    79  func (s *Suite) SnapTests() []utesting.Test {
    80  	return []utesting.Test{
    81  		{Name: "TestSnapStatus", Fn: s.TestSnapStatus},
    82  		{Name: "TestSnapAccountRange", Fn: s.TestSnapGetAccountRange},
    83  		{Name: "TestSnapGetByteCodes", Fn: s.TestSnapGetByteCodes},
    84  		{Name: "TestSnapGetTrieNodes", Fn: s.TestSnapTrieNodes},
    85  		{Name: "TestSnapGetStorageRanges", Fn: s.TestSnapGetStorageRanges},
    86  	}
    87  }
    88  
    89  // TestStatus attempts to connect to the given node and exchange
    90  // a status message with it on the zond protocol.
    91  func (s *Suite) TestStatus(t *utesting.T) {
    92  	conn, err := s.dial()
    93  	if err != nil {
    94  		t.Fatalf("dial failed: %v", err)
    95  	}
    96  	defer conn.Close()
    97  	if err := conn.peer(s.chain, nil); err != nil {
    98  		t.Fatalf("peering failed: %v", err)
    99  	}
   100  }
   101  
   102  // TestGetBlockHeaders tests whether the given node can respond to
   103  // an zond `GetBlockHeaders` request and that the response is accurate.
   104  func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
   105  	conn, err := s.dial()
   106  	if err != nil {
   107  		t.Fatalf("dial failed: %v", err)
   108  	}
   109  	defer conn.Close()
   110  	if err = conn.peer(s.chain, nil); err != nil {
   111  		t.Fatalf("peering failed: %v", err)
   112  	}
   113  	// write request
   114  	req := &GetBlockHeaders{
   115  		GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{
   116  			Origin:  zond.HashOrNumber{Hash: s.chain.blocks[1].Hash()},
   117  			Amount:  2,
   118  			Skip:    1,
   119  			Reverse: false,
   120  		},
   121  	}
   122  	headers, err := conn.headersRequest(req, s.chain, 33)
   123  	if err != nil {
   124  		t.Fatalf("could not get block headers: %v", err)
   125  	}
   126  	// check for correct headers
   127  	expected, err := s.chain.GetHeaders(req)
   128  	if err != nil {
   129  		t.Fatalf("failed to get headers for given request: %v", err)
   130  	}
   131  	if !headersMatch(expected, headers) {
   132  		t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers)
   133  	}
   134  }
   135  
   136  // TestSimultaneousRequests sends two simultaneous `GetBlockHeader` requests from
   137  // the same connection with different request IDs and checks to make sure the node
   138  // responds with the correct headers per request.
   139  func (s *Suite) TestSimultaneousRequests(t *utesting.T) {
   140  	// create a connection
   141  	conn, err := s.dial()
   142  	if err != nil {
   143  		t.Fatalf("dial failed: %v", err)
   144  	}
   145  	defer conn.Close()
   146  	if err := conn.peer(s.chain, nil); err != nil {
   147  		t.Fatalf("peering failed: %v", err)
   148  	}
   149  
   150  	// create two requests
   151  	req1 := &GetBlockHeaders{
   152  		RequestId: uint64(111),
   153  		GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{
   154  			Origin: zond.HashOrNumber{
   155  				Hash: s.chain.blocks[1].Hash(),
   156  			},
   157  			Amount:  2,
   158  			Skip:    1,
   159  			Reverse: false,
   160  		},
   161  	}
   162  	req2 := &GetBlockHeaders{
   163  		RequestId: uint64(222),
   164  		GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{
   165  			Origin: zond.HashOrNumber{
   166  				Hash: s.chain.blocks[1].Hash(),
   167  			},
   168  			Amount:  4,
   169  			Skip:    1,
   170  			Reverse: false,
   171  		},
   172  	}
   173  
   174  	// write the first request
   175  	if err := conn.Write(req1); err != nil {
   176  		t.Fatalf("failed to write to connection: %v", err)
   177  	}
   178  	// write the second request
   179  	if err := conn.Write(req2); err != nil {
   180  		t.Fatalf("failed to write to connection: %v", err)
   181  	}
   182  
   183  	// wait for responses
   184  	msg := conn.waitForResponse(s.chain, timeout, req1.RequestId)
   185  	headers1, ok := msg.(*BlockHeaders)
   186  	if !ok {
   187  		t.Fatalf("unexpected %s", pretty.Sdump(msg))
   188  	}
   189  	msg = conn.waitForResponse(s.chain, timeout, req2.RequestId)
   190  	headers2, ok := msg.(*BlockHeaders)
   191  	if !ok {
   192  		t.Fatalf("unexpected %s", pretty.Sdump(msg))
   193  	}
   194  
   195  	// check received headers for accuracy
   196  	expected1, err := s.chain.GetHeaders(req1)
   197  	if err != nil {
   198  		t.Fatalf("failed to get expected headers for request 1: %v", err)
   199  	}
   200  	expected2, err := s.chain.GetHeaders(req2)
   201  	if err != nil {
   202  		t.Fatalf("failed to get expected headers for request 2: %v", err)
   203  	}
   204  	if !headersMatch(expected1, headers1.BlockHeadersPacket) {
   205  		t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected1, headers1)
   206  	}
   207  	if !headersMatch(expected2, headers2.BlockHeadersPacket) {
   208  		t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected2, headers2)
   209  	}
   210  }
   211  
   212  // TestSameRequestID sends two requests with the same request ID to a
   213  // single node.
   214  func (s *Suite) TestSameRequestID(t *utesting.T) {
   215  	conn, err := s.dial()
   216  	if err != nil {
   217  		t.Fatalf("dial failed: %v", err)
   218  	}
   219  	defer conn.Close()
   220  	if err := conn.peer(s.chain, nil); err != nil {
   221  		t.Fatalf("peering failed: %v", err)
   222  	}
   223  	// create requests
   224  	reqID := uint64(1234)
   225  	request1 := &GetBlockHeaders{
   226  		RequestId: reqID,
   227  		GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{
   228  			Origin: zond.HashOrNumber{
   229  				Number: 1,
   230  			},
   231  			Amount: 2,
   232  		},
   233  	}
   234  	request2 := &GetBlockHeaders{
   235  		RequestId: reqID,
   236  		GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{
   237  			Origin: zond.HashOrNumber{
   238  				Number: 33,
   239  			},
   240  			Amount: 2,
   241  		},
   242  	}
   243  
   244  	// write the requests
   245  	if err = conn.Write(request1); err != nil {
   246  		t.Fatalf("failed to write to connection: %v", err)
   247  	}
   248  	if err = conn.Write(request2); err != nil {
   249  		t.Fatalf("failed to write to connection: %v", err)
   250  	}
   251  
   252  	// wait for responses
   253  	msg := conn.waitForResponse(s.chain, timeout, reqID)
   254  	headers1, ok := msg.(*BlockHeaders)
   255  	if !ok {
   256  		t.Fatalf("unexpected %s", pretty.Sdump(msg))
   257  	}
   258  	msg = conn.waitForResponse(s.chain, timeout, reqID)
   259  	headers2, ok := msg.(*BlockHeaders)
   260  	if !ok {
   261  		t.Fatalf("unexpected %s", pretty.Sdump(msg))
   262  	}
   263  
   264  	// check if headers match
   265  	expected1, err := s.chain.GetHeaders(request1)
   266  	if err != nil {
   267  		t.Fatalf("failed to get expected block headers: %v", err)
   268  	}
   269  	expected2, err := s.chain.GetHeaders(request2)
   270  	if err != nil {
   271  		t.Fatalf("failed to get expected block headers: %v", err)
   272  	}
   273  	if !headersMatch(expected1, headers1.BlockHeadersPacket) {
   274  		t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected1, headers1)
   275  	}
   276  	if !headersMatch(expected2, headers2.BlockHeadersPacket) {
   277  		t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected2, headers2)
   278  	}
   279  }
   280  
   281  // TestZeroRequestID checks that a message with a request ID of zero is still handled
   282  // by the node.
   283  func (s *Suite) TestZeroRequestID(t *utesting.T) {
   284  	conn, err := s.dial()
   285  	if err != nil {
   286  		t.Fatalf("dial failed: %v", err)
   287  	}
   288  	defer conn.Close()
   289  	if err := conn.peer(s.chain, nil); err != nil {
   290  		t.Fatalf("peering failed: %v", err)
   291  	}
   292  	req := &GetBlockHeaders{
   293  		GetBlockHeadersPacket: &zond.GetBlockHeadersPacket{
   294  			Origin: zond.HashOrNumber{Number: 0},
   295  			Amount: 2,
   296  		},
   297  	}
   298  	headers, err := conn.headersRequest(req, s.chain, 0)
   299  	if err != nil {
   300  		t.Fatalf("failed to get block headers: %v", err)
   301  	}
   302  	expected, err := s.chain.GetHeaders(req)
   303  	if err != nil {
   304  		t.Fatalf("failed to get expected block headers: %v", err)
   305  	}
   306  	if !headersMatch(expected, headers) {
   307  		t.Fatalf("header mismatch: \nexpected %v \ngot %v", expected, headers)
   308  	}
   309  }
   310  
   311  // TestGetBlockBodies tests whether the given node can respond to
   312  // a `GetBlockBodies` request and that the response is accurate.
   313  func (s *Suite) TestGetBlockBodies(t *utesting.T) {
   314  	conn, err := s.dial()
   315  	if err != nil {
   316  		t.Fatalf("dial failed: %v", err)
   317  	}
   318  	defer conn.Close()
   319  	if err := conn.peer(s.chain, nil); err != nil {
   320  		t.Fatalf("peering failed: %v", err)
   321  	}
   322  	// create block bodies request
   323  	req := &GetBlockBodies{
   324  		RequestId: uint64(55),
   325  		GetBlockBodiesPacket: zond.GetBlockBodiesPacket{
   326  			s.chain.blocks[54].Hash(),
   327  			s.chain.blocks[75].Hash(),
   328  		},
   329  	}
   330  	if err := conn.Write(req); err != nil {
   331  		t.Fatalf("could not write to connection: %v", err)
   332  	}
   333  	// wait for block bodies response
   334  	msg := conn.waitForResponse(s.chain, timeout, req.RequestId)
   335  	resp, ok := msg.(*BlockBodies)
   336  	if !ok {
   337  		t.Fatalf("unexpected: %s", pretty.Sdump(msg))
   338  	}
   339  	bodies := resp.BlockBodiesPacket
   340  	t.Logf("received %d block bodies", len(bodies))
   341  	if len(bodies) != len(req.GetBlockBodiesPacket) {
   342  		t.Fatalf("wrong bodies in response: expected %d bodies, "+
   343  			"got %d", len(req.GetBlockBodiesPacket), len(bodies))
   344  	}
   345  }
   346  
   347  // TestBroadcast tests whether a block announcement is correctly
   348  // propagated to the node's peers.
   349  func (s *Suite) TestBroadcast(t *utesting.T) {
   350  	if err := s.sendNextBlock(); err != nil {
   351  		t.Fatalf("block broadcast failed: %v", err)
   352  	}
   353  }
   354  
   355  // TestLargeAnnounce tests the announcement mechanism with a large block.
   356  func (s *Suite) TestLargeAnnounce(t *utesting.T) {
   357  	nextBlock := len(s.chain.blocks)
   358  	blocks := []*NewBlock{
   359  		{
   360  			Block: largeBlock(),
   361  			TD:    s.fullChain.TotalDifficultyAt(nextBlock),
   362  		},
   363  		{
   364  			Block: s.fullChain.blocks[nextBlock],
   365  			TD:    largeNumber(2),
   366  		},
   367  		{
   368  			Block: largeBlock(),
   369  			TD:    largeNumber(2),
   370  		},
   371  	}
   372  
   373  	for i, blockAnnouncement := range blocks[0:3] {
   374  		t.Logf("Testing malicious announcement: %v\n", i)
   375  		conn, err := s.dial()
   376  		if err != nil {
   377  			t.Fatalf("dial failed: %v", err)
   378  		}
   379  		if err := conn.peer(s.chain, nil); err != nil {
   380  			t.Fatalf("peering failed: %v", err)
   381  		}
   382  		if err := conn.Write(blockAnnouncement); err != nil {
   383  			t.Fatalf("could not write to connection: %v", err)
   384  		}
   385  		// Invalid announcement, check that peer disconnected
   386  		switch msg := conn.readAndServe(s.chain, 8*time.Second).(type) {
   387  		case *Disconnect:
   388  		case *Error:
   389  			break
   390  		default:
   391  			t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg))
   392  		}
   393  		conn.Close()
   394  	}
   395  	// Test the last block as a valid block
   396  	if err := s.sendNextBlock(); err != nil {
   397  		t.Fatalf("failed to broadcast next block: %v", err)
   398  	}
   399  }
   400  
   401  // TestOldAnnounce tests the announcement mechanism with an old block.
   402  func (s *Suite) TestOldAnnounce(t *utesting.T) {
   403  	if err := s.oldAnnounce(); err != nil {
   404  		t.Fatal(err)
   405  	}
   406  }
   407  
   408  // TestBlockHashAnnounce sends a new block hash announcement and expects
   409  // the node to perform a `GetBlockHeaders` request.
   410  func (s *Suite) TestBlockHashAnnounce(t *utesting.T) {
   411  	if err := s.hashAnnounce(); err != nil {
   412  		t.Fatalf("block hash announcement failed: %v", err)
   413  	}
   414  }
   415  
   416  // TestMaliciousHandshake tries to send malicious data during the handshake.
   417  func (s *Suite) TestMaliciousHandshake(t *utesting.T) {
   418  	if err := s.maliciousHandshakes(t); err != nil {
   419  		t.Fatal(err)
   420  	}
   421  }
   422  
   423  // TestMaliciousStatus sends a status package with a large total difficulty.
   424  func (s *Suite) TestMaliciousStatus(t *utesting.T) {
   425  	conn, err := s.dial()
   426  	if err != nil {
   427  		t.Fatalf("dial failed: %v", err)
   428  	}
   429  	defer conn.Close()
   430  
   431  	if err := s.maliciousStatus(conn); err != nil {
   432  		t.Fatal(err)
   433  	}
   434  }
   435  
   436  // TestTransaction sends a valid transaction to the node and
   437  // checks if the transaction gets propagated.
   438  func (s *Suite) TestTransaction(t *utesting.T) {
   439  	if err := s.sendSuccessfulTxs(t); err != nil {
   440  		t.Fatal(err)
   441  	}
   442  }
   443  
   444  // TestMaliciousTx sends several invalid transactions and tests whether
   445  // the node will propagate them.
   446  func (s *Suite) TestMaliciousTx(t *utesting.T) {
   447  	if err := s.sendMaliciousTxs(t); err != nil {
   448  		t.Fatal(err)
   449  	}
   450  }
   451  
   452  // TestLargeTxRequest tests whether a node can fulfill a large GetPooledTransactions
   453  // request.
   454  func (s *Suite) TestLargeTxRequest(t *utesting.T) {
   455  	// send the next block to ensure the node is no longer syncing and
   456  	// is able to accept txs
   457  	if err := s.sendNextBlock(); err != nil {
   458  		t.Fatalf("failed to send next block: %v", err)
   459  	}
   460  	// send 2000 transactions to the node
   461  	hashMap, txs, err := generateTxs(s, 2000)
   462  	if err != nil {
   463  		t.Fatalf("failed to generate transactions: %v", err)
   464  	}
   465  	if err = sendMultipleSuccessfulTxs(t, s, txs); err != nil {
   466  		t.Fatalf("failed to send multiple txs: %v", err)
   467  	}
   468  	// set up connection to receive to ensure node is peered with the receiving connection
   469  	// before tx request is sent
   470  	conn, err := s.dial()
   471  	if err != nil {
   472  		t.Fatalf("dial failed: %v", err)
   473  	}
   474  	defer conn.Close()
   475  	if err = conn.peer(s.chain, nil); err != nil {
   476  		t.Fatalf("peering failed: %v", err)
   477  	}
   478  	// create and send pooled tx request
   479  	hashes := make([]common.Hash, 0)
   480  	for _, hash := range hashMap {
   481  		hashes = append(hashes, hash)
   482  	}
   483  	getTxReq := &GetPooledTransactions{
   484  		RequestId:                   1234,
   485  		GetPooledTransactionsPacket: hashes,
   486  	}
   487  	if err = conn.Write(getTxReq); err != nil {
   488  		t.Fatalf("could not write to conn: %v", err)
   489  	}
   490  	// check that all received transactions match those that were sent to node
   491  	switch msg := conn.waitForResponse(s.chain, timeout, getTxReq.RequestId).(type) {
   492  	case *PooledTransactions:
   493  		for _, gotTx := range msg.PooledTransactionsPacket {
   494  			if _, exists := hashMap[gotTx.Hash()]; !exists {
   495  				t.Fatalf("unexpected tx received: %v", gotTx.Hash())
   496  			}
   497  		}
   498  	default:
   499  		t.Fatalf("unexpected %s", pretty.Sdump(msg))
   500  	}
   501  }
   502  
   503  // TestNewPooledTxs tests whether a node will do a GetPooledTransactions
   504  // request upon receiving a NewPooledTransactionHashes announcement.
   505  func (s *Suite) TestNewPooledTxs(t *utesting.T) {
   506  	// send the next block to ensure the node is no longer syncing and
   507  	// is able to accept txs
   508  	if err := s.sendNextBlock(); err != nil {
   509  		t.Fatalf("failed to send next block: %v", err)
   510  	}
   511  
   512  	// generate 50 txs
   513  	_, txs, err := generateTxs(s, 50)
   514  	if err != nil {
   515  		t.Fatalf("failed to generate transactions: %v", err)
   516  	}
   517  	hashes := make([]common.Hash, len(txs))
   518  	types := make([]byte, len(txs))
   519  	sizes := make([]uint32, len(txs))
   520  	for i, tx := range txs {
   521  		hashes[i] = tx.Hash()
   522  		types[i] = tx.Type()
   523  		sizes[i] = uint32(tx.Size())
   524  	}
   525  
   526  	// send announcement
   527  	conn, err := s.dial()
   528  	if err != nil {
   529  		t.Fatalf("dial failed: %v", err)
   530  	}
   531  	defer conn.Close()
   532  	if err = conn.peer(s.chain, nil); err != nil {
   533  		t.Fatalf("peering failed: %v", err)
   534  	}
   535  
   536  	var ann Message = NewPooledTransactionHashes{Types: types, Sizes: sizes, Hashes: hashes}
   537  	if conn.negotiatedProtoVersion < zond.ETH68 {
   538  		ann = NewPooledTransactionHashes66(hashes)
   539  	}
   540  	err = conn.Write(ann)
   541  	if err != nil {
   542  		t.Fatalf("failed to write to connection: %v", err)
   543  	}
   544  
   545  	// wait for GetPooledTxs request
   546  	for {
   547  		msg := conn.readAndServe(s.chain, timeout)
   548  		switch msg := msg.(type) {
   549  		case *GetPooledTransactions:
   550  			if len(msg.GetPooledTransactionsPacket) != len(hashes) {
   551  				t.Fatalf("unexpected number of txs requested: wanted %d, got %d", len(hashes), len(msg.GetPooledTransactionsPacket))
   552  			}
   553  			return
   554  
   555  		// ignore propagated txs from previous tests
   556  		case *NewPooledTransactionHashes66:
   557  			continue
   558  		case *NewPooledTransactionHashes:
   559  			continue
   560  		case *Transactions:
   561  			continue
   562  
   563  		// ignore block announcements from previous tests
   564  		case *NewBlockHashes:
   565  			continue
   566  		case *NewBlock:
   567  			continue
   568  		default:
   569  			t.Fatalf("unexpected %s", pretty.Sdump(msg))
   570  		}
   571  	}
   572  }