eth/protocols/eth: drop protocol version eth/68 (#33511)
Some checks failed
/ Keeper Build (push) Has been cancelled
/ Linux Build (push) Has been cancelled
/ Linux Build (arm) (push) Has been cancelled
/ Windows Build (push) Has been cancelled
/ Docker Image (push) Has been cancelled

With this, we are dropping support for protocol version eth/68. The only supported
version is eth/69 now. The p2p receipt encoding logic can be simplified a lot, and
processing of receipts during sync gets a little faster because we now transform
the network encoding into the database encoding directly, without decoding the
receipts first.

---------

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Bosul Mun 2026-03-01 05:43:40 +09:00 committed by GitHub
parent cee751a1ed
commit 723aae2b4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 206 additions and 706 deletions

View file

@ -155,7 +155,7 @@ func (c *Conn) ReadEth() (any, error) {
var msg any var msg any
switch int(code) { switch int(code) {
case eth.StatusMsg: case eth.StatusMsg:
msg = new(eth.StatusPacket69) msg = new(eth.StatusPacket)
case eth.GetBlockHeadersMsg: case eth.GetBlockHeadersMsg:
msg = new(eth.GetBlockHeadersPacket) msg = new(eth.GetBlockHeadersPacket)
case eth.BlockHeadersMsg: case eth.BlockHeadersMsg:
@ -164,10 +164,6 @@ func (c *Conn) ReadEth() (any, error) {
msg = new(eth.GetBlockBodiesPacket) msg = new(eth.GetBlockBodiesPacket)
case eth.BlockBodiesMsg: case eth.BlockBodiesMsg:
msg = new(eth.BlockBodiesPacket) msg = new(eth.BlockBodiesPacket)
case eth.NewBlockMsg:
msg = new(eth.NewBlockPacket)
case eth.NewBlockHashesMsg:
msg = new(eth.NewBlockHashesPacket)
case eth.TransactionsMsg: case eth.TransactionsMsg:
msg = new(eth.TransactionsPacket) msg = new(eth.TransactionsPacket)
case eth.NewPooledTransactionHashesMsg: case eth.NewPooledTransactionHashesMsg:
@ -229,7 +225,7 @@ func (c *Conn) ReadSnap() (any, error) {
} }
// dialAndPeer creates a peer connection and runs the handshake. // dialAndPeer creates a peer connection and runs the handshake.
func (s *Suite) dialAndPeer(status *eth.StatusPacket69) (*Conn, error) { func (s *Suite) dialAndPeer(status *eth.StatusPacket) (*Conn, error) {
c, err := s.dial() c, err := s.dial()
if err != nil { if err != nil {
return nil, err return nil, err
@ -242,7 +238,7 @@ func (s *Suite) dialAndPeer(status *eth.StatusPacket69) (*Conn, error) {
// peer performs both the protocol handshake and the status message // peer performs both the protocol handshake and the status message
// exchange with the node in order to peer with it. // exchange with the node in order to peer with it.
func (c *Conn) peer(chain *Chain, status *eth.StatusPacket69) error { func (c *Conn) peer(chain *Chain, status *eth.StatusPacket) error {
if err := c.handshake(); err != nil { if err := c.handshake(); err != nil {
return fmt.Errorf("handshake failed: %v", err) return fmt.Errorf("handshake failed: %v", err)
} }
@ -315,7 +311,7 @@ func (c *Conn) negotiateEthProtocol(caps []p2p.Cap) {
} }
// statusExchange performs a `Status` message exchange with the given node. // statusExchange performs a `Status` message exchange with the given node.
func (c *Conn) statusExchange(chain *Chain, status *eth.StatusPacket69) error { func (c *Conn) statusExchange(chain *Chain, status *eth.StatusPacket) error {
loop: loop:
for { for {
code, data, err := c.Read() code, data, err := c.Read()
@ -324,7 +320,7 @@ loop:
} }
switch code { switch code {
case eth.StatusMsg + protoOffset(ethProto): case eth.StatusMsg + protoOffset(ethProto):
msg := new(eth.StatusPacket69) msg := new(eth.StatusPacket)
if err := rlp.DecodeBytes(data, &msg); err != nil { if err := rlp.DecodeBytes(data, &msg); err != nil {
return fmt.Errorf("error decoding status packet: %w", err) return fmt.Errorf("error decoding status packet: %w", err)
} }
@ -363,7 +359,7 @@ loop:
} }
if status == nil { if status == nil {
// default status message // default status message
status = &eth.StatusPacket69{ status = &eth.StatusPacket{
ProtocolVersion: uint32(c.negotiatedProtoVersion), ProtocolVersion: uint32(c.negotiatedProtoVersion),
NetworkID: chain.config.ChainID.Uint64(), NetworkID: chain.config.ChainID.Uint64(),
Genesis: chain.blocks[0].Hash(), Genesis: chain.blocks[0].Hash(),

View file

@ -447,7 +447,7 @@ func (s *Suite) TestGetReceipts(t *utesting.T) {
t.Fatalf("could not write to connection: %v", err) t.Fatalf("could not write to connection: %v", err)
} }
// Wait for response. // Wait for response.
resp := new(eth.ReceiptsPacket[*eth.ReceiptList69]) resp := new(eth.ReceiptsPacket)
if err := conn.ReadMsg(ethProto, eth.ReceiptsMsg, &resp); err != nil { if err := conn.ReadMsg(ethProto, eth.ReceiptsMsg, &resp); err != nil {
t.Fatalf("error reading block bodies msg: %v", err) t.Fatalf("error reading block bodies msg: %v", err)
} }

View file

@ -17,7 +17,6 @@
package downloader package downloader
import ( import (
"fmt"
"math/big" "math/big"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -261,23 +260,24 @@ func (dlp *downloadTesterPeer) RequestBodies(hashes []common.Hash, sink chan *et
// peer in the download tester. The returned function can be used to retrieve // peer in the download tester. The returned function can be used to retrieve
// batches of block receipts from the particularly requested peer. // batches of block receipts from the particularly requested peer.
func (dlp *downloadTesterPeer) RequestReceipts(hashes []common.Hash, sink chan *eth.Response) (*eth.Request, error) { func (dlp *downloadTesterPeer) RequestReceipts(hashes []common.Hash, sink chan *eth.Response) (*eth.Request, error) {
blobs := eth.ServiceGetReceiptsQuery68(dlp.chain, hashes) blobs := eth.ServiceGetReceiptsQuery(dlp.chain, hashes)
receipts := make([]types.Receipts, blobs.Len())
receipts := make([]types.Receipts, len(blobs)) // compute hashes
for i, blob := range blobs { hashes = make([]common.Hash, blobs.Len())
rlp.DecodeBytes(blob, &receipts[i])
}
hasher := trie.NewStackTrie(nil) hasher := trie.NewStackTrie(nil)
hashes = make([]common.Hash, len(receipts)) receiptLists, err := blobs.Items()
for i, receipt := range receipts { if err != nil {
hashes[i] = types.DeriveSha(receipt, hasher) panic(err)
} }
req := &eth.Request{ for i, rl := range receiptLists {
Peer: dlp.id, hashes[i] = types.DeriveSha(rl.Derivable(), hasher)
} }
// deliver the response right away
resp := eth.ReceiptsRLPResponse(types.EncodeBlockReceiptLists(receipts)) resp := eth.ReceiptsRLPResponse(types.EncodeBlockReceiptLists(receipts))
res := &eth.Response{ res := &eth.Response{
Req: req, Req: &eth.Request{Peer: dlp.id},
Res: &resp, Res: &resp,
Meta: hashes, Meta: hashes,
Time: 1, Time: 1,
@ -286,7 +286,7 @@ func (dlp *downloadTesterPeer) RequestReceipts(hashes []common.Hash, sink chan *
go func() { go func() {
sink <- res sink <- res
}() }()
return req, nil return res.Req, nil
} }
// ID retrieves the peer's unique identifier. // ID retrieves the peer's unique identifier.
@ -398,8 +398,8 @@ func assertOwnChain(t *testing.T, tester *downloadTester, length int) {
} }
} }
func TestCanonicalSynchronisation68Full(t *testing.T) { testCanonSync(t, eth.ETH68, FullSync) } func TestCanonicalSynchronisationFull(t *testing.T) { testCanonSync(t, eth.ETH69, FullSync) }
func TestCanonicalSynchronisation68Snap(t *testing.T) { testCanonSync(t, eth.ETH68, SnapSync) } func TestCanonicalSynchronisationSnap(t *testing.T) { testCanonSync(t, eth.ETH69, SnapSync) }
func testCanonSync(t *testing.T, protocol uint, mode SyncMode) { func testCanonSync(t *testing.T, protocol uint, mode SyncMode) {
success := make(chan struct{}) success := make(chan struct{})
@ -426,8 +426,8 @@ func testCanonSync(t *testing.T, protocol uint, mode SyncMode) {
// Tests that if a large batch of blocks are being downloaded, it is throttled // Tests that if a large batch of blocks are being downloaded, it is throttled
// until the cached blocks are retrieved. // until the cached blocks are retrieved.
func TestThrottling68Full(t *testing.T) { testThrottling(t, eth.ETH68, FullSync) } func TestThrottlingFull(t *testing.T) { testThrottling(t, eth.ETH69, FullSync) }
func TestThrottling68Snap(t *testing.T) { testThrottling(t, eth.ETH68, SnapSync) } func TestThrottlingSnap(t *testing.T) { testThrottling(t, eth.ETH69, SnapSync) }
func testThrottling(t *testing.T, protocol uint, mode SyncMode) { func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
tester := newTester(t, mode) tester := newTester(t, mode)
@ -504,8 +504,8 @@ func testThrottling(t *testing.T, protocol uint, mode SyncMode) {
} }
// Tests that a canceled download wipes all previously accumulated state. // Tests that a canceled download wipes all previously accumulated state.
func TestCancel68Full(t *testing.T) { testCancel(t, eth.ETH68, FullSync) } func TestCancelFull(t *testing.T) { testCancel(t, eth.ETH69, FullSync) }
func TestCancel68Snap(t *testing.T) { testCancel(t, eth.ETH68, SnapSync) } func TestCancelSnap(t *testing.T) { testCancel(t, eth.ETH69, SnapSync) }
func testCancel(t *testing.T, protocol uint, mode SyncMode) { func testCancel(t *testing.T, protocol uint, mode SyncMode) {
complete := make(chan struct{}) complete := make(chan struct{})
@ -534,49 +534,10 @@ func testCancel(t *testing.T, protocol uint, mode SyncMode) {
} }
} }
// Tests that synchronisations behave well in multi-version protocol environments
// and not wreak havoc on other nodes in the network.
func TestMultiProtoSynchronisation68Full(t *testing.T) { testMultiProtoSync(t, eth.ETH68, FullSync) }
func TestMultiProtoSynchronisation68Snap(t *testing.T) { testMultiProtoSync(t, eth.ETH68, SnapSync) }
func testMultiProtoSync(t *testing.T, protocol uint, mode SyncMode) {
complete := make(chan struct{})
success := func() {
close(complete)
}
tester := newTesterWithNotification(t, mode, success)
defer tester.terminate()
// Create a small enough block chain to download
chain := testChainBase.shorten(blockCacheMaxItems - 15)
// Create peers of every type
tester.newPeer("peer 68", eth.ETH68, chain.blocks[1:])
if err := tester.downloader.BeaconSync(chain.blocks[len(chain.blocks)-1].Header(), nil); err != nil {
t.Fatalf("failed to start beacon sync: %v", err)
}
select {
case <-complete:
break
case <-time.NewTimer(time.Second * 3).C:
t.Fatalf("Failed to sync chain in three seconds")
}
assertOwnChain(t, tester, len(chain.blocks))
// Check that no peers have been dropped off
for _, version := range []int{68} {
peer := fmt.Sprintf("peer %d", version)
if _, ok := tester.peers[peer]; !ok {
t.Errorf("%s dropped", peer)
}
}
}
// Tests that if a block is empty (e.g. header only), no body request should be // Tests that if a block is empty (e.g. header only), no body request should be
// made, and instead the header should be assembled into a whole block in itself. // made, and instead the header should be assembled into a whole block in itself.
func TestEmptyShortCircuit68Full(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, FullSync) } func TestEmptyShortCircuitFull(t *testing.T) { testEmptyShortCircuit(t, eth.ETH69, FullSync) }
func TestEmptyShortCircuit68Snap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH68, SnapSync) } func TestEmptyShortCircuitSnap(t *testing.T) { testEmptyShortCircuit(t, eth.ETH69, SnapSync) }
func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) { func testEmptyShortCircuit(t *testing.T, protocol uint, mode SyncMode) {
success := make(chan struct{}) success := make(chan struct{})
@ -644,8 +605,8 @@ func checkProgress(t *testing.T, d *Downloader, stage string, want ethereum.Sync
// Tests that peers below a pre-configured checkpoint block are prevented from // Tests that peers below a pre-configured checkpoint block are prevented from
// being fast-synced from, avoiding potential cheap eclipse attacks. // being fast-synced from, avoiding potential cheap eclipse attacks.
func TestBeaconSync68Full(t *testing.T) { testBeaconSync(t, eth.ETH68, FullSync) } func TestBeaconSyncFull(t *testing.T) { testBeaconSync(t, eth.ETH69, FullSync) }
func TestBeaconSync68Snap(t *testing.T) { testBeaconSync(t, eth.ETH68, SnapSync) } func TestBeaconSyncSnap(t *testing.T) { testBeaconSync(t, eth.ETH69, SnapSync) }
func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) { func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) {
var cases = []struct { var cases = []struct {
@ -690,8 +651,8 @@ func testBeaconSync(t *testing.T, protocol uint, mode SyncMode) {
// Tests that synchronisation progress (origin block number, current block number // Tests that synchronisation progress (origin block number, current block number
// and highest block number) is tracked and updated correctly. // and highest block number) is tracked and updated correctly.
func TestSyncProgress68Full(t *testing.T) { testSyncProgress(t, eth.ETH68, FullSync) } func TestSyncProgressFull(t *testing.T) { testSyncProgress(t, eth.ETH69, FullSync) }
func TestSyncProgress68Snap(t *testing.T) { testSyncProgress(t, eth.ETH68, SnapSync) } func TestSyncProgressSnap(t *testing.T) { testSyncProgress(t, eth.ETH69, SnapSync) }
func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) { func testSyncProgress(t *testing.T, protocol uint, mode SyncMode) {
success := make(chan struct{}) success := make(chan struct{})

View file

@ -845,7 +845,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
// Create a peer set to feed headers through // Create a peer set to feed headers through
peerset := newPeerSet() peerset := newPeerSet()
for _, peer := range tt.peers { for _, peer := range tt.peers {
peerset.Register(newPeerConnection(peer.id, eth.ETH68, peer, log.New("id", peer.id))) peerset.Register(newPeerConnection(peer.id, eth.ETH69, peer, log.New("id", peer.id)))
} }
// Create a peer dropper to track malicious peers // Create a peer dropper to track malicious peers
dropped := make(map[string]int) dropped := make(map[string]int)
@ -912,7 +912,7 @@ func TestSkeletonSyncRetrievals(t *testing.T) {
// Apply the post-init events if there's any // Apply the post-init events if there's any
endpeers := tt.peers endpeers := tt.peers
if tt.newPeer != nil { if tt.newPeer != nil {
if err := peerset.Register(newPeerConnection(tt.newPeer.id, eth.ETH68, tt.newPeer, log.New("id", tt.newPeer.id))); err != nil { if err := peerset.Register(newPeerConnection(tt.newPeer.id, eth.ETH69, tt.newPeer, log.New("id", tt.newPeer.id))); err != nil {
t.Errorf("test %d: failed to register new peer: %v", i, err) t.Errorf("test %d: failed to register new peer: %v", i, err)
} }
time.Sleep(time.Millisecond * 50) // given time for peer registration time.Sleep(time.Millisecond * 50) // given time for peer registration

View file

@ -38,9 +38,8 @@ import (
// testEthHandler is a mock event handler to listen for inbound network requests // testEthHandler is a mock event handler to listen for inbound network requests
// on the `eth` protocol and convert them into a more easily testable form. // on the `eth` protocol and convert them into a more easily testable form.
type testEthHandler struct { type testEthHandler struct {
blockBroadcasts event.Feed txAnnounces event.Feed
txAnnounces event.Feed txBroadcasts event.Feed
txBroadcasts event.Feed
} }
func (h *testEthHandler) Chain() *core.BlockChain { panic("no backing chain") } func (h *testEthHandler) Chain() *core.BlockChain { panic("no backing chain") }
@ -51,10 +50,6 @@ func (h *testEthHandler) PeerInfo(enode.ID) interface{} { panic("not used
func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error { func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
switch packet := packet.(type) { switch packet := packet.(type) {
case *eth.NewBlockPacket:
h.blockBroadcasts.Send(packet.Block)
return nil
case *eth.NewPooledTransactionHashesPacket: case *eth.NewPooledTransactionHashesPacket:
h.txAnnounces.Send(packet.Hashes) h.txAnnounces.Send(packet.Hashes)
return nil return nil
@ -82,7 +77,7 @@ func (h *testEthHandler) Handle(peer *eth.Peer, packet eth.Packet) error {
// Tests that peers are correctly accepted (or rejected) based on the advertised // Tests that peers are correctly accepted (or rejected) based on the advertised
// fork IDs in the protocol handshake. // fork IDs in the protocol handshake.
func TestForkIDSplit68(t *testing.T) { testForkIDSplit(t, eth.ETH68) } func TestForkIDSplit69(t *testing.T) { testForkIDSplit(t, eth.ETH69) }
func testForkIDSplit(t *testing.T, protocol uint) { func testForkIDSplit(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -234,7 +229,7 @@ func testForkIDSplit(t *testing.T, protocol uint) {
} }
// Tests that received transactions are added to the local pool. // Tests that received transactions are added to the local pool.
func TestRecvTransactions68(t *testing.T) { testRecvTransactions(t, eth.ETH68) } func TestRecvTransactions69(t *testing.T) { testRecvTransactions(t, eth.ETH69) }
func testRecvTransactions(t *testing.T, protocol uint) { func testRecvTransactions(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -263,7 +258,8 @@ func testRecvTransactions(t *testing.T, protocol uint) {
return eth.Handle((*ethHandler)(handler.handler), peer) return eth.Handle((*ethHandler)(handler.handler), peer)
}) })
// Run the handshake locally to avoid spinning up a source handler // Run the handshake locally to avoid spinning up a source handler
if err := src.Handshake(1, handler.chain, eth.BlockRangeUpdatePacket{}); err != nil { head := handler.chain.CurrentBlock()
if err := src.Handshake(1, handler.chain, eth.BlockRangeUpdatePacket{EarliestBlock: 0, LatestBlock: head.Number.Uint64(), LatestBlockHash: head.Hash()}); err != nil {
t.Fatalf("failed to run protocol handshake") t.Fatalf("failed to run protocol handshake")
} }
// Send the transaction to the sink and verify that it's added to the tx pool // Send the transaction to the sink and verify that it's added to the tx pool
@ -286,7 +282,7 @@ func testRecvTransactions(t *testing.T, protocol uint) {
} }
// This test checks that pending transactions are sent. // This test checks that pending transactions are sent.
func TestSendTransactions68(t *testing.T) { testSendTransactions(t, eth.ETH68) } func TestSendTransactions69(t *testing.T) { testSendTransactions(t, eth.ETH69) }
func testSendTransactions(t *testing.T, protocol uint) { func testSendTransactions(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -318,7 +314,8 @@ func testSendTransactions(t *testing.T, protocol uint) {
return eth.Handle((*ethHandler)(handler.handler), peer) return eth.Handle((*ethHandler)(handler.handler), peer)
}) })
// Run the handshake locally to avoid spinning up a source handler // Run the handshake locally to avoid spinning up a source handler
if err := sink.Handshake(1, handler.chain, eth.BlockRangeUpdatePacket{}); err != nil { head := handler.chain.CurrentBlock()
if err := sink.Handshake(1, handler.chain, eth.BlockRangeUpdatePacket{EarliestBlock: 0, LatestBlock: head.Number.Uint64(), LatestBlockHash: head.Hash()}); err != nil {
t.Fatalf("failed to run protocol handshake") t.Fatalf("failed to run protocol handshake")
} }
// After the handshake completes, the source handler should stream the sink // After the handshake completes, the source handler should stream the sink
@ -338,22 +335,16 @@ func testSendTransactions(t *testing.T, protocol uint) {
// Make sure we get all the transactions on the correct channels // Make sure we get all the transactions on the correct channels
seen := make(map[common.Hash]struct{}) seen := make(map[common.Hash]struct{})
for len(seen) < len(insert) { for len(seen) < len(insert) {
switch protocol { select {
case 68: case hashes := <-anns:
select { for _, hash := range hashes {
case hashes := <-anns: if _, ok := seen[hash]; ok {
for _, hash := range hashes { t.Errorf("duplicate transaction announced: %x", hash)
if _, ok := seen[hash]; ok {
t.Errorf("duplicate transaction announced: %x", hash)
}
seen[hash] = struct{}{}
} }
case <-bcasts: seen[hash] = struct{}{}
t.Errorf("initial tx broadcast received on post eth/66")
} }
case <-bcasts:
default: t.Errorf("initial tx broadcast received on post eth/66")
panic("unsupported protocol, please extend test")
} }
} }
for _, tx := range insert { for _, tx := range insert {
@ -365,7 +356,7 @@ func testSendTransactions(t *testing.T, protocol uint) {
// Tests that transactions get propagated to all attached peers, either via direct // Tests that transactions get propagated to all attached peers, either via direct
// broadcasts or via announcements/retrievals. // broadcasts or via announcements/retrievals.
func TestTransactionPropagation68(t *testing.T) { testTransactionPropagation(t, eth.ETH68) } func TestTransactionPropagation69(t *testing.T) { testTransactionPropagation(t, eth.ETH69) }
func testTransactionPropagation(t *testing.T, protocol uint) { func testTransactionPropagation(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()

View file

@ -166,21 +166,6 @@ type Decoder interface {
Time() time.Time Time() time.Time
} }
var eth68 = map[uint64]msgHandler{
NewBlockHashesMsg: handleNewBlockhashes,
NewBlockMsg: handleNewBlock,
TransactionsMsg: handleTransactions,
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes,
GetBlockHeadersMsg: handleGetBlockHeaders,
BlockHeadersMsg: handleBlockHeaders,
GetBlockBodiesMsg: handleGetBlockBodies,
BlockBodiesMsg: handleBlockBodies,
GetReceiptsMsg: handleGetReceipts68,
ReceiptsMsg: handleReceipts[*ReceiptList68],
GetPooledTransactionsMsg: handleGetPooledTransactions,
PooledTransactionsMsg: handlePooledTransactions,
}
var eth69 = map[uint64]msgHandler{ var eth69 = map[uint64]msgHandler{
TransactionsMsg: handleTransactions, TransactionsMsg: handleTransactions,
NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes, NewPooledTransactionHashesMsg: handleNewPooledTransactionHashes,
@ -188,8 +173,8 @@ var eth69 = map[uint64]msgHandler{
BlockHeadersMsg: handleBlockHeaders, BlockHeadersMsg: handleBlockHeaders,
GetBlockBodiesMsg: handleGetBlockBodies, GetBlockBodiesMsg: handleGetBlockBodies,
BlockBodiesMsg: handleBlockBodies, BlockBodiesMsg: handleBlockBodies,
GetReceiptsMsg: handleGetReceipts69, GetReceiptsMsg: handleGetReceipts,
ReceiptsMsg: handleReceipts[*ReceiptList69], ReceiptsMsg: handleReceipts,
GetPooledTransactionsMsg: handleGetPooledTransactions, GetPooledTransactionsMsg: handleGetPooledTransactions,
PooledTransactionsMsg: handlePooledTransactions, PooledTransactionsMsg: handlePooledTransactions,
BlockRangeUpdateMsg: handleBlockRangeUpdate, BlockRangeUpdateMsg: handleBlockRangeUpdate,
@ -209,9 +194,7 @@ func handleMessage(backend Backend, peer *Peer) error {
defer msg.Discard() defer msg.Discard()
var handlers map[uint64]msgHandler var handlers map[uint64]msgHandler
if peer.version == ETH68 { if peer.version == ETH69 {
handlers = eth68
} else if peer.version == ETH69 {
handlers = eth69 handlers = eth69
} else { } else {
return fmt.Errorf("unknown eth protocol version: %v", peer.version) return fmt.Errorf("unknown eth protocol version: %v", peer.version)

View file

@ -174,7 +174,7 @@ func (b *testBackend) Handle(*Peer, Packet) error {
} }
// Tests that block headers can be retrieved from a remote chain based on user queries. // Tests that block headers can be retrieved from a remote chain based on user queries.
func TestGetBlockHeaders68(t *testing.T) { testGetBlockHeaders(t, ETH68) } func TestGetBlockHeaders69(t *testing.T) { testGetBlockHeaders(t, ETH69) }
func testGetBlockHeaders(t *testing.T, protocol uint) { func testGetBlockHeaders(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -387,7 +387,7 @@ func testGetBlockHeaders(t *testing.T, protocol uint) {
} }
// Tests that block contents can be retrieved from a remote chain based on their hashes. // Tests that block contents can be retrieved from a remote chain based on their hashes.
func TestGetBlockBodies68(t *testing.T) { testGetBlockBodies(t, ETH68) } func TestGetBlockBodies69(t *testing.T) { testGetBlockBodies(t, ETH69) }
func testGetBlockBodies(t *testing.T, protocol uint) { func testGetBlockBodies(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -536,7 +536,7 @@ func TestHashBody(t *testing.T) {
} }
// Tests that the transaction receipts can be retrieved based on hashes. // Tests that the transaction receipts can be retrieved based on hashes.
func TestGetBlockReceipts68(t *testing.T) { testGetBlockReceipts(t, ETH68) } func TestGetBlockReceipts69(t *testing.T) { testGetBlockReceipts(t, ETH69) }
func testGetBlockReceipts(t *testing.T, protocol uint) { func testGetBlockReceipts(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -586,13 +586,13 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
// Collect the hashes to request, and the response to expect // Collect the hashes to request, and the response to expect
var ( var (
hashes []common.Hash hashes []common.Hash
receipts rlp.RawList[*ReceiptList68] receipts rlp.RawList[*ReceiptList]
) )
for i := uint64(0); i <= backend.chain.CurrentBlock().Number.Uint64(); i++ { for i := uint64(0); i <= backend.chain.CurrentBlock().Number.Uint64(); i++ {
block := backend.chain.GetBlockByNumber(i) block := backend.chain.GetBlockByNumber(i)
hashes = append(hashes, block.Hash()) hashes = append(hashes, block.Hash())
trs := backend.chain.GetReceiptsByHash(block.Hash()) br := backend.chain.GetReceiptsByHash(block.Hash())
receipts.Append(NewReceiptList68(trs)) receipts.Append(NewReceiptList(br))
} }
// Send the hash request and verify the response // Send the hash request and verify the response
@ -600,7 +600,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
RequestId: 123, RequestId: 123,
GetReceiptsRequest: hashes, GetReceiptsRequest: hashes,
}) })
if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, &ReceiptsPacket[*ReceiptList68]{ if err := p2p.ExpectMsg(peer.app, ReceiptsMsg, &ReceiptsPacket{
RequestId: 123, RequestId: 123,
List: receipts, List: receipts,
}); err != nil { }); err != nil {
@ -656,7 +656,7 @@ func setup() (*testBackend, *testPeer) {
} }
} }
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, false, gen) backend := newTestBackendWithGenerator(maxBodiesServe+15, true, false, gen)
peer, _ := newTestPeer("peer", ETH68, backend) peer, _ := newTestPeer("peer", ETH69, backend)
// Discard all messages // Discard all messages
go func() { go func() {
for { for {
@ -701,7 +701,7 @@ func testGetPooledTransaction(t *testing.T, blobTx bool) {
backend := newTestBackendWithGenerator(0, true, true, nil) backend := newTestBackendWithGenerator(0, true, true, nil)
defer backend.close() defer backend.close()
peer, _ := newTestPeer("peer", ETH68, backend) peer, _ := newTestPeer("peer", ETH69, backend)
defer peer.close() defer peer.close()
var ( var (

View file

@ -19,7 +19,6 @@ package eth
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"math" "math"
@ -247,36 +246,27 @@ func ServiceGetBlockBodiesQuery(chain *core.BlockChain, query GetBlockBodiesRequ
return bodies return bodies
} }
func handleGetReceipts68(backend Backend, msg Decoder, peer *Peer) error { func handleGetReceipts(backend Backend, msg Decoder, peer *Peer) error {
// Decode the block receipts retrieval message // Decode the block receipts retrieval message
var query GetReceiptsPacket var query GetReceiptsPacket
if err := msg.Decode(&query); err != nil { if err := msg.Decode(&query); err != nil {
return err return err
} }
response := ServiceGetReceiptsQuery68(backend.Chain(), query.GetReceiptsRequest) response := ServiceGetReceiptsQuery(backend.Chain(), query.GetReceiptsRequest)
return peer.ReplyReceiptsRLP(query.RequestId, response) return peer.ReplyReceiptsRLP(query.RequestId, response)
} }
func handleGetReceipts69(backend Backend, msg Decoder, peer *Peer) error { // ServiceGetReceiptsQuery assembles the response to a receipt query.
// Decode the block receipts retrieval message // It does not send the bloom filters for the receipts. It is exposed
var query GetReceiptsPacket // to allow external packages to test protocol behavior.
if err := msg.Decode(&query); err != nil { func ServiceGetReceiptsQuery(chain *core.BlockChain, query GetReceiptsRequest) rlp.RawList[*ReceiptList] {
return err
}
response := serviceGetReceiptsQuery69(backend.Chain(), query.GetReceiptsRequest)
return peer.ReplyReceiptsRLP(query.RequestId, response)
}
// ServiceGetReceiptsQuery68 assembles the response to a receipt query. It is
// exposed to allow external packages to test protocol behavior.
func ServiceGetReceiptsQuery68(chain *core.BlockChain, query GetReceiptsRequest) []rlp.RawValue {
// Gather state data until the fetch or network limits is reached // Gather state data until the fetch or network limits is reached
var ( var (
bytes int bytes int
receipts []rlp.RawValue receipts rlp.RawList[*ReceiptList]
) )
for lookups, hash := range query { for lookups, hash := range query {
if bytes >= softResponseLimit || len(receipts) >= maxReceiptsServe || if bytes >= softResponseLimit || receipts.Len() >= maxReceiptsServe ||
lookups >= 2*maxReceiptsServe { lookups >= 2*maxReceiptsServe {
break break
} }
@ -292,63 +282,18 @@ func ServiceGetReceiptsQuery68(chain *core.BlockChain, query GetReceiptsRequest)
continue continue
} }
var err error var err error
results, err = blockReceiptsToNetwork68(results, body) results, err = blockReceiptsToNetwork(results, body)
if err != nil { if err != nil {
log.Error("Error in block receipts conversion", "hash", hash, "err", err) log.Error("Error in block receipts conversion", "hash", hash, "err", err)
continue continue
} }
} }
receipts = append(receipts, results) receipts.AppendRaw(results)
bytes += len(results) bytes += len(results)
} }
return receipts return receipts
} }
// serviceGetReceiptsQuery69 assembles the response to a receipt query.
// It does not send the bloom filters for the receipts
func serviceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest) []rlp.RawValue {
// Gather state data until the fetch or network limits is reached
var (
bytes int
receipts []rlp.RawValue
)
for lookups, hash := range query {
if bytes >= softResponseLimit || len(receipts) >= maxReceiptsServe ||
lookups >= 2*maxReceiptsServe {
break
}
// Retrieve the requested block's receipts
results := chain.GetReceiptsRLP(hash)
if results == nil {
if header := chain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash {
continue
}
} else {
body := chain.GetBodyRLP(hash)
if body == nil {
continue
}
var err error
results, err = blockReceiptsToNetwork69(results, body)
if err != nil {
log.Error("Error in block receipts conversion", "hash", hash, "err", err)
continue
}
}
receipts = append(receipts, results)
bytes += len(results)
}
return receipts
}
func handleNewBlockhashes(backend Backend, msg Decoder, peer *Peer) error {
return errors.New("block announcements disallowed") // We dropped support for non-merge networks
}
func handleNewBlock(backend Backend, msg Decoder, peer *Peer) error {
return errors.New("block broadcasts disallowed") // We dropped support for non-merge networks
}
func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error { func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error {
// A batch of headers arrived to one of our previous requests // A batch of headers arrived to one of our previous requests
res := new(BlockHeadersPacket) res := new(BlockHeadersPacket)
@ -490,9 +435,9 @@ func writeTxForHash(tx []byte, buf *bytes.Buffer) {
} }
} }
func handleReceipts[L ReceiptsList](backend Backend, msg Decoder, peer *Peer) error { func handleReceipts(backend Backend, msg Decoder, peer *Peer) error {
// A batch of receipts arrived to one of our previous requests // A batch of receipts arrived to one of our previous requests
res := new(ReceiptsPacket[L]) res := new(ReceiptsPacket)
if err := msg.Decode(res); err != nil { if err := msg.Decode(res); err != nil {
return err return err
} }
@ -502,16 +447,10 @@ func handleReceipts[L ReceiptsList](backend Backend, msg Decoder, peer *Peer) er
return fmt.Errorf("Receipts: %w", err) return fmt.Errorf("Receipts: %w", err)
} }
// Assign temporary hashing buffer to each list item, the same buffer is shared
// between all receipt list instances.
receiptLists, err := res.List.Items() receiptLists, err := res.List.Items()
if err != nil { if err != nil {
return fmt.Errorf("Receipts: %w", err) return fmt.Errorf("Receipts: %w", err)
} }
buffers := new(receiptListBuffers)
for i := range receiptLists {
receiptLists[i].setBuffers(buffers)
}
metadata := func() interface{} { metadata := func() interface{} {
hasher := trie.NewStackTrie(nil) hasher := trie.NewStackTrie(nil)
@ -521,6 +460,7 @@ func handleReceipts[L ReceiptsList](backend Backend, msg Decoder, peer *Peer) er
} }
return hashes return hashes
} }
var enc ReceiptsRLPResponse var enc ReceiptsRLPResponse
for i := range receiptLists { for i := range receiptLists {
encReceipts, err := receiptLists[i].EncodeForStorage() encReceipts, err := receiptLists[i].EncodeForStorage()

View file

@ -36,62 +36,6 @@ const (
// Handshake executes the eth protocol handshake, negotiating version number, // Handshake executes the eth protocol handshake, negotiating version number,
// network IDs, difficulties, head and genesis blocks. // network IDs, difficulties, head and genesis blocks.
func (p *Peer) Handshake(networkID uint64, chain forkid.Blockchain, rangeMsg BlockRangeUpdatePacket) error { func (p *Peer) Handshake(networkID uint64, chain forkid.Blockchain, rangeMsg BlockRangeUpdatePacket) error {
switch p.version {
case ETH69:
return p.handshake69(networkID, chain, rangeMsg)
case ETH68:
return p.handshake68(networkID, chain)
default:
return errors.New("unsupported protocol version")
}
}
func (p *Peer) handshake68(networkID uint64, chain forkid.Blockchain) error {
var (
genesis = chain.Genesis()
latest = chain.CurrentHeader()
forkID = forkid.NewID(chain.Config(), genesis, latest.Number.Uint64(), latest.Time)
forkFilter = forkid.NewFilter(chain)
)
errc := make(chan error, 2)
go func() {
pkt := &StatusPacket68{
ProtocolVersion: uint32(p.version),
NetworkID: networkID,
Head: latest.Hash(),
Genesis: genesis.Hash(),
ForkID: forkID,
}
errc <- p2p.Send(p.rw, StatusMsg, pkt)
}()
var status StatusPacket68 // safe to read after two values have been received from errc
go func() {
errc <- p.readStatus68(networkID, &status, genesis.Hash(), forkFilter)
}()
return waitForHandshake(errc, p)
}
func (p *Peer) readStatus68(networkID uint64, status *StatusPacket68, genesis common.Hash, forkFilter forkid.Filter) error {
if err := p.readStatusMsg(status); err != nil {
return err
}
if status.NetworkID != networkID {
return fmt.Errorf("%w: %d (!= %d)", errNetworkIDMismatch, status.NetworkID, networkID)
}
if uint(status.ProtocolVersion) != p.version {
return fmt.Errorf("%w: %d (!= %d)", errProtocolVersionMismatch, status.ProtocolVersion, p.version)
}
if status.Genesis != genesis {
return fmt.Errorf("%w: %x (!= %x)", errGenesisMismatch, status.Genesis, genesis)
}
if err := forkFilter(status.ForkID); err != nil {
return fmt.Errorf("%w: %v", errForkIDRejected, err)
}
return nil
}
func (p *Peer) handshake69(networkID uint64, chain forkid.Blockchain, rangeMsg BlockRangeUpdatePacket) error {
var ( var (
genesis = chain.Genesis() genesis = chain.Genesis()
latest = chain.CurrentHeader() latest = chain.CurrentHeader()
@ -101,7 +45,7 @@ func (p *Peer) handshake69(networkID uint64, chain forkid.Blockchain, rangeMsg B
errc := make(chan error, 2) errc := make(chan error, 2)
go func() { go func() {
pkt := &StatusPacket69{ pkt := &StatusPacket{
ProtocolVersion: uint32(p.version), ProtocolVersion: uint32(p.version),
NetworkID: networkID, NetworkID: networkID,
Genesis: genesis.Hash(), Genesis: genesis.Hash(),
@ -112,15 +56,15 @@ func (p *Peer) handshake69(networkID uint64, chain forkid.Blockchain, rangeMsg B
} }
errc <- p2p.Send(p.rw, StatusMsg, pkt) errc <- p2p.Send(p.rw, StatusMsg, pkt)
}() }()
var status StatusPacket69 // safe to read after two values have been received from errc var status StatusPacket // safe to read after two values have been received from errc
go func() { go func() {
errc <- p.readStatus69(networkID, &status, genesis.Hash(), forkFilter) errc <- p.readStatus(networkID, &status, genesis.Hash(), forkFilter)
}() }()
return waitForHandshake(errc, p) return waitForHandshake(errc, p)
} }
func (p *Peer) readStatus69(networkID uint64, status *StatusPacket69, genesis common.Hash, forkFilter forkid.Filter) error { func (p *Peer) readStatus(networkID uint64, status *StatusPacket, genesis common.Hash, forkFilter forkid.Filter) error {
if err := p.readStatusMsg(status); err != nil { if err := p.readStatusMsg(status); err != nil {
return err return err
} }

View file

@ -18,7 +18,6 @@ package eth
import ( import (
"errors" "errors"
"math/big"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -28,7 +27,7 @@ import (
) )
// Tests that handshake failures are detected and reported correctly. // Tests that handshake failures are detected and reported correctly.
func TestHandshake68(t *testing.T) { testHandshake(t, ETH68) } func TestHandshake69(t *testing.T) { testHandshake(t, ETH69) }
func testHandshake(t *testing.T, protocol uint) { func testHandshake(t *testing.T, protocol uint) {
t.Parallel() t.Parallel()
@ -52,21 +51,25 @@ func testHandshake(t *testing.T, protocol uint) {
want: errNoStatusMsg, want: errNoStatusMsg,
}, },
{ {
code: StatusMsg, data: StatusPacket68{10, 1, new(big.Int), head.Hash(), genesis.Hash(), forkID}, code: StatusMsg, data: StatusPacket{10, 1, genesis.Hash(), forkID, 0, head.Number.Uint64(), head.Hash()},
want: errProtocolVersionMismatch, want: errProtocolVersionMismatch,
}, },
{ {
code: StatusMsg, data: StatusPacket68{uint32(protocol), 999, new(big.Int), head.Hash(), genesis.Hash(), forkID}, code: StatusMsg, data: StatusPacket{uint32(protocol), 999, genesis.Hash(), forkID, 0, head.Number.Uint64(), head.Hash()},
want: errNetworkIDMismatch, want: errNetworkIDMismatch,
}, },
{ {
code: StatusMsg, data: StatusPacket68{uint32(protocol), 1, new(big.Int), head.Hash(), common.Hash{3}, forkID}, code: StatusMsg, data: StatusPacket{uint32(protocol), 1, common.Hash{3}, forkID, 0, head.Number.Uint64(), head.Hash()},
want: errGenesisMismatch, want: errGenesisMismatch,
}, },
{ {
code: StatusMsg, data: StatusPacket68{uint32(protocol), 1, new(big.Int), head.Hash(), genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}}, code: StatusMsg, data: StatusPacket{uint32(protocol), 1, genesis.Hash(), forkid.ID{Hash: [4]byte{0x00, 0x01, 0x02, 0x03}}, 0, head.Number.Uint64(), head.Hash()},
want: errForkIDRejected, want: errForkIDRejected,
}, },
{
code: StatusMsg, data: StatusPacket{uint32(protocol), 1, genesis.Hash(), forkID, head.Number.Uint64() + 1, head.Number.Uint64(), head.Hash()},
want: errInvalidBlockRange,
},
} }
for i, test := range tests { for i, test := range tests {
// Create the two peers to shake with each other // Create the two peers to shake with each other

View file

@ -215,10 +215,10 @@ func (p *Peer) ReplyBlockBodiesRLP(id uint64, bodies []rlp.RawValue) error {
} }
// ReplyReceiptsRLP is the response to GetReceipts. // ReplyReceiptsRLP is the response to GetReceipts.
func (p *Peer) ReplyReceiptsRLP(id uint64, receipts []rlp.RawValue) error { func (p *Peer) ReplyReceiptsRLP(id uint64, receipts rlp.RawList[*ReceiptList]) error {
return p2p.Send(p.rw, ReceiptsMsg, &ReceiptsRLPPacket{ return p2p.Send(p.rw, ReceiptsMsg, &ReceiptsPacket{
RequestId: id, RequestId: id,
ReceiptsRLPResponse: receipts, List: receipts,
}) })
} }

View file

@ -20,7 +20,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/forkid" "github.com/ethereum/go-ethereum/core/forkid"
@ -30,7 +29,6 @@ import (
// Constants to match up protocol versions and messages // Constants to match up protocol versions and messages
const ( const (
ETH68 = 68
ETH69 = 69 ETH69 = 69
) )
@ -40,11 +38,11 @@ const ProtocolName = "eth"
// ProtocolVersions are the supported versions of the `eth` protocol (first // ProtocolVersions are the supported versions of the `eth` protocol (first
// is primary). // is primary).
var ProtocolVersions = []uint{ETH69, ETH68} var ProtocolVersions = []uint{ETH69}
// protocolLengths are the number of implemented message corresponding to // protocolLengths are the number of implemented message corresponding to
// different protocol versions. // different protocol versions.
var protocolLengths = map[uint]uint64{ETH68: 17, ETH69: 18} var protocolLengths = map[uint]uint64{ETH69: 18}
// maxMessageSize is the maximum cap on the size of a protocol message. // maxMessageSize is the maximum cap on the size of a protocol message.
const maxMessageSize = 10 * 1024 * 1024 const maxMessageSize = 10 * 1024 * 1024
@ -88,17 +86,7 @@ type Packet interface {
} }
// StatusPacket is the network packet for the status message. // StatusPacket is the network packet for the status message.
type StatusPacket68 struct { type StatusPacket struct {
ProtocolVersion uint32
NetworkID uint64
TD *big.Int
Head common.Hash
Genesis common.Hash
ForkID forkid.ID
}
// StatusPacket69 is the network packet for the status message.
type StatusPacket69 struct {
ProtocolVersion uint32 ProtocolVersion uint32
NetworkID uint64 NetworkID uint64
Genesis common.Hash Genesis common.Hash
@ -109,26 +97,6 @@ type StatusPacket69 struct {
LatestBlockHash common.Hash LatestBlockHash common.Hash
} }
// NewBlockHashesPacket is the network packet for the block announcements.
type NewBlockHashesPacket []struct {
Hash common.Hash // Hash of one particular block being announced
Number uint64 // Number of one particular block being announced
}
// Unpack retrieves the block hashes and numbers from the announcement packet
// and returns them in a split flat format that's more consistent with the
// internal data structures.
func (p *NewBlockHashesPacket) Unpack() ([]common.Hash, []uint64) {
var (
hashes = make([]common.Hash, len(*p))
numbers = make([]uint64, len(*p))
)
for i, body := range *p {
hashes[i], numbers[i] = body.Hash, body.Number
}
return hashes, numbers
}
// TransactionsPacket is the network packet for broadcasting new transactions. // TransactionsPacket is the network packet for broadcasting new transactions.
type TransactionsPacket struct { type TransactionsPacket struct {
rlp.RawList[*types.Transaction] rlp.RawList[*types.Transaction]
@ -203,12 +171,6 @@ type BlockHeadersRLPPacket struct {
BlockHeadersRLPResponse BlockHeadersRLPResponse
} }
// NewBlockPacket is the network packet for the block propagation message.
type NewBlockPacket struct {
Block *types.Block
TD *big.Int
}
// GetBlockBodiesRequest represents a block body query. // GetBlockBodiesRequest represents a block body query.
type GetBlockBodiesRequest []common.Hash type GetBlockBodiesRequest []common.Hash
@ -258,30 +220,16 @@ type GetReceiptsPacket struct {
// ReceiptsResponse is the network packet for block receipts distribution. // ReceiptsResponse is the network packet for block receipts distribution.
type ReceiptsResponse []types.Receipts type ReceiptsResponse []types.Receipts
// ReceiptsList is a type constraint for block receceipt list types.
type ReceiptsList interface {
*ReceiptList68 | *ReceiptList69
setBuffers(*receiptListBuffers)
EncodeForStorage() (rlp.RawValue, error)
Derivable() types.DerivableList
}
// ReceiptsPacket is the network packet for block receipts distribution with // ReceiptsPacket is the network packet for block receipts distribution with
// request ID wrapping. // request ID wrapping.
type ReceiptsPacket[L ReceiptsList] struct { type ReceiptsPacket struct {
RequestId uint64 RequestId uint64
List rlp.RawList[L] List rlp.RawList[*ReceiptList]
} }
// ReceiptsRLPResponse is used for receipts, when we already have it encoded // ReceiptsRLPResponse is used for receipts, when we already have it encoded
type ReceiptsRLPResponse []rlp.RawValue type ReceiptsRLPResponse []rlp.RawValue
// ReceiptsRLPPacket is ReceiptsRLPResponse with request ID wrapping.
type ReceiptsRLPPacket struct {
RequestId uint64
ReceiptsRLPResponse
}
// NewPooledTransactionHashesPacket represents a transaction announcement packet on eth/68 and newer. // NewPooledTransactionHashesPacket represents a transaction announcement packet on eth/68 and newer.
type NewPooledTransactionHashesPacket struct { type NewPooledTransactionHashesPacket struct {
Types []byte Types []byte
@ -325,14 +273,8 @@ type BlockRangeUpdatePacket struct {
LatestBlockHash common.Hash LatestBlockHash common.Hash
} }
func (*StatusPacket68) Name() string { return "Status" } func (*StatusPacket) Name() string { return "Status" }
func (*StatusPacket68) Kind() byte { return StatusMsg } func (*StatusPacket) Kind() byte { return StatusMsg }
func (*StatusPacket69) Name() string { return "Status" }
func (*StatusPacket69) Kind() byte { return StatusMsg }
func (*NewBlockHashesPacket) Name() string { return "NewBlockHashes" }
func (*NewBlockHashesPacket) Kind() byte { return NewBlockHashesMsg }
func (*TransactionsPacket) Name() string { return "Transactions" } func (*TransactionsPacket) Name() string { return "Transactions" }
func (*TransactionsPacket) Kind() byte { return TransactionsMsg } func (*TransactionsPacket) Kind() byte { return TransactionsMsg }
@ -349,9 +291,6 @@ func (*GetBlockBodiesRequest) Kind() byte { return GetBlockBodiesMsg }
func (*BlockBodiesResponse) Name() string { return "BlockBodies" } func (*BlockBodiesResponse) Name() string { return "BlockBodies" }
func (*BlockBodiesResponse) Kind() byte { return BlockBodiesMsg } func (*BlockBodiesResponse) Kind() byte { return BlockBodiesMsg }
func (*NewBlockPacket) Name() string { return "NewBlock" }
func (*NewBlockPacket) Kind() byte { return NewBlockMsg }
func (*NewPooledTransactionHashesPacket) Name() string { return "NewPooledTransactionHashes" } func (*NewPooledTransactionHashesPacket) Name() string { return "NewPooledTransactionHashes" }
func (*NewPooledTransactionHashesPacket) Kind() byte { return NewPooledTransactionHashesMsg } func (*NewPooledTransactionHashesPacket) Kind() byte { return NewPooledTransactionHashesMsg }

View file

@ -95,8 +95,7 @@ func TestEmptyMessages(t *testing.T) {
BlockBodiesRLPPacket{1111, BlockBodiesRLPResponse([]rlp.RawValue{})}, BlockBodiesRLPPacket{1111, BlockBodiesRLPResponse([]rlp.RawValue{})},
// Receipts // Receipts
GetReceiptsPacket{1111, GetReceiptsRequest([]common.Hash{})}, GetReceiptsPacket{1111, GetReceiptsRequest([]common.Hash{})},
ReceiptsPacket[*ReceiptList68]{1111, encodeRL([]*ReceiptList68{})}, ReceiptsPacket{1111, encodeRL([]*ReceiptList{})},
ReceiptsPacket[*ReceiptList69]{1111, encodeRL([]*ReceiptList69{})},
// Transactions // Transactions
GetPooledTransactionsPacket{1111, GetPooledTransactionsRequest([]common.Hash{})}, GetPooledTransactionsPacket{1111, GetPooledTransactionsRequest([]common.Hash{})},
PooledTransactionsPacket{1111, encodeRL([]*types.Transaction{})}, PooledTransactionsPacket{1111, encodeRL([]*types.Transaction{})},
@ -122,7 +121,6 @@ func TestMessages(t *testing.T) {
txRlps []rlp.RawValue txRlps []rlp.RawValue
hashes []common.Hash hashes []common.Hash
receipts []*types.Receipt receipts []*types.Receipt
receiptsRlp rlp.RawValue
err error err error
) )
@ -191,11 +189,6 @@ func TestMessages(t *testing.T) {
} }
miniDeriveFields(receipts[0], 0) miniDeriveFields(receipts[0], 0)
miniDeriveFields(receipts[1], 1) miniDeriveFields(receipts[1], 1)
rlpData, err := rlp.EncodeToBytes(receipts)
if err != nil {
t.Fatal(err)
}
receiptsRlp = rlpData
} }
for i, tc := range []struct { for i, tc := range []struct {
@ -231,16 +224,7 @@ func TestMessages(t *testing.T) {
common.FromHex("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"), common.FromHex("f847820457f842a000000000000000000000000000000000000000000000000000000000deadc0dea000000000000000000000000000000000000000000000000000000000feedbeef"),
}, },
{ {
ReceiptsPacket[*ReceiptList68]{1111, encodeRL([]*ReceiptList68{NewReceiptList68(receipts)})}, ReceiptsPacket{1111, encodeRL([]*ReceiptList{NewReceiptList(receipts)})},
common.FromHex("f902e6820457f902e0f902ddf901688082014db9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000004000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ffb9016f01f9016b018201bcb9010000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000000000000000000000000000000000000000000040000000000000000000000000004000000000000000000000000000000000000000000000000000000008000400000000000000000000000000000000000000000000000000000000000000000000000000000040f862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"),
},
{
// Identical to the eth/68 encoding above.
ReceiptsRLPPacket{1111, ReceiptsRLPResponse([]rlp.RawValue{receiptsRlp})},
common.FromHex("f902e6820457f902e0f902ddf901688082014db9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000004000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ffb9016f01f9016b018201bcb9010000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000001000000000000000000000000000000000000000000000000040000000000000000000000000004000000000000000000000000000000000000000000000000000000008000400000000000000000000000000000000000000000000000000000000000000000000000000000040f862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"),
},
{
ReceiptsPacket[*ReceiptList69]{1111, encodeRL([]*ReceiptList69{NewReceiptList69(receipts)})},
common.FromHex("f8da820457f8d5f8d3f866808082014df85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff86901018201bcf862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"), common.FromHex("f8da820457f8d5f8d3f866808082014df85ff85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff86901018201bcf862f860940000000000000000000000000000000000000022f842a00000000000000000000000000000000000000000000000000000000000005668a0000000000000000000000000000000000000000000000000000000000000977386020f0f0f0608"),
}, },
{ {

View file

@ -27,9 +27,6 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
// This is just a sanity limit for the size of a single receipt.
const maxReceiptSize = 16 * 1024 * 1024
// Receipt is the representation of receipts for networking purposes. // Receipt is the representation of receipts for networking purposes.
type Receipt struct { type Receipt struct {
TxType byte TxType byte
@ -49,154 +46,18 @@ func newReceipt(tr *types.Receipt) Receipt {
return r return r
} }
// decode68 parses a receipt in the eth/68 network encoding.
func (r *Receipt) decode68(b []byte) error {
k, content, _, err := rlp.Split(b)
if err != nil {
return err
}
*r = Receipt{}
if k == rlp.List {
// Legacy receipt.
return r.decodeInnerList(b, false, true)
}
// Typed receipt.
if len(content) < 2 || len(content) > maxReceiptSize {
return fmt.Errorf("invalid receipt size %d", len(content))
}
r.TxType = content[0]
return r.decodeInnerList(content[1:], false, true)
}
// decode69 parses a receipt in the eth/69 network encoding.
func (r *Receipt) decode69(b []byte) error {
*r = Receipt{}
return r.decodeInnerList(b, true, false)
}
// decodeDatabase parses a receipt in the basic database encoding.
func (r *Receipt) decodeDatabase(txType byte, b []byte) error {
*r = Receipt{TxType: txType}
return r.decodeInnerList(b, false, false)
}
func (r *Receipt) decodeInnerList(input []byte, readTxType, readBloom bool) error {
input, _, err := rlp.SplitList(input)
if err != nil {
return fmt.Errorf("inner list: %v", err)
}
// txType
if readTxType {
var txType uint64
txType, input, err = rlp.SplitUint64(input)
if err != nil {
return fmt.Errorf("invalid txType: %w", err)
}
if txType > 0x7f {
return fmt.Errorf("invalid txType: too large")
}
r.TxType = byte(txType)
}
// status
r.PostStateOrStatus, input, err = rlp.SplitString(input)
if err != nil {
return fmt.Errorf("invalid postStateOrStatus: %w", err)
}
if len(r.PostStateOrStatus) > 1 && len(r.PostStateOrStatus) != 32 {
return fmt.Errorf("invalid postStateOrStatus length %d", len(r.PostStateOrStatus))
}
// gas
r.GasUsed, input, err = rlp.SplitUint64(input)
if err != nil {
return fmt.Errorf("invalid gasUsed: %w", err)
}
// bloom
if readBloom {
var bloomBytes []byte
bloomBytes, input, err = rlp.SplitString(input)
if err != nil {
return fmt.Errorf("invalid bloom: %v", err)
}
if len(bloomBytes) != types.BloomByteLength {
return fmt.Errorf("invalid bloom length %d", len(bloomBytes))
}
}
// logs
_, rest, err := rlp.SplitList(input)
if err != nil {
return fmt.Errorf("invalid logs: %w", err)
}
if len(rest) != 0 {
return fmt.Errorf("junk at end of receipt")
}
r.Logs = input
return nil
}
// encodeForStorage produces the the storage encoding, i.e. the result matches
// the RLP encoding of types.ReceiptForStorage.
func (r *Receipt) encodeForStorage(w *rlp.EncoderBuffer) {
list := w.List()
w.WriteBytes(r.PostStateOrStatus)
w.WriteUint64(r.GasUsed)
w.Write(r.Logs)
w.ListEnd(list)
}
// encodeForNetwork68 produces the eth/68 network protocol encoding of a receipt.
// Note this recomputes the bloom filter of the receipt.
func (r *Receipt) encodeForNetwork68(buf *receiptListBuffers, w *rlp.EncoderBuffer) {
writeInner := func(w *rlp.EncoderBuffer) {
list := w.List()
w.WriteBytes(r.PostStateOrStatus)
w.WriteUint64(r.GasUsed)
bloom := r.bloom(&buf.bloom)
w.WriteBytes(bloom[:])
w.Write(r.Logs)
w.ListEnd(list)
}
if r.TxType == 0 {
writeInner(w)
} else {
buf.tmp.Reset()
buf.tmp.WriteByte(r.TxType)
buf.enc.Reset(&buf.tmp)
writeInner(&buf.enc)
buf.enc.Flush()
w.WriteBytes(buf.tmp.Bytes())
}
}
// encodeForNetwork69 produces the eth/69 network protocol encoding of a receipt.
func (r *Receipt) encodeForNetwork69(w *rlp.EncoderBuffer) {
list := w.List()
w.WriteUint64(uint64(r.TxType))
w.WriteBytes(r.PostStateOrStatus)
w.WriteUint64(r.GasUsed)
w.Write(r.Logs)
w.ListEnd(list)
}
// encodeForHash encodes a receipt for the block receiptsRoot derivation. // encodeForHash encodes a receipt for the block receiptsRoot derivation.
func (r *Receipt) encodeForHash(buf *receiptListBuffers, out *bytes.Buffer) { func (r *Receipt) encodeForHash(bloomBuf *[6]byte, out *bytes.Buffer) {
// For typed receipts, add the tx type. // For typed receipts, add the tx type.
if r.TxType != 0 { if r.TxType != 0 {
out.WriteByte(r.TxType) out.WriteByte(r.TxType)
} }
// Encode list = [postStateOrStatus, gasUsed, bloom, logs]. // Encode list = [postStateOrStatus, gasUsed, bloom, logs].
w := &buf.enc w := rlp.NewEncoderBuffer(out)
w.Reset(out)
l := w.List() l := w.List()
w.WriteBytes(r.PostStateOrStatus) w.WriteBytes(r.PostStateOrStatus)
w.WriteUint64(r.GasUsed) w.WriteUint64(r.GasUsed)
bloom := r.bloom(&buf.bloom) bloom := r.bloom(bloomBuf)
w.WriteBytes(bloom[:]) w.WriteBytes(bloom[:])
w.Write(r.Logs) w.Write(r.Logs)
w.ListEnd(l) w.ListEnd(l)
@ -229,31 +90,98 @@ func (r *Receipt) bloom(buffer *[6]byte) types.Bloom {
return b return b
} }
type receiptListBuffers struct { // decode assigns the fields of r by decoding the network format.
enc rlp.EncoderBuffer func (r *Receipt) decode(input []byte) error {
bloom [6]byte input, _, err := rlp.SplitList(input)
tmp bytes.Buffer if err != nil {
} return fmt.Errorf("inner list: %v", err)
func initBuffers(buf **receiptListBuffers) {
if *buf == nil {
*buf = new(receiptListBuffers)
} }
// txType
var txType uint64
txType, input, err = rlp.SplitUint64(input)
if err != nil {
return fmt.Errorf("invalid txType: %w", err)
}
if txType > 0x7f {
return fmt.Errorf("invalid txType: too large")
}
r.TxType = byte(txType)
// status
r.PostStateOrStatus, input, err = rlp.SplitString(input)
if err != nil {
return fmt.Errorf("invalid postStateOrStatus: %w", err)
}
if len(r.PostStateOrStatus) > 1 && len(r.PostStateOrStatus) != 32 {
return fmt.Errorf("invalid postStateOrStatus length %d", len(r.PostStateOrStatus))
}
// gas
r.GasUsed, input, err = rlp.SplitUint64(input)
if err != nil {
return fmt.Errorf("invalid gasUsed: %w", err)
}
// logs
_, rest, err := rlp.SplitList(input)
if err != nil {
return fmt.Errorf("invalid logs: %w", err)
}
if len(rest) != 0 {
return fmt.Errorf("junk at end of receipt")
}
r.Logs = input
return nil
} }
// encodeForStorage encodes a list of receipts for the database. // ReceiptList is the block receipt list as downloaded by eth/69.
func (buf *receiptListBuffers) encodeForStorage(rs rlp.RawList[Receipt], decode func([]byte, *Receipt) error) (rlp.RawValue, error) { type ReceiptList struct {
items rlp.RawList[Receipt]
}
// NewReceiptList creates a receipt list.
// This is slow, and exists for testing purposes.
func NewReceiptList(trs []*types.Receipt) *ReceiptList {
rl := new(ReceiptList)
for _, tr := range trs {
r := newReceipt(tr)
encoded, _ := rlp.EncodeToBytes(&r)
rl.items.AppendRaw(encoded)
}
return rl
}
// DecodeRLP decodes a list receipts from the network format.
func (rl *ReceiptList) DecodeRLP(s *rlp.Stream) error {
return rl.items.DecodeRLP(s)
}
// EncodeRLP encodes the list into the network format of eth/69.
func (rl *ReceiptList) EncodeRLP(w io.Writer) error {
return rl.items.EncodeRLP(w)
}
// EncodeForStorage encodes a list of receipts for the database.
// It only strips the first element (TxType) from each receipt's
// raw RLP without the actual decoding and re-encoding.
func (rl *ReceiptList) EncodeForStorage() (rlp.RawValue, error) {
var out bytes.Buffer var out bytes.Buffer
w := &buf.enc w := rlp.NewEncoderBuffer(&out)
w.Reset(&out)
outer := w.List() outer := w.List()
it := rs.ContentIterator() it := rl.items.ContentIterator()
for it.Next() { for it.Next() {
var receipt Receipt content, _, err := rlp.SplitList(it.Value())
if err := decode(it.Value(), &receipt); err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("bad receipt: %v", err)
} }
receipt.encodeForStorage(w) _, _, rest, err := rlp.Split(content)
if err != nil {
return nil, fmt.Errorf("bad receipt: %v", err)
}
inner := w.List()
w.Write(rest)
w.ListEnd(inner)
} }
if it.Err() != nil { if it.Err() != nil {
return nil, fmt.Errorf("bad list: %v", it.Err()) return nil, fmt.Errorf("bad list: %v", it.Err())
@ -263,149 +191,20 @@ func (buf *receiptListBuffers) encodeForStorage(rs rlp.RawList[Receipt], decode
return out.Bytes(), nil return out.Bytes(), nil
} }
// ReceiptList68 is a block receipt list as downloaded by eth/68. // Derivable returns a DerivableList, which can be used to decode
// This also implements types.DerivableList for validation purposes. func (rl *ReceiptList) Derivable() types.DerivableList {
type ReceiptList68 struct { var bloomBuf [6]byte
buf *receiptListBuffers
items rlp.RawList[Receipt]
}
// NewReceiptList68 creates a receipt list.
// This is slow, and exists for testing purposes.
func NewReceiptList68(trs []*types.Receipt) *ReceiptList68 {
rl := new(ReceiptList68)
initBuffers(&rl.buf)
enc := rlp.NewEncoderBuffer(nil)
for _, tr := range trs {
r := newReceipt(tr)
r.encodeForNetwork68(rl.buf, &enc)
rl.items.AppendRaw(enc.ToBytes())
enc.Reset(nil)
}
return rl
}
func blockReceiptsToNetwork68(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
txTypesIter, err := txTypesInBody(blockBody)
if err != nil {
return nil, fmt.Errorf("invalid block body: %v", err)
}
nextTxType, stopTxTypes := iter.Pull(txTypesIter)
defer stopTxTypes()
var (
out bytes.Buffer
buf receiptListBuffers
)
blockReceiptIter, _ := rlp.NewListIterator(blockReceipts)
w := rlp.NewEncoderBuffer(&out)
outer := w.List()
for i := 0; blockReceiptIter.Next(); i++ {
txType, _ := nextTxType()
var r Receipt
if err := r.decodeDatabase(txType, blockReceiptIter.Value()); err != nil {
return nil, fmt.Errorf("invalid database receipt %d: %v", i, err)
}
r.encodeForNetwork68(&buf, &w)
}
w.ListEnd(outer)
w.Flush()
return out.Bytes(), nil
}
// setBuffers implements ReceiptsList.
func (rl *ReceiptList68) setBuffers(buf *receiptListBuffers) {
rl.buf = buf
}
// EncodeForStorage encodes the receipts for storage into the database.
func (rl *ReceiptList68) EncodeForStorage() (rlp.RawValue, error) {
initBuffers(&rl.buf)
return rl.buf.encodeForStorage(rl.items, func(data []byte, r *Receipt) error {
return r.decode68(data)
})
}
// Derivable turns the receipts into a list that can derive the root hash.
func (rl *ReceiptList68) Derivable() types.DerivableList {
initBuffers(&rl.buf)
return newDerivableRawList(&rl.items, func(data []byte, outbuf *bytes.Buffer) { return newDerivableRawList(&rl.items, func(data []byte, outbuf *bytes.Buffer) {
var r Receipt var r Receipt
if r.decode68(data) == nil { if r.decode(data) == nil {
r.encodeForHash(rl.buf, outbuf) r.encodeForHash(&bloomBuf, outbuf)
} }
}) })
} }
// DecodeRLP decodes a list of receipts from the network format. // blockReceiptsToNetwork takes a slice of rlp-encoded receipts, and transactions,
func (rl *ReceiptList68) DecodeRLP(s *rlp.Stream) error { // and re-encodes them for the network protocol.
return rl.items.DecodeRLP(s) func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
}
// EncodeRLP encodes the list into the network format of eth/68.
func (rl *ReceiptList68) EncodeRLP(w io.Writer) error {
return rl.items.EncodeRLP(w)
}
// ReceiptList69 is the block receipt list as downloaded by eth/69.
// This implements types.DerivableList for validation purposes.
type ReceiptList69 struct {
buf *receiptListBuffers
items rlp.RawList[Receipt]
}
// NewReceiptList69 creates a receipt list.
// This is slow, and exists for testing purposes.
func NewReceiptList69(trs []*types.Receipt) *ReceiptList69 {
rl := new(ReceiptList69)
enc := rlp.NewEncoderBuffer(nil)
for _, tr := range trs {
r := newReceipt(tr)
r.encodeForNetwork69(&enc)
rl.items.AppendRaw(enc.ToBytes())
enc.Reset(nil)
}
return rl
}
// setBuffers implements ReceiptsList.
func (rl *ReceiptList69) setBuffers(buf *receiptListBuffers) {
rl.buf = buf
}
// EncodeForStorage encodes the receipts for storage into the database.
func (rl *ReceiptList69) EncodeForStorage() (rlp.RawValue, error) {
initBuffers(&rl.buf)
return rl.buf.encodeForStorage(rl.items, func(data []byte, r *Receipt) error {
return r.decode69(data)
})
}
// Derivable turns the receipts into a list that can derive the root hash.
func (rl *ReceiptList69) Derivable() types.DerivableList {
initBuffers(&rl.buf)
return newDerivableRawList(&rl.items, func(data []byte, outbuf *bytes.Buffer) {
var r Receipt
if r.decode69(data) == nil {
r.encodeForHash(rl.buf, outbuf)
}
})
}
// DecodeRLP decodes a list receipts from the network format.
func (rl *ReceiptList69) DecodeRLP(s *rlp.Stream) error {
return rl.items.DecodeRLP(s)
}
// EncodeRLP encodes the list into the network format of eth/69.
func (rl *ReceiptList69) EncodeRLP(w io.Writer) error {
return rl.items.EncodeRLP(w)
}
// blockReceiptsToNetwork69 takes a slice of rlp-encoded receipts, and transactions,
// and applies the type-encoding on the receipts (for non-legacy receipts).
// e.g. for non-legacy receipts: receipt-data -> {tx-type || receipt-data}
func blockReceiptsToNetwork69(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
txTypesIter, err := txTypesInBody(blockBody) txTypesIter, err := txTypesInBody(blockBody)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid block body: %v", err) return nil, fmt.Errorf("invalid block body: %v", err)

View file

@ -95,7 +95,7 @@ func init() {
} }
} }
func TestReceiptList69(t *testing.T) { func TestReceiptList(t *testing.T) {
for i, test := range receiptsTests { for i, test := range receiptsTests {
// encode receipts from types.ReceiptForStorage object. // encode receipts from types.ReceiptForStorage object.
canonDB, _ := rlp.EncodeToBytes(test.input) canonDB, _ := rlp.EncodeToBytes(test.input)
@ -105,13 +105,13 @@ func TestReceiptList69(t *testing.T) {
canonBody, _ := rlp.EncodeToBytes(blockBody) canonBody, _ := rlp.EncodeToBytes(blockBody)
// convert from storage encoding to network encoding // convert from storage encoding to network encoding
network, err := blockReceiptsToNetwork69(canonDB, canonBody) network, err := blockReceiptsToNetwork(canonDB, canonBody)
if err != nil { if err != nil {
t.Fatalf("test[%d]: blockReceiptsToNetwork69 error: %v", i, err) t.Fatalf("test[%d]: blockReceiptsToNetwork error: %v", i, err)
} }
// parse as Receipts response list from network encoding // parse as Receipts response list from network encoding
var rl ReceiptList69 var rl ReceiptList
if err := rlp.DecodeBytes(network, &rl); err != nil { if err := rlp.DecodeBytes(network, &rl); err != nil {
t.Fatalf("test[%d]: can't decode network receipts: %v", i, err) t.Fatalf("test[%d]: can't decode network receipts: %v", i, err)
} }
@ -127,50 +127,10 @@ func TestReceiptList69(t *testing.T) {
t.Fatalf("test[%d]: re-encoded network receipt list not equal\nhave: %x\nwant: %x", i, rlNetworkEnc, network) t.Fatalf("test[%d]: re-encoded network receipt list not equal\nhave: %x\nwant: %x", i, rlNetworkEnc, network)
} }
// compute root hash from ReceiptList69 and compare. // compute root hash from ReceiptList and compare.
responseHash := types.DeriveSha(rl.Derivable(), trie.NewStackTrie(nil)) responseHash := types.DeriveSha(rl.Derivable(), trie.NewStackTrie(nil))
if responseHash != test.root { if responseHash != test.root {
t.Fatalf("test[%d]: wrong root hash from ReceiptList69\nhave: %v\nwant: %v", i, responseHash, test.root) t.Fatalf("test[%d]: wrong root hash from ReceiptList\nhave: %v\nwant: %v", i, responseHash, test.root)
}
}
}
func TestReceiptList68(t *testing.T) {
for i, test := range receiptsTests {
// encode receipts from types.ReceiptForStorage object.
canonDB, _ := rlp.EncodeToBytes(test.input)
// encode block body from types object.
blockBody := types.Body{Transactions: test.txs}
canonBody, _ := rlp.EncodeToBytes(blockBody)
// convert from storage encoding to network encoding
network, err := blockReceiptsToNetwork68(canonDB, canonBody)
if err != nil {
t.Fatalf("test[%d]: blockReceiptsToNetwork68 error: %v", i, err)
}
// parse as Receipts response list from network encoding
var rl ReceiptList68
if err := rlp.DecodeBytes(network, &rl); err != nil {
t.Fatalf("test[%d]: can't decode network receipts: %v", i, err)
}
rlStorageEnc, err := rl.EncodeForStorage()
if err != nil {
t.Fatalf("test[%d]: error from EncodeForStorage: %v", i, err)
}
if !bytes.Equal(rlStorageEnc, canonDB) {
t.Fatalf("test[%d]: re-encoded receipts not equal\nhave: %x\nwant: %x", i, rlStorageEnc, canonDB)
}
rlNetworkEnc, _ := rlp.EncodeToBytes(&rl)
if !bytes.Equal(rlNetworkEnc, network) {
t.Fatalf("test[%d]: re-encoded network receipt list not equal\nhave: %x\nwant: %x", i, rlNetworkEnc, network)
}
// compute root hash from ReceiptList68 and compare.
responseHash := types.DeriveSha(rl.Derivable(), trie.NewStackTrie(nil))
if responseHash != test.root {
t.Fatalf("test[%d]: wrong root hash from ReceiptList68\nhave: %v\nwant: %v", i, responseHash, test.root)
} }
} }
} }

View file

@ -28,7 +28,7 @@ import (
) )
// Tests that snap sync is disabled after a successful sync cycle. // Tests that snap sync is disabled after a successful sync cycle.
func TestSnapSyncDisabling68(t *testing.T) { testSnapSyncDisabling(t, eth.ETH68, snap.SNAP1) } func TestSnapSyncDisabling69(t *testing.T) { testSnapSyncDisabling(t, eth.ETH69, snap.SNAP1) }
// Tests that snap sync gets disabled as soon as a real block is successfully // Tests that snap sync gets disabled as soon as a real block is successfully
// imported into the blockchain. // imported into the blockchain.