Skip to content
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

cmd/devp2p/internal/ethtest: add block hash announcement test #22535

Merged
merged 1 commit into from May 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 103 additions & 0 deletions cmd/devp2p/internal/ethtest/helpers.go
Expand Up @@ -633,3 +633,106 @@ func (s *Suite) maliciousStatus(conn *Conn) error {
return fmt.Errorf("expected disconnect, got: %s", pretty.Sdump(msg))
}
}

func (s *Suite) hashAnnounce(isEth66 bool) error {
// create connections
sendConn, recvConn, err := s.createSendAndRecvConns(isEth66)
if err != nil {
return fmt.Errorf("failed to create connections: %v", err)
}
defer sendConn.Close()
defer recvConn.Close()
if err := sendConn.peer(s.chain, nil); err != nil {
return fmt.Errorf("peering failed: %v", err)
}
if err := recvConn.peer(s.chain, nil); err != nil {
return fmt.Errorf("peering failed: %v", err)
}
// create NewBlockHashes announcement
nextBlock := s.fullChain.blocks[s.chain.Len()]
newBlockHash := &NewBlockHashes{
{Hash: nextBlock.Hash(), Number: nextBlock.Number().Uint64()},
}

if err := sendConn.Write(newBlockHash); err != nil {
return fmt.Errorf("failed to write to connection: %v", err)
}
if isEth66 {
// expect GetBlockHeaders request, and respond
id, msg := sendConn.Read66()
switch msg := msg.(type) {
case GetBlockHeaders:
blockHeaderReq := msg
if blockHeaderReq.Amount != 1 {
return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount)
}
if blockHeaderReq.Origin.Hash != nextBlock.Hash() {
return fmt.Errorf("unexpected block header requested: %v", pretty.Sdump(blockHeaderReq))
}
resp := &eth.BlockHeadersPacket66{
RequestId: id,
BlockHeadersPacket: eth.BlockHeadersPacket{
nextBlock.Header(),
},
}
if err := sendConn.Write66(resp, BlockHeaders{}.Code()); err != nil {
return fmt.Errorf("failed to write to connection: %v", err)
}
default:
return fmt.Errorf("unexpected %s", pretty.Sdump(msg))
}
} else {
// expect GetBlockHeaders request, and respond
switch msg := sendConn.Read().(type) {
case *GetBlockHeaders:
blockHeaderReq := *msg
if blockHeaderReq.Amount != 1 {
return fmt.Errorf("unexpected number of block headers requested: %v", blockHeaderReq.Amount)
}
if blockHeaderReq.Origin.Hash != nextBlock.Hash() {
return fmt.Errorf("unexpected block header requested: %v", pretty.Sdump(blockHeaderReq))
}
if err := sendConn.Write(&BlockHeaders{nextBlock.Header()}); err != nil {
return fmt.Errorf("failed to write to connection: %v", err)
}
default:
return fmt.Errorf("unexpected %s", pretty.Sdump(msg))
}
}
// wait for block announcement
msg := recvConn.readAndServe(s.chain, timeout)
switch msg := msg.(type) {
case *NewBlockHashes:
hashes := *msg
if len(hashes) != 1 {
return fmt.Errorf("unexpected new block hash announcement: wanted 1 announcement, got %d", len(hashes))
}
if nextBlock.Hash() != hashes[0].Hash {
return fmt.Errorf("unexpected block hash announcement, wanted %v, got %v", nextBlock.Hash(),
hashes[0].Hash)
}
case *NewBlock:
// node should only propagate NewBlock without having requested the body if the body is empty
nextBlockBody := nextBlock.Body()
if len(nextBlockBody.Transactions) != 0 || len(nextBlockBody.Uncles) != 0 {
return fmt.Errorf("unexpected non-empty new block propagated: %s", pretty.Sdump(msg))
}
if msg.Block.Hash() != nextBlock.Hash() {
return fmt.Errorf("mismatched hash of propagated new block: wanted %v, got %v",
nextBlock.Hash(), msg.Block.Hash())
}
// check to make sure header matches header that was sent to the node
if !reflect.DeepEqual(nextBlock.Header(), msg.Block.Header()) {
return fmt.Errorf("incorrect header received: wanted %v, got %v", nextBlock.Header(), msg.Block.Header())
}
default:
return fmt.Errorf("unexpected: %s", pretty.Sdump(msg))
}
// confirm node imported block
if err := s.waitForBlockImport(recvConn, nextBlock, isEth66); err != nil {
return fmt.Errorf("error waiting for node to import new block: %v", err)
}
// update the chain
s.chain.blocks = append(s.chain.blocks, nextBlock)
return nil
}
20 changes: 20 additions & 0 deletions cmd/devp2p/internal/ethtest/suite.go
Expand Up @@ -70,6 +70,8 @@ func (s *Suite) AllEthTests() []utesting.Test {
{Name: "TestLargeAnnounce66", Fn: s.TestLargeAnnounce66},
{Name: "TestOldAnnounce", Fn: s.TestOldAnnounce},
{Name: "TestOldAnnounce66", Fn: s.TestOldAnnounce66},
{Name: "TestBlockHashAnnounce", Fn: s.TestBlockHashAnnounce},
{Name: "TestBlockHashAnnounce66", Fn: s.TestBlockHashAnnounce66},
// malicious handshakes + status
{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus},
Expand All @@ -93,6 +95,7 @@ func (s *Suite) EthTests() []utesting.Test {
{Name: "TestBroadcast", Fn: s.TestBroadcast},
{Name: "TestLargeAnnounce", Fn: s.TestLargeAnnounce},
{Name: "TestOldAnnounce", Fn: s.TestOldAnnounce},
{Name: "TestBlockHashAnnounce", Fn: s.TestBlockHashAnnounce},
{Name: "TestMaliciousHandshake", Fn: s.TestMaliciousHandshake},
{Name: "TestMaliciousStatus", Fn: s.TestMaliciousStatus},
{Name: "TestTransaction", Fn: s.TestTransaction},
Expand All @@ -112,6 +115,7 @@ func (s *Suite) Eth66Tests() []utesting.Test {
{Name: "TestBroadcast66", Fn: s.TestBroadcast66},
{Name: "TestLargeAnnounce66", Fn: s.TestLargeAnnounce66},
{Name: "TestOldAnnounce66", Fn: s.TestOldAnnounce66},
{Name: "TestBlockHashAnnounce66", Fn: s.TestBlockHashAnnounce66},
{Name: "TestMaliciousHandshake66", Fn: s.TestMaliciousHandshake66},
{Name: "TestMaliciousStatus66", Fn: s.TestMaliciousStatus66},
{Name: "TestTransaction66", Fn: s.TestTransaction66},
Expand Down Expand Up @@ -580,6 +584,22 @@ func (s *Suite) TestOldAnnounce66(t *utesting.T) {
}
}

// TestBlockHashAnnounce sends a new block hash announcement and expects
// the node to perform a `GetBlockHeaders` request.
func (s *Suite) TestBlockHashAnnounce(t *utesting.T) {
if err := s.hashAnnounce(eth65); err != nil {
t.Fatalf("block hash announcement failed: %v", err)
}
}

// TestBlockHashAnnounce66 sends a new block hash announcement and expects
// the node to perform a `GetBlockHeaders` request.
func (s *Suite) TestBlockHashAnnounce66(t *utesting.T) {
if err := s.hashAnnounce(eth66); err != nil {
t.Fatalf("block hash announcement failed: %v", err)
}
}

// TestMaliciousHandshake tries to send malicious data during the handshake.
func (s *Suite) TestMaliciousHandshake(t *utesting.T) {
if err := s.maliciousHandshakes(t, eth65); err != nil {
Expand Down