Skip to content

Commit 36bb7ac

Browse files
renaynayfjl
andauthored
cmd/devp2p/internal/ethtest: add correct chain files and improve test output (#21782)
This PR replaces the old test genesis.json and chain.rlp files in the testdata directory for the eth protocol test suite, and also adds documentation for running the eth test suite locally. It also improves the test output text and adds more timeouts. Co-authored-by: Felix Lange <[email protected]>
1 parent 5d20fbb commit 36bb7ac

File tree

7 files changed

+78
-35
lines changed

7 files changed

+78
-35
lines changed

cmd/devp2p/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,25 @@ Now get the ENR of your node and store it in the `NODE` environment variable.
8181

8282
Start the test by running `devp2p discv5 test -listen1 127.0.0.1 -listen2 127.0.0.2 $NODE`.
8383

84+
### Eth Protocol Test Suite
85+
86+
The Eth Protocol test suite is a conformance test suite for the [eth protocol][eth].
87+
88+
To run the eth protocol test suite against your implementation, the node needs to be initialized as such:
89+
90+
1. initialize the geth node with the `genesis.json` file contained in the `testdata` directory
91+
2. import the `halfchain.rlp` file in the `testdata` directory
92+
3. run geth with the following flags:
93+
```
94+
geth --datadir <datadir> --nodiscover --nat=none --networkid 19763 --verbosity 5
95+
```
96+
97+
Then, run the following command, replacing `<enode ID>` with the enode of the geth node:
98+
```
99+
devp2p rlpx eth-test <enode ID> cmd/devp2p/internal/ethtest/testdata/fullchain.rlp cmd/devp2p/internal/ethtest/testdata/genesis.json
100+
```
101+
102+
[eth]: https://github.com/ethereum/devp2p/blob/master/caps/eth.md
84103
[dns-tutorial]: https://geth.ethereum.org/docs/developers/dns-discovery-setup
85104
[discv4]: https://github.com/ethereum/devp2p/tree/master/discv4.md
86105
[discv5]: https://github.com/ethereum/devp2p/tree/master/discv5/discv5.md

cmd/devp2p/internal/ethtest/chain_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func TestEthProtocolNegotiation(t *testing.T) {
7373
// TestChain_GetHeaders tests whether the test suite can correctly
7474
// respond to a GetBlockHeaders request from a node.
7575
func TestChain_GetHeaders(t *testing.T) {
76-
chainFile, err := filepath.Abs("./testdata/chain.rlp.gz")
76+
chainFile, err := filepath.Abs("./testdata/fullchain.rlp.gz")
7777
if err != nil {
7878
t.Fatal(err)
7979
}

cmd/devp2p/internal/ethtest/suite.go

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,23 @@ package ethtest
1919
import (
2020
"fmt"
2121
"net"
22+
"time"
2223

24+
"github.com/davecgh/go-spew/spew"
2325
"github.com/ethereum/go-ethereum/crypto"
2426
"github.com/ethereum/go-ethereum/internal/utesting"
2527
"github.com/ethereum/go-ethereum/p2p/enode"
2628
"github.com/ethereum/go-ethereum/p2p/rlpx"
2729
"github.com/stretchr/testify/assert"
2830
)
2931

32+
var pretty = spew.ConfigState{
33+
Indent: " ",
34+
DisableCapacities: true,
35+
DisablePointerAddresses: true,
36+
SortKeys: true,
37+
}
38+
3039
// Suite represents a structure used to test the eth
3140
// protocol of a node(s).
3241
type Suite struct {
@@ -73,9 +82,9 @@ func (s *Suite) TestStatus(t *utesting.T) {
7382
// get status
7483
switch msg := conn.statusExchange(t, s.chain).(type) {
7584
case *Status:
76-
t.Logf("%+v\n", msg)
85+
t.Logf("got status message: %s", pretty.Sdump(msg))
7786
default:
78-
t.Fatalf("unexpected: %#v", msg)
87+
t.Fatalf("unexpected: %s", pretty.Sdump(msg))
7988
}
8089
}
8190

@@ -104,16 +113,17 @@ func (s *Suite) TestGetBlockHeaders(t *utesting.T) {
104113
t.Fatalf("could not write to connection: %v", err)
105114
}
106115

107-
switch msg := conn.ReadAndServe(s.chain).(type) {
116+
timeout := 20 * time.Second
117+
switch msg := conn.ReadAndServe(s.chain, timeout).(type) {
108118
case *BlockHeaders:
109119
headers := msg
110120
for _, header := range *headers {
111121
num := header.Number.Uint64()
122+
t.Logf("received header (%d): %s", num, pretty.Sdump(header))
112123
assert.Equal(t, s.chain.blocks[int(num)].Header(), header)
113-
t.Logf("\nHEADER FOR BLOCK NUMBER %d: %+v\n", header.Number, header)
114124
}
115125
default:
116-
t.Fatalf("unexpected: %#v", msg)
126+
t.Fatalf("unexpected: %s", pretty.Sdump(msg))
117127
}
118128
}
119129

@@ -133,14 +143,12 @@ func (s *Suite) TestGetBlockBodies(t *utesting.T) {
133143
t.Fatalf("could not write to connection: %v", err)
134144
}
135145

136-
switch msg := conn.ReadAndServe(s.chain).(type) {
146+
timeout := 20 * time.Second
147+
switch msg := conn.ReadAndServe(s.chain, timeout).(type) {
137148
case *BlockBodies:
138-
bodies := msg
139-
for _, body := range *bodies {
140-
t.Logf("\nBODY: %+v\n", body)
141-
}
149+
t.Logf("received %d block bodies", len(*msg))
142150
default:
143-
t.Fatalf("unexpected: %#v", msg)
151+
t.Fatalf("unexpected: %s", pretty.Sdump(msg))
144152
}
145153
}
146154

@@ -173,18 +181,27 @@ func (s *Suite) TestBroadcast(t *utesting.T) {
173181
t.Fatalf("could not write to connection: %v", err)
174182
}
175183

176-
switch msg := receiveConn.ReadAndServe(s.chain).(type) {
184+
timeout := 20 * time.Second
185+
switch msg := receiveConn.ReadAndServe(s.chain, timeout).(type) {
177186
case *NewBlock:
178-
assert.Equal(t, blockAnnouncement.Block.Header(), msg.Block.Header(),
179-
"wrong block header in announcement")
180-
assert.Equal(t, blockAnnouncement.TD, msg.TD,
181-
"wrong TD in announcement")
187+
t.Logf("received NewBlock message: %s", pretty.Sdump(msg.Block))
188+
assert.Equal(t,
189+
blockAnnouncement.Block.Header(), msg.Block.Header(),
190+
"wrong block header in announcement",
191+
)
192+
assert.Equal(t,
193+
blockAnnouncement.TD, msg.TD,
194+
"wrong TD in announcement",
195+
)
182196
case *NewBlockHashes:
183197
hashes := *msg
184-
assert.Equal(t, blockAnnouncement.Block.Hash(), hashes[0].Hash,
185-
"wrong block hash in announcement")
198+
t.Logf("received NewBlockHashes message: %s", pretty.Sdump(hashes))
199+
assert.Equal(t,
200+
blockAnnouncement.Block.Hash(), hashes[0].Hash,
201+
"wrong block hash in announcement",
202+
)
186203
default:
187-
t.Fatalf("unexpected: %#v", msg)
204+
t.Fatalf("unexpected: %s", pretty.Sdump(msg))
188205
}
189206
// update test suite chain
190207
s.chain.blocks = append(s.chain.blocks, s.fullChain.blocks[1000])
-239 KB
Binary file not shown.
247 KB
Binary file not shown.
123 KB
Binary file not shown.

cmd/devp2p/internal/ethtest/types.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,14 @@ type Error struct {
4242
err error
4343
}
4444

45-
func (e *Error) Unwrap() error { return e.err }
46-
func (e *Error) Error() string { return e.err.Error() }
47-
func (e *Error) Code() int { return -1 }
48-
func (e *Error) GoString() string { return e.Error() }
45+
func (e *Error) Unwrap() error { return e.err }
46+
func (e *Error) Error() string { return e.err.Error() }
47+
func (e *Error) Code() int { return -1 }
48+
func (e *Error) String() string { return e.Error() }
49+
50+
func errorf(format string, args ...interface{}) *Error {
51+
return &Error{fmt.Errorf(format, args...)}
52+
}
4953

5054
// Hello is the RLP structure of the protocol handshake.
5155
type Hello struct {
@@ -174,7 +178,7 @@ type Conn struct {
174178
func (c *Conn) Read() Message {
175179
code, rawData, _, err := c.Conn.Read()
176180
if err != nil {
177-
return &Error{fmt.Errorf("could not read from connection: %v", err)}
181+
return errorf("could not read from connection: %v", err)
178182
}
179183

180184
var msg Message
@@ -202,37 +206,40 @@ func (c *Conn) Read() Message {
202206
case (NewBlockHashes{}).Code():
203207
msg = new(NewBlockHashes)
204208
default:
205-
return &Error{fmt.Errorf("invalid message code: %d", code)}
209+
return errorf("invalid message code: %d", code)
206210
}
207211

208212
if err := rlp.DecodeBytes(rawData, msg); err != nil {
209-
return &Error{fmt.Errorf("could not rlp decode message: %v", err)}
213+
return errorf("could not rlp decode message: %v", err)
210214
}
211-
212215
return msg
213216
}
214217

215218
// ReadAndServe serves GetBlockHeaders requests while waiting
216219
// on another message from the node.
217-
func (c *Conn) ReadAndServe(chain *Chain) Message {
218-
for {
220+
func (c *Conn) ReadAndServe(chain *Chain, timeout time.Duration) Message {
221+
start := time.Now()
222+
for time.Since(start) < timeout {
223+
timeout := time.Now().Add(10 * time.Second)
224+
c.SetReadDeadline(timeout)
219225
switch msg := c.Read().(type) {
220226
case *Ping:
221227
c.Write(&Pong{})
222228
case *GetBlockHeaders:
223229
req := *msg
224230
headers, err := chain.GetHeaders(req)
225231
if err != nil {
226-
return &Error{fmt.Errorf("could not get headers for inbound header request: %v", err)}
232+
return errorf("could not get headers for inbound header request: %v", err)
227233
}
228234

229235
if err := c.Write(headers); err != nil {
230-
return &Error{fmt.Errorf("could not write to connection: %v", err)}
236+
return errorf("could not write to connection: %v", err)
231237
}
232238
default:
233239
return msg
234240
}
235241
}
242+
return errorf("no message received within %v", timeout)
236243
}
237244

238245
func (c *Conn) Write(msg Message) error {
@@ -308,7 +315,7 @@ loop:
308315
switch msg := c.Read().(type) {
309316
case *Status:
310317
if msg.Head != chain.blocks[chain.Len()-1].Hash() {
311-
t.Fatalf("wrong head in status: %v", msg.Head)
318+
t.Fatalf("wrong head block in status: %s", msg.Head.String())
312319
}
313320
if msg.TD.Cmp(chain.TD(chain.Len())) != 0 {
314321
t.Fatalf("wrong TD in status: %v", msg.TD)
@@ -324,7 +331,7 @@ loop:
324331
c.Write(&Pong{}) // TODO (renaynay): in the future, this should be an error
325332
// (PINGs should not be a response upon fresh connection)
326333
default:
327-
t.Fatalf("bad status message: %#v", msg)
334+
t.Fatalf("bad status message: %s", pretty.Sdump(msg))
328335
}
329336
}
330337
// make sure eth protocol version is set for negotiation
@@ -366,7 +373,7 @@ func (c *Conn) waitForBlock(block *types.Block) error {
366373
}
367374
time.Sleep(100 * time.Millisecond)
368375
default:
369-
return fmt.Errorf("invalid message: %v", msg)
376+
return fmt.Errorf("invalid message: %s", pretty.Sdump(msg))
370377
}
371378
}
372379
}

0 commit comments

Comments
 (0)