Skip to content

Commit f633a27

Browse files
vdwijdenMariusVanDerWijdenkaralabe
authored andcommitted
eth: implement eth/68 (ethereum#25980)
* eth: implement eth/68 * eth/protocols/eth: added tx size to announcement * eth/protocols/eth: check equal lengths on receiving announcement * eth/protocols/eth: add +1 to tx size because of the type byte * eth: happy lint, add eth68 tests, enable eth68 * eth: various nitpick fixes on eth/68 * eth/protocols/eth: fix announced tx size wrt type byte Co-authored-by: MariusVanDerWijden <m.vanderwijden@live.de> Co-authored-by: Péter Szilágyi <peterke@gmail.com> Conflicts: eth/handler_eth_test.go eth/protocols/eth/handler.go eth/protocols/eth/protocol.go
1 parent d086022 commit f633a27

File tree

10 files changed

+179
-46
lines changed

10 files changed

+179
-46
lines changed

cmd/devp2p/internal/ethtest/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ type NewBlock eth.NewBlockPacket
111111
func (nb NewBlock) Code() int { return 23 }
112112

113113
// NewPooledTransactionHashes is the network packet for the tx hash propagation message.
114-
type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket
114+
type NewPooledTransactionHashes eth.NewPooledTransactionHashesPacket66
115115

116116
func (nb NewPooledTransactionHashes) Code() int { return 24 }
117117

eth/handler_eth.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,12 @@ func (h *ethHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
9090
case *eth.NewBlockPacket:
9191
return h.handleBlockBroadcast(peer, packet.Block, packet.TD)
9292

93-
case *eth.NewPooledTransactionHashesPacket:
93+
case *eth.NewPooledTransactionHashesPacket66:
9494
return h.txFetcher.Notify(peer.ID(), *packet)
9595

96+
case *eth.NewPooledTransactionHashesPacket68:
97+
return h.txFetcher.Notify(peer.ID(), packet.Hashes)
98+
9699
case *eth.TransactionsPacket:
97100
return h.txFetcher.Enqueue(peer.ID(), *packet, false)
98101

eth/handler_eth_test.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2014 The go-ethereum Authors
1+
// Copyright 2020 The go-ethereum Authors
22
// This file is part of the go-ethereum library.
33
//
44
// The go-ethereum library is free software: you can redistribute it and/or modify
@@ -61,10 +61,14 @@ func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
6161
h.blockBroadcasts.Send(packet.Block)
6262
return nil
6363

64-
case *eth.NewPooledTransactionHashesPacket:
64+
case *eth.NewPooledTransactionHashesPacket66:
6565
h.txAnnounces.Send(([]common.Hash)(*packet))
6666
return nil
6767

68+
case *eth.NewPooledTransactionHashesPacket68:
69+
h.txAnnounces.Send(packet.Hashes)
70+
return nil
71+
6872
case *eth.TransactionsPacket:
6973
h.txBroadcasts.Send(([]*types.Transaction)(*packet))
7074
return nil
@@ -81,6 +85,8 @@ func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
8185
// Tests that peers are correctly accepted (or rejected) based on the advertised
8286
// fork IDs in the protocol handshake.
8387
func TestForkIDSplit66(t *testing.T) { testForkIDSplit(t, eth.ETH66) }
88+
func TestForkIDSplit67(t *testing.T) { testForkIDSplit(t, eth.ETH67) }
89+
func TestForkIDSplit68(t *testing.T) { testForkIDSplit(t, eth.ETH68) }
8490

8591
func testForkIDSplit(t *testing.T, protocol uint) {
8692
t.Parallel()
@@ -236,6 +242,8 @@ func testForkIDSplit(t *testing.T, protocol uint) {
236242

237243
// Tests that received transactions are added to the local pool.
238244
func TestRecvTransactions66(t *testing.T) { testRecvTransactions(t, eth.ETH66) }
245+
func TestRecvTransactions67(t *testing.T) { testRecvTransactions(t, eth.ETH67) }
246+
func TestRecvTransactions68(t *testing.T) { testRecvTransactions(t, eth.ETH68) }
239247

240248
func testRecvTransactions(t *testing.T, protocol uint) {
241249
t.Parallel()
@@ -293,6 +301,8 @@ func testRecvTransactions(t *testing.T, protocol uint) {
293301

294302
// This test checks that pending transactions are sent.
295303
func TestSendTransactions66(t *testing.T) { testSendTransactions(t, eth.ETH66) }
304+
func TestSendTransactions67(t *testing.T) { testSendTransactions(t, eth.ETH67) }
305+
func TestSendTransactions68(t *testing.T) { testSendTransactions(t, eth.ETH68) }
296306

297307
func testSendTransactions(t *testing.T, protocol uint) {
298308
t.Parallel()
@@ -351,7 +361,7 @@ func testSendTransactions(t *testing.T, protocol uint) {
351361
seen := make(map[common.Hash]struct{})
352362
for len(seen) < len(insert) {
353363
switch protocol {
354-
case 65, 66:
364+
case 65, 66, 67, 68:
355365
select {
356366
case hashes := <-anns:
357367
for _, hash := range hashes {
@@ -378,6 +388,8 @@ func testSendTransactions(t *testing.T, protocol uint) {
378388
// Tests that transactions get propagated to all attached peers, either via direct
379389
// broadcasts or via announcements/retrievals.
380390
func TestTransactionPropagation66(t *testing.T) { testTransactionPropagation(t, eth.ETH66) }
391+
func TestTransactionPropagation67(t *testing.T) { testTransactionPropagation(t, eth.ETH67) }
392+
func TestTransactionPropagation68(t *testing.T) { testTransactionPropagation(t, eth.ETH68) }
381393

382394
func testTransactionPropagation(t *testing.T, protocol uint) {
383395
t.Parallel()
@@ -435,12 +447,13 @@ func testTransactionPropagation(t *testing.T, protocol uint) {
435447

436448
// Iterate through all the sinks and ensure they all got the transactions
437449
for i := range sinks {
438-
for arrived := 0; arrived < len(txs); {
450+
for arrived, timeout := 0, false; arrived < len(txs) && !timeout; {
439451
select {
440452
case event := <-txChs[i]:
441453
arrived += len(event.Txs)
442-
case <-time.NewTimer(time.Second).C:
454+
case <-time.After(time.Second):
443455
t.Errorf("sink %d: transaction propagation timed out: have %d, want %d", i, arrived, len(txs))
456+
timeout = true
444457
}
445458
}
446459
}
@@ -486,7 +499,6 @@ func TestCheckpointChallenge(t *testing.T) {
486499
}
487500

488501
func testCheckpointChallenge(t *testing.T, syncmode downloader.SyncMode, checkpoint bool, timeout bool, empty bool, match bool, drop bool) {
489-
490502
// Reduce the checkpoint handshake challenge timeout
491503
defer func(old time.Duration) { syncChallengeTimeout = old }(syncChallengeTimeout)
492504
syncChallengeTimeout = 250 * time.Millisecond
@@ -676,6 +688,8 @@ func testBroadcastBlock(t *testing.T, peers, bcasts int) {
676688
// Tests that a propagated malformed block (uncles or transactions don't match
677689
// with the hashes in the header) gets discarded and not broadcast forward.
678690
func TestBroadcastMalformedBlock66(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH66) }
691+
func TestBroadcastMalformedBlock67(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH67) }
692+
func TestBroadcastMalformedBlock68(t *testing.T) { testBroadcastMalformedBlock(t, eth.ETH68) }
679693

680694
func testBroadcastMalformedBlock(t *testing.T, protocol uint) {
681695
t.Parallel()

eth/protocols/eth/broadcast.go

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,17 @@ func (p *Peer) announceTransactions() {
142142
if done == nil && len(queue) > 0 {
143143
// Pile transaction hashes until we reach our allowed network limit
144144
var (
145-
count int
146-
pending []common.Hash
147-
size common.StorageSize
145+
count int
146+
pending []common.Hash
147+
pendingTypes []byte
148+
pendingSizes []uint32
149+
size common.StorageSize
148150
)
149151
for count = 0; count < len(queue) && size < maxTxPacketSize; count++ {
150-
if p.txpool.Get(queue[count]) != nil {
152+
if tx := p.txpool.Get(queue[count]); tx != nil {
151153
pending = append(pending, queue[count])
154+
pendingTypes = append(pendingTypes, tx.Type())
155+
pendingSizes = append(pendingSizes, uint32(tx.Size()))
152156
size += common.HashLength
153157
}
154158
}
@@ -159,9 +163,16 @@ func (p *Peer) announceTransactions() {
159163
if len(pending) > 0 {
160164
done = make(chan struct{})
161165
go func() {
162-
if err := p.sendPooledTransactionHashes(pending); err != nil {
163-
fail <- err
164-
return
166+
if p.version >= ETH68 {
167+
if err := p.sendPooledTransactionHashes68(pending, pendingTypes, pendingSizes); err != nil {
168+
fail <- err
169+
return
170+
}
171+
} else {
172+
if err := p.sendPooledTransactionHashes66(pending); err != nil {
173+
fail <- err
174+
return
175+
}
165176
}
166177
close(done)
167178
p.Log().Trace("Sent transaction announcements", "count", len(pending))

eth/protocols/eth/handler.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ type Backend interface {
9696

9797
// TxPool defines the methods needed by the protocol handler to serve transactions.
9898
type TxPool interface {
99-
// Get retrieves the the transaction from the local txpool with the given hash.
99+
// Get retrieves the transaction from the local txpool with the given hash.
100100
Get(hash common.Hash) *types.Transaction
101101
}
102102

@@ -175,7 +175,7 @@ var eth66 = map[uint64]msgHandler{
175175
NewBlockHashesMsg: handleNewBlockhashes,
176176
NewBlockMsg: handleNewBlock,
177177
TransactionsMsg: handleTransactions,
178-
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes,
178+
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes66,
179179
GetBlockHeadersMsg: handleGetBlockHeaders66,
180180
BlockHeadersMsg: handleBlockHeaders66,
181181
GetBlockBodiesMsg: handleGetBlockBodies66,
@@ -188,6 +188,36 @@ var eth66 = map[uint64]msgHandler{
188188
PooledTransactionsMsg: handlePooledTransactions66,
189189
}
190190

191+
var eth67 = map[uint64]msgHandler{
192+
NewBlockHashesMsg: handleNewBlockhashes,
193+
NewBlockMsg: handleNewBlock,
194+
TransactionsMsg: handleTransactions,
195+
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes66,
196+
GetBlockHeadersMsg: handleGetBlockHeaders66,
197+
BlockHeadersMsg: handleBlockHeaders66,
198+
GetBlockBodiesMsg: handleGetBlockBodies66,
199+
BlockBodiesMsg: handleBlockBodies66,
200+
GetReceiptsMsg: handleGetReceipts66,
201+
ReceiptsMsg: handleReceipts66,
202+
GetPooledTransactionsMsg: handleGetPooledTransactions66,
203+
PooledTransactionsMsg: handlePooledTransactions66,
204+
}
205+
206+
var eth68 = map[uint64]msgHandler{
207+
NewBlockHashesMsg: handleNewBlockhashes,
208+
NewBlockMsg: handleNewBlock,
209+
TransactionsMsg: handleTransactions,
210+
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes68,
211+
GetBlockHeadersMsg: handleGetBlockHeaders66,
212+
BlockHeadersMsg: handleBlockHeaders66,
213+
GetBlockBodiesMsg: handleGetBlockBodies66,
214+
BlockBodiesMsg: handleBlockBodies66,
215+
GetReceiptsMsg: handleGetReceipts66,
216+
ReceiptsMsg: handleReceipts66,
217+
GetPooledTransactionsMsg: handleGetPooledTransactions66,
218+
PooledTransactionsMsg: handlePooledTransactions66,
219+
}
220+
191221
// handleMessage is invoked whenever an inbound message is received from a remote
192222
// peer. The remote connection is torn down upon returning any error.
193223
func handleMessage(backend Backend, peer *Peer) error {
@@ -202,9 +232,12 @@ func handleMessage(backend Backend, peer *Peer) error {
202232
defer msg.Discard()
203233

204234
var handlers = eth66
205-
//if peer.Version() >= ETH67 { // Left in as a sample when new protocol is added
206-
// handlers = eth67
207-
//}
235+
if peer.Version() == ETH67 {
236+
handlers = eth67
237+
}
238+
if peer.Version() >= ETH68 {
239+
handlers = eth68
240+
}
208241

209242
// Track the amount of time it takes to serve the request and run the handler
210243
if metrics.Enabled {

eth/protocols/eth/handler_test.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ func (b *testBackend) Handle(*Peer, Packet) error {
111111

112112
// Tests that block headers can be retrieved from a remote chain based on user queries.
113113
func TestGetBlockHeaders66(t *testing.T) { testGetBlockHeaders(t, ETH66) }
114+
func TestGetBlockHeaders67(t *testing.T) { testGetBlockHeaders(t, ETH67) }
115+
func TestGetBlockHeaders68(t *testing.T) { testGetBlockHeaders(t, ETH68) }
114116

115117
func testGetBlockHeaders(t *testing.T, protocol uint) {
116118
t.Parallel()
@@ -291,6 +293,8 @@ func testGetBlockHeaders(t *testing.T, protocol uint) {
291293

292294
// Tests that block contents can be retrieved from a remote chain based on their hashes.
293295
func TestGetBlockBodies66(t *testing.T) { testGetBlockBodies(t, ETH66) }
296+
func TestGetBlockBodies67(t *testing.T) { testGetBlockBodies(t, ETH67) }
297+
func TestGetBlockBodies68(t *testing.T) { testGetBlockBodies(t, ETH68) }
294298

295299
func testGetBlockBodies(t *testing.T, protocol uint) {
296300
t.Parallel()
@@ -373,9 +377,11 @@ func testGetBlockBodies(t *testing.T, protocol uint) {
373377
}
374378

375379
// Tests that the state trie nodes can be retrieved based on hashes.
376-
func TestGetNodeData66(t *testing.T) { testGetNodeData(t, ETH66) }
380+
func TestGetNodeData66(t *testing.T) { testGetNodeData(t, ETH66, false) }
381+
func TestGetNodeData67(t *testing.T) { testGetNodeData(t, ETH67, true) }
382+
func TestGetNodeData68(t *testing.T) { testGetNodeData(t, ETH68, true) }
377383

378-
func testGetNodeData(t *testing.T, protocol uint) {
384+
func testGetNodeData(t *testing.T, protocol uint, drop bool) {
379385
t.Parallel()
380386

381387
// Define three accounts to simulate transactions with
@@ -436,8 +442,15 @@ func testGetNodeData(t *testing.T, protocol uint) {
436442
GetNodeDataPacket: hashes,
437443
})
438444
msg, err := peer.app.ReadMsg()
439-
if err != nil {
440-
t.Fatalf("failed to read node data response: %v", err)
445+
if !drop {
446+
if err != nil {
447+
t.Fatalf("failed to read node data response: %v", err)
448+
}
449+
} else {
450+
if err != nil {
451+
return
452+
}
453+
t.Fatalf("succeeded to read node data response on non-supporting protocol: %v", msg)
441454
}
442455
if msg.Code != NodeDataMsg {
443456
t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, NodeDataMsg)
@@ -483,6 +496,8 @@ func testGetNodeData(t *testing.T, protocol uint) {
483496

484497
// Tests that the transaction receipts can be retrieved based on hashes.
485498
func TestGetBlockReceipts66(t *testing.T) { testGetBlockReceipts(t, ETH66) }
499+
func TestGetBlockReceipts67(t *testing.T) { testGetBlockReceipts(t, ETH67) }
500+
func TestGetBlockReceipts68(t *testing.T) { testGetBlockReceipts(t, ETH68) }
486501

487502
func testGetBlockReceipts(t *testing.T, protocol uint) {
488503
t.Parallel()

eth/protocols/eth/handlers.go

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,13 +315,13 @@ func handleReceipts66(backend Backend, msg Decoder, peer *Peer) error {
315315
return backend.Handle(peer, &res.ReceiptsPacket)
316316
}
317317

318-
func handleNewPooledTransactionHashes(backend Backend, msg Decoder, peer *Peer) error {
318+
func handleNewPooledTransactionHashes66(backend Backend, msg Decoder, peer *Peer) error {
319319
// New transaction announcement arrived, make sure we have
320320
// a valid and fresh chain to handle them
321321
if !backend.AcceptTxs() {
322322
return nil
323323
}
324-
ann := new(NewPooledTransactionHashesPacket)
324+
ann := new(NewPooledTransactionHashesPacket66)
325325
if err := msg.Decode(ann); err != nil {
326326
return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
327327
}
@@ -332,6 +332,26 @@ func handleNewPooledTransactionHashes(backend Backend, msg Decoder, peer *Peer)
332332
return backend.Handle(peer, ann)
333333
}
334334

335+
func handleNewPooledTransactionHashes68(backend Backend, msg Decoder, peer *Peer) error {
336+
// New transaction announcement arrived, make sure we have
337+
// a valid and fresh chain to handle them
338+
if !backend.AcceptTxs() {
339+
return nil
340+
}
341+
ann := new(NewPooledTransactionHashesPacket68)
342+
if err := msg.Decode(ann); err != nil {
343+
return fmt.Errorf("%w: message %v: %v", errDecode, msg, err)
344+
}
345+
if len(ann.Hashes) != len(ann.Types) || len(ann.Hashes) != len(ann.Sizes) {
346+
return fmt.Errorf("%w: message %v: invalid len of fields: %v %v %v", errDecode, msg, len(ann.Hashes), len(ann.Types), len(ann.Sizes))
347+
}
348+
// Schedule all the unknown hashes for retrieval
349+
for _, hash := range ann.Hashes {
350+
peer.markTransaction(hash)
351+
}
352+
return backend.Handle(peer, ann)
353+
}
354+
335355
func handleGetPooledTransactions66(backend Backend, msg Decoder, peer *Peer) error {
336356
// Decode the pooled transactions retrieval message
337357
var query GetPooledTransactionsPacket66

eth/protocols/eth/peer.go

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,29 @@ func (p *Peer) AsyncSendTransactions(hashes []common.Hash) {
203203
}
204204
}
205205

206-
// sendPooledTransactionHashes sends transaction hashes to the peer and includes
206+
// sendPooledTransactionHashes66 sends transaction hashes to the peer and includes
207207
// them in its transaction hash set for future reference.
208208
//
209209
// This method is a helper used by the async transaction announcer. Don't call it
210210
// directly as the queueing (memory) and transmission (bandwidth) costs should
211211
// not be managed directly.
212-
func (p *Peer) sendPooledTransactionHashes(hashes []common.Hash) error {
212+
func (p *Peer) sendPooledTransactionHashes66(hashes []common.Hash) error {
213213
// Mark all the transactions as known, but ensure we don't overflow our limits
214214
p.knownTxs.Add(hashes...)
215-
return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket(hashes))
215+
return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket66(hashes))
216+
}
217+
218+
// sendPooledTransactionHashes68 sends transaction hashes (tagged with their type
219+
// and size) to the peer and includes them in its transaction hash set for future
220+
// reference.
221+
//
222+
// This method is a helper used by the async transaction announcer. Don't call it
223+
// directly as the queueing (memory) and transmission (bandwidth) costs should
224+
// not be managed directly.
225+
func (p *Peer) sendPooledTransactionHashes68(hashes []common.Hash, types []byte, sizes []uint32) error {
226+
// Mark all the transactions as known, but ensure we don't overflow our limits
227+
p.knownTxs.Add(hashes...)
228+
return p2p.Send(p.rw, NewPooledTransactionHashesMsg, NewPooledTransactionHashesPacket68{Types: types, Sizes: sizes, Hashes: hashes})
216229
}
217230

218231
// AsyncSendPooledTransactionHashes queues a list of transactions hashes to eventually

eth/protocols/eth/peer_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ func newTestPeer(name string, version uint, backend Backend) (*testPeer, <-chan
4848
peer := NewPeer(version, p2p.NewPeer(id, name, nil), net, backend.TxPool())
4949
errc := make(chan error, 1)
5050
go func() {
51+
defer app.Close()
52+
5153
errc <- backend.RunPeer(peer, func(peer *Peer) error {
5254
return Handle(backend, peer)
5355
})

0 commit comments

Comments
 (0)