Skip to content

cmd/devp2p: ethtest suite runnable as unit test #22698

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Apr 23, 2021
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cmd/devp2p/internal/ethtest/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
)

type Chain struct {
genesis core.Genesis
blocks []*types.Block
chainConfig *params.ChainConfig
}
Expand Down Expand Up @@ -124,16 +125,34 @@ func (c *Chain) GetHeaders(req GetBlockHeaders) (BlockHeaders, error) {
// loadChain takes the given chain.rlp file, and decodes and returns
// the blocks from the file.
func loadChain(chainfile string, genesis string) (*Chain, error) {
chainConfig, err := ioutil.ReadFile(genesis)
gen, err := loadGenesis(genesis)
if err != nil {
return nil, err
}
gblock := gen.ToBlock(nil)

blocks, err := blocksFromFile(chainfile, gblock)
if err != nil {
return nil, err
}

c := &Chain{genesis: gen, blocks: blocks, chainConfig: gen.Config}
return c, nil
}

func loadGenesis(genesisFile string) (core.Genesis, error) {
chainConfig, err := ioutil.ReadFile(genesisFile)
if err != nil {
return core.Genesis{}, err
}
var gen core.Genesis
if err := json.Unmarshal(chainConfig, &gen); err != nil {
return nil, err
return core.Genesis{}, err
}
gblock := gen.ToBlock(nil)
return gen, nil
}

func blocksFromFile(chainfile string, gblock *types.Block) ([]*types.Block, error) {
// Load chain.rlp.
fh, err := os.Open(chainfile)
if err != nil {
Expand Down Expand Up @@ -161,7 +180,5 @@ func loadChain(chainfile string, genesis string) (*Chain, error) {
}
blocks = append(blocks, &b)
}

c := &Chain{blocks: blocks, chainConfig: gen.Config}
return c, nil
return blocks, nil
}
34 changes: 26 additions & 8 deletions cmd/devp2p/internal/ethtest/eth66_suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func (s *Suite) Is_66(t *utesting.T) {
// make sure the chain head is correct.
func (s *Suite) TestStatus_66(t *utesting.T) {
conn := s.dial66(t)
defer conn.Close()
// get protoHandshake
conn.handshake(t)
// get status
Expand All @@ -60,6 +61,7 @@ func (s *Suite) TestStatus_66(t *utesting.T) {
// an eth66 `GetBlockHeaders` request and that the response is accurate.
func (s *Suite) TestGetBlockHeaders_66(t *utesting.T) {
conn := s.setupConnection66(t)
defer conn.Close()
// get block headers
req := &eth.GetBlockHeadersPacket66{
RequestId: 3,
Expand All @@ -84,6 +86,8 @@ func (s *Suite) TestGetBlockHeaders_66(t *utesting.T) {
func (s *Suite) TestSimultaneousRequests_66(t *utesting.T) {
// create two connections
conn1, conn2 := s.setupConnection66(t), s.setupConnection66(t)
defer conn1.Close()
defer conn2.Close()
// create two requests
req1 := &eth.GetBlockHeadersPacket66{
RequestId: 111,
Expand Down Expand Up @@ -122,6 +126,9 @@ func (s *Suite) TestSimultaneousRequests_66(t *utesting.T) {
// 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)
defer sendConn.Close()
defer receiveConn.Close()

nextBlock := len(s.chain.blocks)
blockAnnouncement := &NewBlock{
Block: s.fullChain.blocks[nextBlock],
Expand All @@ -141,6 +148,7 @@ func (s *Suite) TestBroadcast_66(t *utesting.T) {
// the eth66 protocol.
func (s *Suite) TestGetBlockBodies_66(t *utesting.T) {
conn := s.setupConnection66(t)
defer conn.Close()
// create block bodies request
id := uint64(55)
req := &eth.GetBlockBodiesPacket66{
Expand Down Expand Up @@ -202,10 +210,13 @@ func (s *Suite) TestLargeAnnounce_66(t *utesting.T) {
default:
t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg))
}
sendConn.Close()
}
// Test the last block as a valid block
sendConn := s.setupConnection66(t)
receiveConn := s.setupConnection66(t)
sendConn, receiveConn := s.setupConnection66(t), s.setupConnection66(t)
defer sendConn.Close()
defer receiveConn.Close()

s.testAnnounce66(t, sendConn, receiveConn, blocks[3])
// update test suite chain
s.chain.blocks = append(s.chain.blocks, s.fullChain.blocks[nextBlock])
Expand All @@ -216,12 +227,17 @@ func (s *Suite) TestLargeAnnounce_66(t *utesting.T) {
}

func (s *Suite) TestOldAnnounce_66(t *utesting.T) {
s.oldAnnounce(t, s.setupConnection66(t), s.setupConnection66(t))
sendConn, recvConn := s.setupConnection66(t), s.setupConnection66(t)
defer sendConn.Close()
defer recvConn.Close()

s.oldAnnounce(t, sendConn, recvConn)
}

// TestMaliciousHandshake_66 tries to send malicious data during the handshake.
func (s *Suite) TestMaliciousHandshake_66(t *utesting.T) {
conn := s.dial66(t)
defer conn.Close()
// write hello to client
pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:]
handshakes := []*Hello{
Expand Down Expand Up @@ -295,6 +311,7 @@ func (s *Suite) TestMaliciousHandshake_66(t *utesting.T) {
// TestMaliciousStatus_66 sends a status package with a large total difficulty.
func (s *Suite) TestMaliciousStatus_66(t *utesting.T) {
conn := s.dial66(t)
defer conn.Close()
// get protoHandshake
conn.handshake(t)
status := &Status{
Expand Down Expand Up @@ -334,23 +351,23 @@ func (s *Suite) TestTransaction_66(t *utesting.T) {
}

func (s *Suite) TestMaliciousTx_66(t *utesting.T) {
tests := []*types.Transaction{
badTxs := []*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)
}
t.Logf("Testing malicious tx propagation")
sendFailingTx66(t, s, badTxs)
}

// 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)
defer conn.Close()

req := &eth.GetBlockHeadersPacket66{
RequestId: 0,
GetBlockHeadersPacket: &eth.GetBlockHeadersPacket{
Expand All @@ -367,6 +384,7 @@ func (s *Suite) TestZeroRequestID_66(t *utesting.T) {
// concurrently to a single node.
func (s *Suite) TestSameRequestID_66(t *utesting.T) {
conn := s.setupConnection66(t)
defer conn.Close()
// create two separate requests with same ID
reqID := uint64(1234)
req1 := &eth.GetBlockHeadersPacket66{
Expand Down
7 changes: 5 additions & 2 deletions cmd/devp2p/internal/ethtest/eth66_suiteHelpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,12 +238,15 @@ func (c *Conn) waitForBlock66(block *types.Block) error {

func sendSuccessfulTx66(t *utesting.T, s *Suite, tx *types.Transaction) {
sendConn := s.setupConnection66(t)
defer sendConn.Close()
sendSuccessfulTxWithConn(t, s, tx, sendConn)
}

func sendFailingTx66(t *utesting.T, s *Suite, tx *types.Transaction) {
func sendFailingTx66(t *utesting.T, s *Suite, txs []*types.Transaction) {
sendConn, recvConn := s.setupConnection66(t), s.setupConnection66(t)
sendFailingTxWithConns(t, s, tx, sendConn, recvConn)
defer sendConn.Close()
defer recvConn.Close()
sendFailingTxsWithConns(t, s, txs, sendConn, recvConn)
}

func (s *Suite) getBlockHeaders66(t *utesting.T, conn *Conn, req eth.Packet, expectedID uint64) BlockHeaders {
Expand Down
82 changes: 48 additions & 34 deletions cmd/devp2p/internal/ethtest/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,29 +74,29 @@ func (s *Suite) AllEthTests() []utesting.Test {
// get block headers
{Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders},
{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},
{Name: "SimultaneousRequests_66", Fn: s.TestSimultaneousRequests_66},
{Name: "SameRequestID_66", Fn: s.TestSameRequestID_66},
{Name: "ZeroRequestID_66", Fn: s.TestZeroRequestID_66},
// get block bodies
{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_66", Fn: s.TestLargeAnnounce_66},
{Name: "TestOldAnnounce", Fn: s.TestOldAnnounce},
{Name: "TestOldAnnounce_66", Fn: s.TestOldAnnounce_66},
{Name: "LargeAnnounce", Fn: s.TestLargeAnnounce},
{Name: "LargeAnnounce_66", Fn: s.TestLargeAnnounce_66},
{Name: "OldAnnounce", Fn: s.TestOldAnnounce},
{Name: "OldAnnounce_66", Fn: s.TestOldAnnounce_66},
// malicious handshakes + status
{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus},
{Name: "TestMaliciousHandshake_66", Fn: s.TestMaliciousHandshake_66},
{Name: "TestMaliciousStatus_66", Fn: s.TestMaliciousStatus},
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "MaliciousStatus", Fn: s.TestMaliciousStatus},
{Name: "MaliciousHandshake_66", Fn: s.TestMaliciousHandshake_66},
{Name: "MaliciousStatus_66", Fn: s.TestMaliciousStatus_66},
// test transactions
{Name: "TestTransactions", Fn: s.TestTransaction},
{Name: "TestTransactions_66", Fn: s.TestTransaction_66},
{Name: "TestMaliciousTransactions", Fn: s.TestMaliciousTx},
{Name: "TestMaliciousTransactions_66", Fn: s.TestMaliciousTx_66},
{Name: "Transactions", Fn: s.TestTransaction},
{Name: "Transactions_66", Fn: s.TestTransaction_66},
{Name: "MaliciousTransactions", Fn: s.TestMaliciousTx},
{Name: "MaliciousTransactions_66", Fn: s.TestMaliciousTx_66},
}
}

Expand All @@ -106,12 +106,12 @@ func (s *Suite) EthTests() []utesting.Test {
{Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders},
{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies},
{Name: "Broadcast", Fn: s.TestBroadcast},
{Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce},
{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus},
{Name: "TestMaliciousStatus_66", Fn: s.TestMaliciousStatus},
{Name: "TestTransactions", Fn: s.TestTransaction},
{Name: "TestMaliciousTransactions", Fn: s.TestMaliciousTx},
{Name: "LargeAnnounce", Fn: s.TestLargeAnnounce},
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "MaliciousStatus", Fn: s.TestMaliciousStatus},
{Name: "MaliciousStatus_66", Fn: s.TestMaliciousStatus},
{Name: "Transactions", Fn: s.TestTransaction},
{Name: "MaliciousTransactions", Fn: s.TestMaliciousTx},
}
}

Expand All @@ -120,15 +120,15 @@ func (s *Suite) Eth66Tests() []utesting.Test {
// only proceed with eth66 test suite if node supports eth 66 protocol
{Name: "Status_66", Fn: s.TestStatus_66},
{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},
{Name: "SimultaneousRequests_66", Fn: s.TestSimultaneousRequests_66},
{Name: "SameRequestID_66", Fn: s.TestSameRequestID_66},
{Name: "ZeroRequestID_66", Fn: s.TestZeroRequestID_66},
{Name: "GetBlockBodies_66", Fn: s.TestGetBlockBodies_66},
{Name: "Broadcast_66", Fn: s.TestBroadcast_66},
{Name: "TestLargeAnnounce_66", Fn: s.TestLargeAnnounce_66},
{Name: "TestMaliciousHandshake_66", Fn: s.TestMaliciousHandshake_66},
{Name: "TestTransactions_66", Fn: s.TestTransaction_66},
{Name: "TestMaliciousTransactions_66", Fn: s.TestMaliciousTx_66},
{Name: "LargeAnnounce_66", Fn: s.TestLargeAnnounce_66},
{Name: "MaliciousHandshake_66", Fn: s.TestMaliciousHandshake_66},
{Name: "Transactions_66", Fn: s.TestTransaction_66},
{Name: "MaliciousTransactions_66", Fn: s.TestMaliciousTx_66},
}
}

Expand All @@ -140,6 +140,7 @@ func (s *Suite) TestStatus(t *utesting.T) {
if err != nil {
t.Fatalf("could not dial: %v", err)
}
defer conn.Close()
// get protoHandshake
conn.handshake(t)
// get status
Expand All @@ -157,6 +158,7 @@ func (s *Suite) TestMaliciousStatus(t *utesting.T) {
if err != nil {
t.Fatalf("could not dial: %v", err)
}
defer conn.Close()
// get protoHandshake
conn.handshake(t)
status := &Status{
Expand Down Expand Up @@ -191,6 +193,7 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
if err != nil {
t.Fatalf("could not dial: %v", err)
}
defer conn.Close()

conn.handshake(t)
conn.statusExchange(t, s.chain, nil)
Expand Down Expand Up @@ -229,6 +232,7 @@ func (s *Suite) TestGetBlockBodies(t *utesting.T) {
if err != nil {
t.Fatalf("could not dial: %v", err)
}
defer conn.Close()

conn.handshake(t)
conn.statusExchange(t, s.chain, nil)
Expand All @@ -253,6 +257,9 @@ func (s *Suite) TestGetBlockBodies(t *utesting.T) {
// propagated to the given node's peer(s).
func (s *Suite) TestBroadcast(t *utesting.T) {
sendConn, receiveConn := s.setupConnection(t), s.setupConnection(t)
defer sendConn.Close()
defer receiveConn.Close()

nextBlock := len(s.chain.blocks)
blockAnnouncement := &NewBlock{
Block: s.fullChain.blocks[nextBlock],
Expand All @@ -273,6 +280,7 @@ func (s *Suite) TestMaliciousHandshake(t *utesting.T) {
if err != nil {
t.Fatalf("could not dial: %v", err)
}
defer conn.Close()
// write hello to client
pub0 := crypto.FromECDSAPub(&conn.ourKey.PublicKey)[1:]
handshakes := []*Hello{
Expand Down Expand Up @@ -379,10 +387,14 @@ func (s *Suite) TestLargeAnnounce(t *utesting.T) {
default:
t.Fatalf("unexpected: %s wanted disconnect", pretty.Sdump(msg))
}
sendConn.Close()
}
// Test the last block as a valid block
sendConn := s.setupConnection(t)
receiveConn := s.setupConnection(t)
defer sendConn.Close()
defer receiveConn.Close()

s.testAnnounce(t, sendConn, receiveConn, blocks[3])
// update test suite chain
s.chain.blocks = append(s.chain.blocks, s.fullChain.blocks[nextBlock])
Expand All @@ -393,7 +405,11 @@ func (s *Suite) TestLargeAnnounce(t *utesting.T) {
}

func (s *Suite) TestOldAnnounce(t *utesting.T) {
s.oldAnnounce(t, s.setupConnection(t), s.setupConnection(t))
sendConn, recvConn := s.setupConnection(t), s.setupConnection(t)
defer sendConn.Close()
defer recvConn.Close()

s.oldAnnounce(t, sendConn, recvConn)
}

func (s *Suite) oldAnnounce(t *utesting.T, sendConn, receiveConn *Conn) {
Expand Down Expand Up @@ -502,15 +518,13 @@ func (s *Suite) TestTransaction(t *utesting.T) {
}

func (s *Suite) TestMaliciousTx(t *utesting.T) {
tests := []*types.Transaction{
badTxs := []*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)
sendFailingTx(t, s, tx)
}
t.Logf("Testing malicious tx propagation")
sendFailingTxs(t, s, badTxs)
}
Loading