Skip to content

Commit 85ae3e1

Browse files
authored
cmd/devp2p/internal/ethtest: tests for BlockRangeUpdate (#31843)
I added a test for BlockRangeUpdate in #29158 but forgot to enable it. Here I'm adding two more tests for it. Also applied a small refactoring to combine calls to `dial()` and `peer()` into a single function, since these two calls are duplicated in each test.
1 parent c8be0f9 commit 85ae3e1

File tree

2 files changed

+110
-60
lines changed

2 files changed

+110
-60
lines changed

cmd/devp2p/internal/ethtest/conn.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,18 @@ func (c *Conn) ReadSnap() (any, error) {
228228
}
229229
}
230230

231+
// dialAndPeer creates a peer connection and runs the handshake.
232+
func (s *Suite) dialAndPeer(status *eth.StatusPacket69) (*Conn, error) {
233+
c, err := s.dial()
234+
if err != nil {
235+
return nil, err
236+
}
237+
if err = c.peer(s.chain, status); err != nil {
238+
c.Close()
239+
}
240+
return c, err
241+
}
242+
231243
// peer performs both the protocol handshake and the status message
232244
// exchange with the node in order to peer with it.
233245
func (c *Conn) peer(chain *Chain, status *eth.StatusPacket69) error {

cmd/devp2p/internal/ethtest/suite.go

Lines changed: 98 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ func (s *Suite) EthTests() []utesting.Test {
6868
return []utesting.Test{
6969
// status
7070
{Name: "Status", Fn: s.TestStatus},
71+
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
72+
{Name: "BlockRangeUpdateExpired", Fn: s.TestBlockRangeUpdateHistoryExp},
73+
{Name: "BlockRangeUpdateFuture", Fn: s.TestBlockRangeUpdateFuture},
74+
{Name: "BlockRangeUpdateInvalid", Fn: s.TestBlockRangeUpdateInvalid},
7175
// get block headers
7276
{Name: "GetBlockHeaders", Fn: s.TestGetBlockHeaders},
7377
{Name: "GetNonexistentBlockHeaders", Fn: s.TestGetNonexistentBlockHeaders},
@@ -77,8 +81,6 @@ func (s *Suite) EthTests() []utesting.Test {
7781
// get history
7882
{Name: "GetBlockBodies", Fn: s.TestGetBlockBodies},
7983
{Name: "GetReceipts", Fn: s.TestGetReceipts},
80-
// // malicious handshakes + status
81-
{Name: "MaliciousHandshake", Fn: s.TestMaliciousHandshake},
8284
// test transactions
8385
{Name: "LargeTxRequest", Fn: s.TestLargeTxRequest, Slow: true},
8486
{Name: "Transaction", Fn: s.TestTransaction},
@@ -102,15 +104,11 @@ func (s *Suite) SnapTests() []utesting.Test {
102104

103105
func (s *Suite) TestStatus(t *utesting.T) {
104106
t.Log(`This test is just a sanity check. It performs an eth protocol handshake.`)
105-
106-
conn, err := s.dial()
107+
conn, err := s.dialAndPeer(nil)
107108
if err != nil {
108-
t.Fatalf("dial failed: %v", err)
109-
}
110-
defer conn.Close()
111-
if err := conn.peer(s.chain, nil); err != nil {
112-
t.Fatalf("peering failed: %v", err)
109+
t.Fatal("peering failed:", err)
113110
}
111+
conn.Close()
114112
}
115113

116114
// headersMatch returns whether the received headers match the given request
@@ -120,15 +118,12 @@ func headersMatch(expected []*types.Header, headers []*types.Header) bool {
120118

121119
func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
122120
t.Log(`This test requests block headers from the node.`)
123-
124-
conn, err := s.dial()
121+
conn, err := s.dialAndPeer(nil)
125122
if err != nil {
126-
t.Fatalf("dial failed: %v", err)
127-
}
128-
defer conn.Close()
129-
if err = conn.peer(s.chain, nil); err != nil {
130123
t.Fatalf("peering failed: %v", err)
131124
}
125+
defer conn.Close()
126+
132127
// Send headers request.
133128
req := &eth.GetBlockHeadersPacket{
134129
RequestId: 33,
@@ -161,18 +156,13 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
161156
}
162157

163158
func (s *Suite) TestGetNonexistentBlockHeaders(t *utesting.T) {
164-
t.Log(`This test sends GetBlockHeaders requests for nonexistent blocks (using max uint64 value)
159+
t.Log(`This test sends GetBlockHeaders requests for nonexistent blocks (using max uint64 value)
165160
to check if the node disconnects after receiving multiple invalid requests.`)
166-
167-
conn, err := s.dial()
161+
conn, err := s.dialAndPeer(nil)
168162
if err != nil {
169-
t.Fatalf("dial failed: %v", err)
170-
}
171-
defer conn.Close()
172-
173-
if err := conn.peer(s.chain, nil); err != nil {
174163
t.Fatalf("peering failed: %v", err)
175164
}
165+
defer conn.Close()
176166

177167
// Create request with max uint64 value for a nonexistent block
178168
badReq := &eth.GetBlockHeadersPacket{
@@ -205,15 +195,11 @@ to check if the node disconnects after receiving multiple invalid requests.`)
205195
func (s *Suite) TestSimultaneousRequests(t *utesting.T) {
206196
t.Log(`This test requests blocks headers from the node, performing two requests
207197
concurrently, with different request IDs.`)
208-
209-
conn, err := s.dial()
198+
conn, err := s.dialAndPeer(nil)
210199
if err != nil {
211-
t.Fatalf("dial failed: %v", err)
212-
}
213-
defer conn.Close()
214-
if err := conn.peer(s.chain, nil); err != nil {
215200
t.Fatalf("peering failed: %v", err)
216201
}
202+
defer conn.Close()
217203

218204
// Create two different requests.
219205
req1 := &eth.GetBlockHeadersPacket{
@@ -279,15 +265,11 @@ concurrently, with different request IDs.`)
279265
func (s *Suite) TestSameRequestID(t *utesting.T) {
280266
t.Log(`This test requests block headers, performing two concurrent requests with the
281267
same request ID. The node should handle the request by responding to both requests.`)
282-
283-
conn, err := s.dial()
268+
conn, err := s.dialAndPeer(nil)
284269
if err != nil {
285-
t.Fatalf("dial failed: %v", err)
286-
}
287-
defer conn.Close()
288-
if err := conn.peer(s.chain, nil); err != nil {
289270
t.Fatalf("peering failed: %v", err)
290271
}
272+
defer conn.Close()
291273

292274
// Create two different requests with the same ID.
293275
reqID := uint64(1234)
@@ -350,15 +332,12 @@ same request ID. The node should handle the request by responding to both reques
350332
func (s *Suite) TestZeroRequestID(t *utesting.T) {
351333
t.Log(`This test sends a GetBlockHeaders message with a request-id of zero,
352334
and expects a response.`)
353-
354-
conn, err := s.dial()
335+
conn, err := s.dialAndPeer(nil)
355336
if err != nil {
356-
t.Fatalf("dial failed: %v", err)
357-
}
358-
defer conn.Close()
359-
if err := conn.peer(s.chain, nil); err != nil {
360337
t.Fatalf("peering failed: %v", err)
361338
}
339+
defer conn.Close()
340+
362341
req := &eth.GetBlockHeadersPacket{
363342
GetBlockHeadersRequest: &eth.GetBlockHeadersRequest{
364343
Origin: eth.HashOrNumber{Number: 0},
@@ -385,15 +364,12 @@ and expects a response.`)
385364

386365
func (s *Suite) TestGetBlockBodies(t *utesting.T) {
387366
t.Log(`This test sends GetBlockBodies requests to the node for known blocks in the test chain.`)
388-
389-
conn, err := s.dial()
367+
conn, err := s.dialAndPeer(nil)
390368
if err != nil {
391-
t.Fatalf("dial failed: %v", err)
392-
}
393-
defer conn.Close()
394-
if err := conn.peer(s.chain, nil); err != nil {
395369
t.Fatalf("peering failed: %v", err)
396370
}
371+
defer conn.Close()
372+
397373
// Create block bodies request.
398374
req := &eth.GetBlockBodiesPacket{
399375
RequestId: 55,
@@ -421,15 +397,11 @@ func (s *Suite) TestGetBlockBodies(t *utesting.T) {
421397

422398
func (s *Suite) TestGetReceipts(t *utesting.T) {
423399
t.Log(`This test sends GetReceipts requests to the node for known blocks in the test chain.`)
424-
425-
conn, err := s.dial()
400+
conn, err := s.dialAndPeer(nil)
426401
if err != nil {
427-
t.Fatalf("dial failed: %v", err)
428-
}
429-
defer conn.Close()
430-
if err := conn.peer(s.chain, nil); err != nil {
431402
t.Fatalf("peering failed: %v", err)
432403
}
404+
defer conn.Close()
433405

434406
// Find some blocks containing receipts.
435407
var hashes = make([]common.Hash, 0, 3)
@@ -546,17 +518,13 @@ func (s *Suite) TestMaliciousHandshake(t *utesting.T) {
546518
}
547519
}
548520

549-
func (s *Suite) TestInvalidBlockRangeUpdate(t *utesting.T) {
521+
func (s *Suite) TestBlockRangeUpdateInvalid(t *utesting.T) {
550522
t.Log(`This test sends an invalid BlockRangeUpdate message to the node and expects to be disconnected.`)
551-
552-
conn, err := s.dial()
523+
conn, err := s.dialAndPeer(nil)
553524
if err != nil {
554-
t.Fatalf("dial failed: %v", err)
525+
t.Fatal(err)
555526
}
556527
defer conn.Close()
557-
if err := conn.peer(s.chain, nil); err != nil {
558-
t.Fatalf("peering failed: %v", err)
559-
}
560528

561529
conn.Write(ethProto, eth.BlockRangeUpdateMsg, &eth.BlockRangeUpdatePacket{
562530
EarliestBlock: 10,
@@ -571,6 +539,76 @@ func (s *Suite) TestInvalidBlockRangeUpdate(t *utesting.T) {
571539
}
572540
}
573541

542+
func (s *Suite) TestBlockRangeUpdateFuture(t *utesting.T) {
543+
t.Log(`This test sends a BlockRangeUpdate that is beyond the chain head.
544+
The node should accept the update and should not disonnect.`)
545+
conn, err := s.dialAndPeer(nil)
546+
if err != nil {
547+
t.Fatal(err)
548+
}
549+
defer conn.Close()
550+
551+
head := s.chain.Head().NumberU64()
552+
var hash common.Hash
553+
rand.Read(hash[:])
554+
conn.Write(ethProto, eth.BlockRangeUpdateMsg, &eth.BlockRangeUpdatePacket{
555+
EarliestBlock: head + 10,
556+
LatestBlock: head + 50,
557+
LatestBlockHash: hash,
558+
})
559+
560+
// Ensure the node does not disconnect us.
561+
// Just send a few ping messages.
562+
for range 10 {
563+
time.Sleep(100 * time.Millisecond)
564+
if err := conn.Write(baseProto, pingMsg, []any{}); err != nil {
565+
t.Fatal("write error:", err)
566+
}
567+
code, _, err := conn.Read()
568+
switch {
569+
case err != nil:
570+
t.Fatal("read error:", err)
571+
case code == discMsg:
572+
t.Fatal("got disconnect")
573+
case code == pongMsg:
574+
}
575+
}
576+
}
577+
578+
func (s *Suite) TestBlockRangeUpdateHistoryExp(t *utesting.T) {
579+
t.Log(`This test sends a BlockRangeUpdate announcing incomplete (expired) history.
580+
The node should accept the update and should not disonnect.`)
581+
conn, err := s.dialAndPeer(nil)
582+
if err != nil {
583+
t.Fatal(err)
584+
}
585+
defer conn.Close()
586+
587+
head := s.chain.Head()
588+
conn.Write(ethProto, eth.BlockRangeUpdateMsg, &eth.BlockRangeUpdatePacket{
589+
EarliestBlock: head.NumberU64() - 10,
590+
LatestBlock: head.NumberU64(),
591+
LatestBlockHash: head.Hash(),
592+
})
593+
594+
// Ensure the node does not disconnect us.
595+
// Just send a few ping messages.
596+
for range 10 {
597+
time.Sleep(100 * time.Millisecond)
598+
if err := conn.Write(baseProto, pingMsg, []any{}); err != nil {
599+
t.Fatal("write error:", err)
600+
}
601+
code, _, err := conn.Read()
602+
switch {
603+
case err != nil:
604+
t.Fatal("read error:", err)
605+
case code == discMsg:
606+
t.Fatal("got disconnect")
607+
case code == pongMsg:
608+
}
609+
}
610+
}
611+
574612
func (s *Suite) TestTransaction(t *utesting.T) {
575613
t.Log(`This test sends a valid transaction to the node and checks if the
576614
transaction gets propagated.`)

0 commit comments

Comments
 (0)