cmd/devp2p: add eth66 test suite (#22363)
Co-authored-by: Martin Holst Swende <martin@swende.se>
This commit is contained in:
		
							parent
							
								
									bbfb1e4008
								
							
						
					
					
						commit
						de9465f991
					
				| @ -100,7 +100,17 @@ Then, run the following command, replacing `<enode>` with the enode of the geth | |||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again. | Repeat the above process (re-initialising the node) in order to run the Eth Protocol test suite again. | ||||||
|   | 
 | ||||||
|  | #### Eth66 Test Suite | ||||||
|  | 
 | ||||||
|  | The Eth66 test suite is also a conformance test suite for the eth 66 protocol version specifically.  | ||||||
|  | To run the eth66 protocol test suite, initialize a geth node as described above and run the following command, | ||||||
|  | replacing `<enode>` with the enode of the geth node: | ||||||
|  | 
 | ||||||
|  |  ``` | ||||||
|  |  devp2p rlpx eth66-test <enode> cmd/devp2p/internal/ethtest/testdata/chain.rlp cmd/devp2p/internal/ethtest/testdata/genesis.json | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| [eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md | [eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md | ||||||
| [dns-tutorial]: https://geth.ethereum.org/docs/developers/dns-discovery-setup | [dns-tutorial]: https://geth.ethereum.org/docs/developers/dns-discovery-setup | ||||||
| [discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md | [discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md | ||||||
|  | |||||||
							
								
								
									
										382
									
								
								cmd/devp2p/internal/ethtest/eth66_suite.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								cmd/devp2p/internal/ethtest/eth66_suite.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,382 @@ | |||||||
|  | // Copyright 2021 The go-ethereum Authors
 | ||||||
|  | // This file is part of the go-ethereum library.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU Lesser General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU Lesser General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU Lesser General Public License
 | ||||||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package ethtest | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
|  | 	"github.com/ethereum/go-ethereum/crypto" | ||||||
|  | 	"github.com/ethereum/go-ethereum/eth/protocols/eth" | ||||||
|  | 	"github.com/ethereum/go-ethereum/internal/utesting" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // TestStatus_66 attempts to connect to the given node and exchange
 | ||||||
|  | // a status message with it on the eth66 protocol, and then check to
 | ||||||
|  | // make sure the chain head is correct.
 | ||||||
|  | func (s *Suite) TestStatus_66(t *utesting.T) { | ||||||
|  | 	conn := s.dial66(t) | ||||||
|  | 	// get protoHandshake
 | ||||||
|  | 	conn.handshake(t) | ||||||
|  | 	// get status
 | ||||||
|  | 	switch msg := conn.statusExchange66(t, s.chain).(type) { | ||||||
|  | 	case *Status: | ||||||
|  | 		status := *msg | ||||||
|  | 		if status.ProtocolVersion != uint32(66) { | ||||||
|  | 			t.Fatalf("mismatch in version: wanted 66, got %d", status.ProtocolVersion) | ||||||
|  | 		} | ||||||
|  | 		t.Logf("got status message: %s", pretty.Sdump(msg)) | ||||||
|  | 	default: | ||||||
|  | 		t.Fatalf("unexpected: %s", pretty.Sdump(msg)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestGetBlockHeaders_66 tests whether the given node can respond to
 | ||||||
|  | // an eth66 `GetBlockHeaders` request and that the response is accurate.
 | ||||||
|  | func (s *Suite) TestGetBlockHeaders_66(t *utesting.T) { | ||||||
|  | 	conn := s.setupConnection66(t) | ||||||
|  | 	// get block headers
 | ||||||
|  | 	req := ð.GetBlockHeadersPacket66{ | ||||||
|  | 		RequestId: 3, | ||||||
|  | 		GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 			Origin: eth.HashOrNumber{ | ||||||
|  | 				Hash: s.chain.blocks[1].Hash(), | ||||||
|  | 			}, | ||||||
|  | 			Amount:  2, | ||||||
|  | 			Skip:    1, | ||||||
|  | 			Reverse: false, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	// write message
 | ||||||
|  | 	headers := s.getBlockHeaders66(t, conn, req, req.RequestId) | ||||||
|  | 	// check for correct headers
 | ||||||
|  | 	headersMatch(t, s.chain, headers) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestSimultaneousRequests_66 sends two simultaneous `GetBlockHeader` requests
 | ||||||
|  | // with different request IDs and checks to make sure the node responds with the correct
 | ||||||
|  | // headers per request.
 | ||||||
|  | func (s *Suite) TestSimultaneousRequests_66(t *utesting.T) { | ||||||
|  | 	// create two connections
 | ||||||
|  | 	conn1, conn2 := s.setupConnection66(t), s.setupConnection66(t) | ||||||
|  | 	// create two requests
 | ||||||
|  | 	req1 := ð.GetBlockHeadersPacket66{ | ||||||
|  | 		RequestId: 111, | ||||||
|  | 		GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 			Origin: eth.HashOrNumber{ | ||||||
|  | 				Hash: s.chain.blocks[1].Hash(), | ||||||
|  | 			}, | ||||||
|  | 			Amount:  2, | ||||||
|  | 			Skip:    1, | ||||||
|  | 			Reverse: false, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	req2 := ð.GetBlockHeadersPacket66{ | ||||||
|  | 		RequestId: 222, | ||||||
|  | 		GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 			Origin: eth.HashOrNumber{ | ||||||
|  | 				Hash: s.chain.blocks[1].Hash(), | ||||||
|  | 			}, | ||||||
|  | 			Amount:  4, | ||||||
|  | 			Skip:    1, | ||||||
|  | 			Reverse: false, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	// wait for headers for first request
 | ||||||
|  | 	headerChan := make(chan BlockHeaders, 1) | ||||||
|  | 	go func(headers chan BlockHeaders) { | ||||||
|  | 		headers <- s.getBlockHeaders66(t, conn1, req1, req1.RequestId) | ||||||
|  | 	}(headerChan) | ||||||
|  | 	// check headers of second request
 | ||||||
|  | 	headersMatch(t, s.chain, s.getBlockHeaders66(t, conn2, req2, req2.RequestId)) | ||||||
|  | 	// check headers of first request
 | ||||||
|  | 	headersMatch(t, s.chain, <-headerChan) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestBroadcast_66 tests whether a block announcement is correctly
 | ||||||
|  | // propagated to the given node's peer(s) on the eth66 protocol.
 | ||||||
|  | func (s *Suite) TestBroadcast_66(t *utesting.T) { | ||||||
|  | 	sendConn, receiveConn := s.setupConnection66(t), s.setupConnection66(t) | ||||||
|  | 	nextBlock := len(s.chain.blocks) | ||||||
|  | 	blockAnnouncement := &NewBlock{ | ||||||
|  | 		Block: s.fullChain.blocks[nextBlock], | ||||||
|  | 		TD:    s.fullChain.TD(nextBlock + 1), | ||||||
|  | 	} | ||||||
|  | 	s.testAnnounce66(t, sendConn, receiveConn, blockAnnouncement) | ||||||
|  | 	// update test suite chain
 | ||||||
|  | 	s.chain.blocks = append(s.chain.blocks, s.fullChain.blocks[nextBlock]) | ||||||
|  | 	// wait for client to update its chain
 | ||||||
|  | 	if err := receiveConn.waitForBlock66(s.chain.Head()); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestGetBlockBodies_66 tests whether the given node can respond to
 | ||||||
|  | // a `GetBlockBodies` request and that the response is accurate over
 | ||||||
|  | // the eth66 protocol.
 | ||||||
|  | func (s *Suite) TestGetBlockBodies_66(t *utesting.T) { | ||||||
|  | 	conn := s.setupConnection66(t) | ||||||
|  | 	// create block bodies request
 | ||||||
|  | 	id := uint64(55) | ||||||
|  | 	req := ð.GetBlockBodiesPacket66{ | ||||||
|  | 		RequestId: id, | ||||||
|  | 		GetBlockBodiesPacket: eth.GetBlockBodiesPacket{ | ||||||
|  | 			s.chain.blocks[54].Hash(), | ||||||
|  | 			s.chain.blocks[75].Hash(), | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	if err := conn.write66(req, GetBlockBodies{}.Code()); err != nil { | ||||||
|  | 		t.Fatalf("could not write to connection: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	reqID, msg := conn.readAndServe66(s.chain, timeout) | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case BlockBodies: | ||||||
|  | 		if reqID != req.RequestId { | ||||||
|  | 			t.Fatalf("request ID mismatch: wanted %d, got %d", req.RequestId, reqID) | ||||||
|  | 		} | ||||||
|  | 		t.Logf("received %d block bodies", len(msg)) | ||||||
|  | 	default: | ||||||
|  | 		t.Fatalf("unexpected: %s", pretty.Sdump(msg)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestLargeAnnounce_66 tests the announcement mechanism with a large block.
 | ||||||
|  | func (s *Suite) TestLargeAnnounce_66(t *utesting.T) { | ||||||
|  | 	nextBlock := len(s.chain.blocks) | ||||||
|  | 	blocks := []*NewBlock{ | ||||||
|  | 		{ | ||||||
|  | 			Block: largeBlock(), | ||||||
|  | 			TD:    s.fullChain.TD(nextBlock + 1), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Block: s.fullChain.blocks[nextBlock], | ||||||
|  | 			TD:    largeNumber(2), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Block: largeBlock(), | ||||||
|  | 			TD:    largeNumber(2), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Block: s.fullChain.blocks[nextBlock], | ||||||
|  | 			TD:    s.fullChain.TD(nextBlock + 1), | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for i, blockAnnouncement := range blocks[0:3] { | ||||||
|  | 		t.Logf("Testing malicious announcement: %v\n", i) | ||||||
|  | 		sendConn := s.setupConnection66(t) | ||||||
|  | 		if err := sendConn.Write(blockAnnouncement); err != nil { | ||||||
|  | 			t.Fatalf("could not write to connection: %v", err) | ||||||
|  | 		} | ||||||
|  | 		// Invalid announcement, check that peer disconnected
 | ||||||
|  | 		switch msg := sendConn.ReadAndServe(s.chain, timeout).(type) { | ||||||
|  | 		case *Disconnect: | ||||||
|  | 		case *Error: | ||||||
|  | 			break | ||||||
|  | 		default: | ||||||
|  | 			t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	// Test the last block as a valid block
 | ||||||
|  | 	sendConn := s.setupConnection66(t) | ||||||
|  | 	receiveConn := s.setupConnection66(t) | ||||||
|  | 	s.testAnnounce66(t, sendConn, receiveConn, blocks[3]) | ||||||
|  | 	// update test suite chain
 | ||||||
|  | 	s.chain.blocks = append(s.chain.blocks, s.fullChain.blocks[nextBlock]) | ||||||
|  | 	// wait for client to update its chain
 | ||||||
|  | 	if err := receiveConn.waitForBlock66(s.fullChain.blocks[nextBlock]); err != nil { | ||||||
|  | 		t.Fatal(err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestMaliciousHandshake_66 tries to send malicious data during the handshake.
 | ||||||
|  | func (s *Suite) TestMaliciousHandshake_66(t *utesting.T) { | ||||||
|  | 	conn := s.dial66(t) | ||||||
|  | 	// write hello to client
 | ||||||
|  | 	pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:] | ||||||
|  | 	handshakes := []*Hello{ | ||||||
|  | 		{ | ||||||
|  | 			Version: 5, | ||||||
|  | 			Caps: []p2p.Cap{ | ||||||
|  | 				{Name: largeString(2), Version: 66}, | ||||||
|  | 			}, | ||||||
|  | 			ID: pub0, | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Version: 5, | ||||||
|  | 			Caps: []p2p.Cap{ | ||||||
|  | 				{Name: "eth", Version: 64}, | ||||||
|  | 				{Name: "eth", Version: 65}, | ||||||
|  | 				{Name: "eth", Version: 66}, | ||||||
|  | 			}, | ||||||
|  | 			ID: append(pub0, byte(0)), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Version: 5, | ||||||
|  | 			Caps: []p2p.Cap{ | ||||||
|  | 				{Name: "eth", Version: 64}, | ||||||
|  | 				{Name: "eth", Version: 65}, | ||||||
|  | 				{Name: "eth", Version: 66}, | ||||||
|  | 			}, | ||||||
|  | 			ID: append(pub0, pub0...), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Version: 5, | ||||||
|  | 			Caps: []p2p.Cap{ | ||||||
|  | 				{Name: "eth", Version: 64}, | ||||||
|  | 				{Name: "eth", Version: 65}, | ||||||
|  | 				{Name: "eth", Version: 66}, | ||||||
|  | 			}, | ||||||
|  | 			ID: largeBuffer(2), | ||||||
|  | 		}, | ||||||
|  | 		{ | ||||||
|  | 			Version: 5, | ||||||
|  | 			Caps: []p2p.Cap{ | ||||||
|  | 				{Name: largeString(2), Version: 66}, | ||||||
|  | 			}, | ||||||
|  | 			ID: largeBuffer(2), | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	for i, handshake := range handshakes { | ||||||
|  | 		t.Logf("Testing malicious handshake %v\n", i) | ||||||
|  | 		// Init the handshake
 | ||||||
|  | 		if err := conn.Write(handshake); err != nil { | ||||||
|  | 			t.Fatalf("could not write to connection: %v", err) | ||||||
|  | 		} | ||||||
|  | 		// check that the peer disconnected
 | ||||||
|  | 		timeout := 20 * time.Second | ||||||
|  | 		// Discard one hello
 | ||||||
|  | 		for i := 0; i < 2; i++ { | ||||||
|  | 			switch msg := conn.ReadAndServe(s.chain, timeout).(type) { | ||||||
|  | 			case *Disconnect: | ||||||
|  | 			case *Error: | ||||||
|  | 			case *Hello: | ||||||
|  | 				// Hello's are sent concurrently, so ignore them
 | ||||||
|  | 				continue | ||||||
|  | 			default: | ||||||
|  | 				t.Fatalf("unexpected: %s", pretty.Sdump(msg)) | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		// Dial for the next round
 | ||||||
|  | 		conn = s.dial66(t) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestMaliciousStatus_66 sends a status package with a large total difficulty.
 | ||||||
|  | func (s *Suite) TestMaliciousStatus_66(t *utesting.T) { | ||||||
|  | 	conn := s.dial66(t) | ||||||
|  | 	// get protoHandshake
 | ||||||
|  | 	conn.handshake(t) | ||||||
|  | 	status := &Status{ | ||||||
|  | 		ProtocolVersion: uint32(66), | ||||||
|  | 		NetworkID:       s.chain.chainConfig.ChainID.Uint64(), | ||||||
|  | 		TD:              largeNumber(2), | ||||||
|  | 		Head:            s.chain.blocks[s.chain.Len()-1].Hash(), | ||||||
|  | 		Genesis:         s.chain.blocks[0].Hash(), | ||||||
|  | 		ForkID:          s.chain.ForkID(), | ||||||
|  | 	} | ||||||
|  | 	// get status
 | ||||||
|  | 	switch msg := conn.statusExchange(t, s.chain, status).(type) { | ||||||
|  | 	case *Status: | ||||||
|  | 		t.Logf("%+v\n", msg) | ||||||
|  | 	default: | ||||||
|  | 		t.Fatalf("expected status, got: %#v ", msg) | ||||||
|  | 	} | ||||||
|  | 	// wait for disconnect
 | ||||||
|  | 	switch msg := conn.ReadAndServe(s.chain, timeout).(type) { | ||||||
|  | 	case *Disconnect: | ||||||
|  | 	case *Error: | ||||||
|  | 		return | ||||||
|  | 	default: | ||||||
|  | 		t.Fatalf("expected disconnect, got: %s", pretty.Sdump(msg)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) TestTransaction_66(t *utesting.T) { | ||||||
|  | 	tests := []*types.Transaction{ | ||||||
|  | 		getNextTxFromChain(t, s), | ||||||
|  | 		unknownTx(t, s), | ||||||
|  | 	} | ||||||
|  | 	for i, tx := range tests { | ||||||
|  | 		t.Logf("Testing tx propagation: %v\n", i) | ||||||
|  | 		sendSuccessfulTx66(t, s, tx) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) TestMaliciousTx_66(t *utesting.T) { | ||||||
|  | 	tests := []*types.Transaction{ | ||||||
|  | 		getOldTxFromChain(t, s), | ||||||
|  | 		invalidNonceTx(t, s), | ||||||
|  | 		hugeAmount(t, s), | ||||||
|  | 		hugeGasPrice(t, s), | ||||||
|  | 		hugeData(t, s), | ||||||
|  | 	} | ||||||
|  | 	for i, tx := range tests { | ||||||
|  | 		t.Logf("Testing malicious tx propagation: %v\n", i) | ||||||
|  | 		sendFailingTx66(t, s, tx) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestZeroRequestID_66 checks that a request ID of zero is still handled
 | ||||||
|  | // by the node.
 | ||||||
|  | func (s *Suite) TestZeroRequestID_66(t *utesting.T) { | ||||||
|  | 	conn := s.setupConnection66(t) | ||||||
|  | 	req := ð.GetBlockHeadersPacket66{ | ||||||
|  | 		RequestId: 0, | ||||||
|  | 		GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 			Origin: eth.HashOrNumber{ | ||||||
|  | 				Number: 0, | ||||||
|  | 			}, | ||||||
|  | 			Amount: 2, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	headersMatch(t, s.chain, s.getBlockHeaders66(t, conn, req, req.RequestId)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TestSameRequestID_66 sends two requests with the same request ID
 | ||||||
|  | // concurrently to a single node.
 | ||||||
|  | func (s *Suite) TestSameRequestID_66(t *utesting.T) { | ||||||
|  | 	conn := s.setupConnection66(t) | ||||||
|  | 	// create two separate requests with same ID
 | ||||||
|  | 	reqID := uint64(1234) | ||||||
|  | 	req1 := ð.GetBlockHeadersPacket66{ | ||||||
|  | 		RequestId: reqID, | ||||||
|  | 		GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 			Origin: eth.HashOrNumber{ | ||||||
|  | 				Number: 0, | ||||||
|  | 			}, | ||||||
|  | 			Amount: 2, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	req2 := ð.GetBlockHeadersPacket66{ | ||||||
|  | 		RequestId: reqID, | ||||||
|  | 		GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 			Origin: eth.HashOrNumber{ | ||||||
|  | 				Number: 33, | ||||||
|  | 			}, | ||||||
|  | 			Amount: 2, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	// send requests concurrently
 | ||||||
|  | 	go func() { | ||||||
|  | 		headersMatch(t, s.chain, s.getBlockHeaders66(t, conn, req2, reqID)) | ||||||
|  | 	}() | ||||||
|  | 	// check response from first request
 | ||||||
|  | 	headersMatch(t, s.chain, s.getBlockHeaders66(t, conn, req1, reqID)) | ||||||
|  | } | ||||||
							
								
								
									
										270
									
								
								cmd/devp2p/internal/ethtest/eth66_suiteHelpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								cmd/devp2p/internal/ethtest/eth66_suiteHelpers.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,270 @@ | |||||||
|  | // Copyright 2021 The go-ethereum Authors
 | ||||||
|  | // This file is part of the go-ethereum library.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is free software: you can redistribute it and/or modify
 | ||||||
|  | // it under the terms of the GNU Lesser General Public License as published by
 | ||||||
|  | // the Free Software Foundation, either version 3 of the License, or
 | ||||||
|  | // (at your option) any later version.
 | ||||||
|  | //
 | ||||||
|  | // The go-ethereum library is distributed in the hope that it will be useful,
 | ||||||
|  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||||
|  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 | ||||||
|  | // GNU Lesser General Public License for more details.
 | ||||||
|  | //
 | ||||||
|  | // You should have received a copy of the GNU Lesser General Public License
 | ||||||
|  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
 | ||||||
|  | 
 | ||||||
|  | package ethtest | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/ethereum/go-ethereum/core/types" | ||||||
|  | 	"github.com/ethereum/go-ethereum/eth/protocols/eth" | ||||||
|  | 	"github.com/ethereum/go-ethereum/internal/utesting" | ||||||
|  | 	"github.com/ethereum/go-ethereum/p2p" | ||||||
|  | 	"github.com/ethereum/go-ethereum/rlp" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func (c *Conn) statusExchange66(t *utesting.T, chain *Chain) Message { | ||||||
|  | 	status := &Status{ | ||||||
|  | 		ProtocolVersion: uint32(66), | ||||||
|  | 		NetworkID:       chain.chainConfig.ChainID.Uint64(), | ||||||
|  | 		TD:              chain.TD(chain.Len()), | ||||||
|  | 		Head:            chain.blocks[chain.Len()-1].Hash(), | ||||||
|  | 		Genesis:         chain.blocks[0].Hash(), | ||||||
|  | 		ForkID:          chain.ForkID(), | ||||||
|  | 	} | ||||||
|  | 	return c.statusExchange(t, chain, status) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) dial66(t *utesting.T) *Conn { | ||||||
|  | 	conn, err := s.dial() | ||||||
|  | 	if err != nil { | ||||||
|  | 		t.Fatalf("could not dial: %v", err) | ||||||
|  | 	} | ||||||
|  | 	conn.caps = append(conn.caps, p2p.Cap{Name: "eth", Version: 66}) | ||||||
|  | 	return conn | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Conn) write66(req eth.Packet, code int) error { | ||||||
|  | 	payload, err := rlp.EncodeToBytes(req) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	_, err = c.Conn.Write(uint64(code), payload) | ||||||
|  | 	return err | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (c *Conn) read66() (uint64, Message) { | ||||||
|  | 	code, rawData, _, err := c.Conn.Read() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return 0, errorf("could not read from connection: %v", err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	var msg Message | ||||||
|  | 
 | ||||||
|  | 	switch int(code) { | ||||||
|  | 	case (Hello{}).Code(): | ||||||
|  | 		msg = new(Hello) | ||||||
|  | 
 | ||||||
|  | 	case (Ping{}).Code(): | ||||||
|  | 		msg = new(Ping) | ||||||
|  | 	case (Pong{}).Code(): | ||||||
|  | 		msg = new(Pong) | ||||||
|  | 	case (Disconnect{}).Code(): | ||||||
|  | 		msg = new(Disconnect) | ||||||
|  | 	case (Status{}).Code(): | ||||||
|  | 		msg = new(Status) | ||||||
|  | 	case (GetBlockHeaders{}).Code(): | ||||||
|  | 		ethMsg := new(eth.GetBlockHeadersPacket66) | ||||||
|  | 		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { | ||||||
|  | 			return 0, errorf("could not rlp decode message: %v", err) | ||||||
|  | 		} | ||||||
|  | 		return ethMsg.RequestId, GetBlockHeaders(*ethMsg.GetBlockHeadersPacket) | ||||||
|  | 	case (BlockHeaders{}).Code(): | ||||||
|  | 		ethMsg := new(eth.BlockHeadersPacket66) | ||||||
|  | 		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { | ||||||
|  | 			return 0, errorf("could not rlp decode message: %v", err) | ||||||
|  | 		} | ||||||
|  | 		return ethMsg.RequestId, BlockHeaders(ethMsg.BlockHeadersPacket) | ||||||
|  | 	case (GetBlockBodies{}).Code(): | ||||||
|  | 		ethMsg := new(eth.GetBlockBodiesPacket66) | ||||||
|  | 		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { | ||||||
|  | 			return 0, errorf("could not rlp decode message: %v", err) | ||||||
|  | 		} | ||||||
|  | 		return ethMsg.RequestId, GetBlockBodies(ethMsg.GetBlockBodiesPacket) | ||||||
|  | 	case (BlockBodies{}).Code(): | ||||||
|  | 		ethMsg := new(eth.BlockBodiesPacket66) | ||||||
|  | 		if err := rlp.DecodeBytes(rawData, ethMsg); err != nil { | ||||||
|  | 			return 0, errorf("could not rlp decode message: %v", err) | ||||||
|  | 		} | ||||||
|  | 		return ethMsg.RequestId, BlockBodies(ethMsg.BlockBodiesPacket) | ||||||
|  | 	case (NewBlock{}).Code(): | ||||||
|  | 		msg = new(NewBlock) | ||||||
|  | 	case (NewBlockHashes{}).Code(): | ||||||
|  | 		msg = new(NewBlockHashes) | ||||||
|  | 	case (Transactions{}).Code(): | ||||||
|  | 		msg = new(Transactions) | ||||||
|  | 	case (NewPooledTransactionHashes{}).Code(): | ||||||
|  | 		msg = new(NewPooledTransactionHashes) | ||||||
|  | 	default: | ||||||
|  | 		msg = errorf("invalid message code: %d", code) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if msg != nil { | ||||||
|  | 		if err := rlp.DecodeBytes(rawData, msg); err != nil { | ||||||
|  | 			return 0, errorf("could not rlp decode message: %v", err) | ||||||
|  | 		} | ||||||
|  | 		return 0, msg | ||||||
|  | 	} | ||||||
|  | 	return 0, errorf("invalid message: %s", string(rawData)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // ReadAndServe serves GetBlockHeaders requests while waiting
 | ||||||
|  | // on another message from the node.
 | ||||||
|  | func (c *Conn) readAndServe66(chain *Chain, timeout time.Duration) (uint64, Message) { | ||||||
|  | 	start := time.Now() | ||||||
|  | 	for time.Since(start) < timeout { | ||||||
|  | 		timeout := time.Now().Add(10 * time.Second) | ||||||
|  | 		c.SetReadDeadline(timeout) | ||||||
|  | 
 | ||||||
|  | 		reqID, msg := c.read66() | ||||||
|  | 
 | ||||||
|  | 		switch msg := msg.(type) { | ||||||
|  | 		case *Ping: | ||||||
|  | 			c.Write(&Pong{}) | ||||||
|  | 		case *GetBlockHeaders: | ||||||
|  | 			headers, err := chain.GetHeaders(*msg) | ||||||
|  | 			if err != nil { | ||||||
|  | 				return 0, errorf("could not get headers for inbound header request: %v", err) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if err := c.Write(headers); err != nil { | ||||||
|  | 				return 0, errorf("could not write to connection: %v", err) | ||||||
|  | 			} | ||||||
|  | 		default: | ||||||
|  | 			return reqID, msg | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return 0, errorf("no message received within %v", timeout) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) setupConnection66(t *utesting.T) *Conn { | ||||||
|  | 	// create conn
 | ||||||
|  | 	sendConn := s.dial66(t) | ||||||
|  | 	sendConn.handshake(t) | ||||||
|  | 	sendConn.statusExchange66(t, s.chain) | ||||||
|  | 	return sendConn | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) testAnnounce66(t *utesting.T, sendConn, receiveConn *Conn, blockAnnouncement *NewBlock) { | ||||||
|  | 	// Announce the block.
 | ||||||
|  | 	if err := sendConn.Write(blockAnnouncement); err != nil { | ||||||
|  | 		t.Fatalf("could not write to connection: %v", err) | ||||||
|  | 	} | ||||||
|  | 	s.waitAnnounce66(t, receiveConn, blockAnnouncement) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) waitAnnounce66(t *utesting.T, conn *Conn, blockAnnouncement *NewBlock) { | ||||||
|  | 	timeout := 20 * time.Second | ||||||
|  | 	_, msg := conn.readAndServe66(s.chain, timeout) | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case *NewBlock: | ||||||
|  | 		t.Logf("received NewBlock message: %s", pretty.Sdump(msg.Block)) | ||||||
|  | 		assert.Equal(t, | ||||||
|  | 			blockAnnouncement.Block.Header(), msg.Block.Header(), | ||||||
|  | 			"wrong block header in announcement", | ||||||
|  | 		) | ||||||
|  | 		assert.Equal(t, | ||||||
|  | 			blockAnnouncement.TD, msg.TD, | ||||||
|  | 			"wrong TD in announcement", | ||||||
|  | 		) | ||||||
|  | 	case *NewBlockHashes: | ||||||
|  | 		blockHashes := *msg | ||||||
|  | 		t.Logf("received NewBlockHashes message: %s", pretty.Sdump(blockHashes)) | ||||||
|  | 		assert.Equal(t, blockAnnouncement.Block.Hash(), blockHashes[0].Hash, | ||||||
|  | 			"wrong block hash in announcement", | ||||||
|  | 		) | ||||||
|  | 	default: | ||||||
|  | 		t.Fatalf("unexpected: %s", pretty.Sdump(msg)) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // waitForBlock66 waits for confirmation from the client that it has
 | ||||||
|  | // imported the given block.
 | ||||||
|  | func (c *Conn) waitForBlock66(block *types.Block) error { | ||||||
|  | 	defer c.SetReadDeadline(time.Time{}) | ||||||
|  | 
 | ||||||
|  | 	timeout := time.Now().Add(20 * time.Second) | ||||||
|  | 	c.SetReadDeadline(timeout) | ||||||
|  | 	for { | ||||||
|  | 		req := eth.GetBlockHeadersPacket66{ | ||||||
|  | 			RequestId: 54, | ||||||
|  | 			GetBlockHeadersPacket: ð.GetBlockHeadersPacket{ | ||||||
|  | 				Origin: eth.HashOrNumber{ | ||||||
|  | 					Hash: block.Hash(), | ||||||
|  | 				}, | ||||||
|  | 				Amount: 1, | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		if err := c.write66(req, GetBlockHeaders{}.Code()); err != nil { | ||||||
|  | 			return err | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		reqID, msg := c.read66() | ||||||
|  | 		// check message
 | ||||||
|  | 		switch msg := msg.(type) { | ||||||
|  | 		case BlockHeaders: | ||||||
|  | 			// check request ID
 | ||||||
|  | 			if reqID != req.RequestId { | ||||||
|  | 				return fmt.Errorf("request ID mismatch: wanted %d, got %d", req.RequestId, reqID) | ||||||
|  | 			} | ||||||
|  | 			if len(msg) > 0 { | ||||||
|  | 				return nil | ||||||
|  | 			} | ||||||
|  | 			time.Sleep(100 * time.Millisecond) | ||||||
|  | 		default: | ||||||
|  | 			return fmt.Errorf("invalid message: %s", pretty.Sdump(msg)) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sendSuccessfulTx66(t *utesting.T, s *Suite, tx *types.Transaction) { | ||||||
|  | 	sendConn := s.setupConnection66(t) | ||||||
|  | 	sendSuccessfulTxWithConn(t, s, tx, sendConn) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sendFailingTx66(t *utesting.T, s *Suite, tx *types.Transaction) { | ||||||
|  | 	sendConn, recvConn := s.setupConnection66(t), s.setupConnection66(t) | ||||||
|  | 	sendFailingTxWithConns(t, s, tx, sendConn, recvConn) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (s *Suite) getBlockHeaders66(t *utesting.T, conn *Conn, req eth.Packet, expectedID uint64) BlockHeaders { | ||||||
|  | 	if err := conn.write66(req, GetBlockHeaders{}.Code()); err != nil { | ||||||
|  | 		t.Fatalf("could not write to connection: %v", err) | ||||||
|  | 	} | ||||||
|  | 	// check block headers response
 | ||||||
|  | 	reqID, msg := conn.readAndServe66(s.chain, timeout) | ||||||
|  | 
 | ||||||
|  | 	switch msg := msg.(type) { | ||||||
|  | 	case BlockHeaders: | ||||||
|  | 		if reqID != expectedID { | ||||||
|  | 			t.Fatalf("request ID mismatch: wanted %d, got %d", expectedID, reqID) | ||||||
|  | 		} | ||||||
|  | 		return msg | ||||||
|  | 	default: | ||||||
|  | 		t.Fatalf("unexpected: %s", pretty.Sdump(msg)) | ||||||
|  | 		return nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func headersMatch(t *utesting.T, chain *Chain, headers BlockHeaders) { | ||||||
|  | 	for _, header := range headers { | ||||||
|  | 		num := header.Number.Uint64() | ||||||
|  | 		t.Logf("received header (%d): %s", num, pretty.Sdump(header.Hash())) | ||||||
|  | 		assert.Equal(t, chain.blocks[int(num)].Header(), header) | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -53,29 +53,47 @@ type Suite struct { | |||||||
| // NewSuite creates and returns a new eth-test suite that can
 | // NewSuite creates and returns a new eth-test suite that can
 | ||||||
| // be used to test the given node against the given blockchain
 | // be used to test the given node against the given blockchain
 | ||||||
| // data.
 | // data.
 | ||||||
| func NewSuite(dest *enode.Node, chainfile string, genesisfile string) *Suite { | func NewSuite(dest *enode.Node, chainfile string, genesisfile string) (*Suite, error) { | ||||||
| 	chain, err := loadChain(chainfile, genesisfile) | 	chain, err := loadChain(chainfile, genesisfile) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(err) | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return &Suite{ | 	return &Suite{ | ||||||
| 		Dest:      dest, | 		Dest:      dest, | ||||||
| 		chain:     chain.Shorten(1000), | 		chain:     chain.Shorten(1000), | ||||||
| 		fullChain: chain, | 		fullChain: chain, | ||||||
| 	} | 	}, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (s *Suite) AllTests() []utesting.Test { | func (s *Suite) EthTests() []utesting.Test { | ||||||
| 	return []utesting.Test{ | 	return []utesting.Test{ | ||||||
|  | 		// status
 | ||||||
| 		{Name: "Status", Fn: s.TestStatus}, | 		{Name: "Status", Fn: s.TestStatus}, | ||||||
|  | 		{Name: "Status_66", Fn: s.TestStatus_66}, | ||||||
|  | 		// get block headers
 | ||||||
| 		{Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders}, | 		{Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders}, | ||||||
| 		{Name: "Broadcast", Fn: s.TestBroadcast}, | 		{Name: "GetBlockHeaders_66", Fn: s.TestGetBlockHeaders_66}, | ||||||
|  | 		{Name: "TestSimultaneousRequests_66", Fn: s.TestSimultaneousRequests_66}, | ||||||
|  | 		{Name: "TestSameRequestID_66", Fn: s.TestSameRequestID_66}, | ||||||
|  | 		{Name: "TestZeroRequestID_66", Fn: s.TestZeroRequestID_66}, | ||||||
|  | 		// get block bodies
 | ||||||
| 		{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies}, | 		{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies}, | ||||||
|  | 		{Name: "GetBlockBodies_66", Fn: s.TestGetBlockBodies_66}, | ||||||
|  | 		// broadcast
 | ||||||
|  | 		{Name: "Broadcast", Fn: s.TestBroadcast}, | ||||||
|  | 		{Name: "Broadcast_66", Fn: s.TestBroadcast_66}, | ||||||
| 		{Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce}, | 		{Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce}, | ||||||
|  | 		{Name: "TestLargeAnnounce_66", Fn: s.TestLargeAnnounce_66}, | ||||||
|  | 		// malicious handshakes + status
 | ||||||
| 		{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake}, | 		{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake}, | ||||||
| 		{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus}, | 		{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus}, | ||||||
|  | 		{Name: "TestMaliciousHandshake_66", Fn: s.TestMaliciousHandshake_66}, | ||||||
|  | 		{Name: "TestMaliciousStatus_66", Fn: s.TestMaliciousStatus}, | ||||||
|  | 		// test transactions
 | ||||||
| 		{Name: "TestTransactions", Fn: s.TestTransaction}, | 		{Name: "TestTransactions", Fn: s.TestTransaction}, | ||||||
|  | 		{Name: "TestTransactions_66", Fn: s.TestTransaction_66}, | ||||||
| 		{Name: "TestMaliciousTransactions", Fn: s.TestMaliciousTx}, | 		{Name: "TestMaliciousTransactions", Fn: s.TestMaliciousTx}, | ||||||
|  | 		{Name: "TestMaliciousTransactions_66", Fn: s.TestMaliciousTx_66}, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -161,7 +179,7 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) { | |||||||
| 		headers := *msg | 		headers := *msg | ||||||
| 		for _, header := range headers { | 		for _, header := range headers { | ||||||
| 			num := header.Number.Uint64() | 			num := header.Number.Uint64() | ||||||
| 			t.Logf("received header (%d): %s", num, pretty.Sdump(header)) | 			t.Logf("received header (%d): %s", num, pretty.Sdump(header.Hash())) | ||||||
| 			assert.Equal(t, s.chain.blocks[int(num)].Header(), header) | 			assert.Equal(t, s.chain.blocks[int(num)].Header(), header) | ||||||
| 		} | 		} | ||||||
| 	default: | 	default: | ||||||
| @ -386,20 +404,23 @@ func (s *Suite) setupConnection(t *utesting.T) *Conn { | |||||||
| // returning the created Conn if successful.
 | // returning the created Conn if successful.
 | ||||||
| func (s *Suite) dial() (*Conn, error) { | func (s *Suite) dial() (*Conn, error) { | ||||||
| 	var conn Conn | 	var conn Conn | ||||||
| 
 | 	// dial
 | ||||||
| 	fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP())) | 	fd, err := net.Dial("tcp", fmt.Sprintf("%v:%d", s.Dest.IP(), s.Dest.TCP())) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	conn.Conn = rlpx.NewConn(fd, s.Dest.Pubkey()) | 	conn.Conn = rlpx.NewConn(fd, s.Dest.Pubkey()) | ||||||
| 
 |  | ||||||
| 	// do encHandshake
 | 	// do encHandshake
 | ||||||
| 	conn.ourKey, _ = crypto.GenerateKey() | 	conn.ourKey, _ = crypto.GenerateKey() | ||||||
| 	_, err = conn.Handshake(conn.ourKey) | 	_, err = conn.Handshake(conn.ourKey) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 
 | 	// set default p2p capabilities
 | ||||||
|  | 	conn.caps = []p2p.Cap{ | ||||||
|  | 		{Name: "eth", Version: 64}, | ||||||
|  | 		{Name: "eth", Version: 65}, | ||||||
|  | 	} | ||||||
| 	return &conn, nil | 	return &conn, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -30,6 +30,10 @@ var faucetKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c666 | |||||||
| 
 | 
 | ||||||
| func sendSuccessfulTx(t *utesting.T, s *Suite, tx *types.Transaction) { | func sendSuccessfulTx(t *utesting.T, s *Suite, tx *types.Transaction) { | ||||||
| 	sendConn := s.setupConnection(t) | 	sendConn := s.setupConnection(t) | ||||||
|  | 	sendSuccessfulTxWithConn(t, s, tx, sendConn) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sendSuccessfulTxWithConn(t *utesting.T, s *Suite, tx *types.Transaction, sendConn *Conn) { | ||||||
| 	t.Logf("sending tx: %v %v %v\n", tx.Hash().String(), tx.GasPrice(), tx.Gas()) | 	t.Logf("sending tx: %v %v %v\n", tx.Hash().String(), tx.GasPrice(), tx.Gas()) | ||||||
| 	// Send the transaction
 | 	// Send the transaction
 | ||||||
| 	if err := sendConn.Write(&Transactions{tx}); err != nil { | 	if err := sendConn.Write(&Transactions{tx}); err != nil { | ||||||
| @ -41,20 +45,21 @@ func sendSuccessfulTx(t *utesting.T, s *Suite, tx *types.Transaction) { | |||||||
| 	switch msg := recvConn.ReadAndServe(s.chain, timeout).(type) { | 	switch msg := recvConn.ReadAndServe(s.chain, timeout).(type) { | ||||||
| 	case *Transactions: | 	case *Transactions: | ||||||
| 		recTxs := *msg | 		recTxs := *msg | ||||||
| 		if len(recTxs) < 1 { | 		for _, gotTx := range recTxs { | ||||||
| 			t.Fatalf("received transactions do not match send: %v", recTxs) | 			if gotTx.Hash() == tx.Hash() { | ||||||
| 		} | 				// Ok
 | ||||||
| 		if tx.Hash() != recTxs[len(recTxs)-1].Hash() { | 				return | ||||||
| 			t.Fatalf("received transactions do not match send: got %v want %v", recTxs, tx) | 			} | ||||||
| 		} | 		} | ||||||
|  | 		t.Fatalf("missing transaction: got %v missing %v", recTxs, tx.Hash()) | ||||||
| 	case *NewPooledTransactionHashes: | 	case *NewPooledTransactionHashes: | ||||||
| 		txHashes := *msg | 		txHashes := *msg | ||||||
| 		if len(txHashes) < 1 { | 		for _, gotHash := range txHashes { | ||||||
| 			t.Fatalf("received transactions do not match send: %v", txHashes) | 			if gotHash == tx.Hash() { | ||||||
| 		} | 				return | ||||||
| 		if tx.Hash() != txHashes[len(txHashes)-1] { | 			} | ||||||
| 			t.Fatalf("wrong announcement received, wanted %v got %v", tx, txHashes) |  | ||||||
| 		} | 		} | ||||||
|  | 		t.Fatalf("missing transaction announcement: got %v missing %v", txHashes, tx.Hash()) | ||||||
| 	default: | 	default: | ||||||
| 		t.Fatalf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg)) | 		t.Fatalf("unexpected message in sendSuccessfulTx: %s", pretty.Sdump(msg)) | ||||||
| 	} | 	} | ||||||
| @ -62,6 +67,10 @@ func sendSuccessfulTx(t *utesting.T, s *Suite, tx *types.Transaction) { | |||||||
| 
 | 
 | ||||||
| func sendFailingTx(t *utesting.T, s *Suite, tx *types.Transaction) { | func sendFailingTx(t *utesting.T, s *Suite, tx *types.Transaction) { | ||||||
| 	sendConn, recvConn := s.setupConnection(t), s.setupConnection(t) | 	sendConn, recvConn := s.setupConnection(t), s.setupConnection(t) | ||||||
|  | 	sendFailingTxWithConns(t, s, tx, sendConn, recvConn) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func sendFailingTxWithConns(t *utesting.T, s *Suite, tx *types.Transaction, sendConn, recvConn *Conn) { | ||||||
| 	// Wait for a transaction announcement
 | 	// Wait for a transaction announcement
 | ||||||
| 	switch msg := recvConn.ReadAndServe(s.chain, timeout).(type) { | 	switch msg := recvConn.ReadAndServe(s.chain, timeout).(type) { | ||||||
| 	case *NewPooledTransactionHashes: | 	case *NewPooledTransactionHashes: | ||||||
|  | |||||||
| @ -125,6 +125,7 @@ type Conn struct { | |||||||
| 	*rlpx.Conn | 	*rlpx.Conn | ||||||
| 	ourKey             *ecdsa.PrivateKey | 	ourKey             *ecdsa.PrivateKey | ||||||
| 	ethProtocolVersion uint | 	ethProtocolVersion uint | ||||||
|  | 	caps               []p2p.Cap | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *Conn) Read() Message { | func (c *Conn) Read() Message { | ||||||
| @ -221,11 +222,8 @@ func (c *Conn) handshake(t *utesting.T) Message { | |||||||
| 	pub0 := crypto.FromECDSAPub(&c.ourKey.PublicKey)[1:] | 	pub0 := crypto.FromECDSAPub(&c.ourKey.PublicKey)[1:] | ||||||
| 	ourHandshake := &Hello{ | 	ourHandshake := &Hello{ | ||||||
| 		Version: 5, | 		Version: 5, | ||||||
| 		Caps: []p2p.Cap{ | 		Caps:    c.caps, | ||||||
| 			{Name: "eth", Version: 64}, | 		ID:      pub0, | ||||||
| 			{Name: "eth", Version: 65}, |  | ||||||
| 		}, |  | ||||||
| 		ID: pub0, |  | ||||||
| 	} | 	} | ||||||
| 	if err := c.Write(ourHandshake); err != nil { | 	if err := c.Write(ourHandshake); err != nil { | ||||||
| 		t.Fatalf("could not write to connection: %v", err) | 		t.Fatalf("could not write to connection: %v", err) | ||||||
|  | |||||||
| @ -94,6 +94,9 @@ func rlpxEthTest(ctx *cli.Context) error { | |||||||
| 	if ctx.NArg() < 3 { | 	if ctx.NArg() < 3 { | ||||||
| 		exit("missing path to chain.rlp as command-line argument") | 		exit("missing path to chain.rlp as command-line argument") | ||||||
| 	} | 	} | ||||||
| 	suite := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2]) | 	suite, err := ethtest.NewSuite(getNodeArg(ctx), ctx.Args()[1], ctx.Args()[2]) | ||||||
| 	return runTests(ctx, suite.AllTests()) | 	if err != nil { | ||||||
|  | 		exit(err) | ||||||
|  | 	} | ||||||
|  | 	return runTests(ctx, suite.EthTests()) | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							| @ -48,6 +48,7 @@ require ( | |||||||
| 	github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca | 	github.com/syndtr/goleveldb v1.0.1-0.20200815110645-5c35d600f0ca | ||||||
| 	github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef | 	github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef | ||||||
| 	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 | 	golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 | ||||||
|  | 	golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect | ||||||
| 	golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c | 	golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c | ||||||
| 	golang.org/x/text v0.3.3 | 	golang.org/x/text v0.3.3 | ||||||
| 	golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 | 	golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user