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