From 594363117329d2a12f7584885526eb282247fb58 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 16 Apr 2025 01:05:05 +0200 Subject: [PATCH] eth/protocols/eth: fix receipt hashing --- eth/protocols/eth/receipt.go | 25 ++++++++----------------- eth/protocols/eth/receipt_test.go | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/eth/protocols/eth/receipt.go b/eth/protocols/eth/receipt.go index 7e43ce42f9..f833ddd66d 100644 --- a/eth/protocols/eth/receipt.go +++ b/eth/protocols/eth/receipt.go @@ -96,6 +96,7 @@ func (r *Receipt) bloom(buffer *[6]byte) types.Bloom { } for logsIter.Next() { log := logsIter.Value() + log, _, _ = rlp.SplitList(log) address, log, _ := rlp.SplitString(log) b.AddWithBuffer(address, buffer) topicsIter, err := rlp.NewListIterator(log) @@ -103,7 +104,8 @@ func (r *Receipt) bloom(buffer *[6]byte) types.Bloom { return b } for topicsIter.Next() { - b.AddWithBuffer(topicsIter.Value(), buffer) + topic, _, _ := rlp.SplitString(topicsIter.Value()) + b.AddWithBuffer(topic, buffer) } } return b @@ -137,7 +139,10 @@ func (rl *ReceiptList69) EncodeIndex(i int, b *bytes.Buffer) { bloom = r.bloom(&rl.buf.bloom) w = &rl.buf.enc ) - // encode receipt list: [postStateOrStatus, gasUsed, bloom, logs] + if r.TxType != 0 { + b.WriteByte(r.TxType) + } + // encode list = [postStateOrStatus, gasUsed, bloom, logs] w.Reset(b) l := w.List() w.WriteBytes(r.PostStateOrStatus) @@ -145,19 +150,6 @@ func (rl *ReceiptList69) EncodeIndex(i int, b *bytes.Buffer) { w.WriteBytes(bloom[:]) w.Write(r.Logs) w.ListEnd(l) - if err := w.Flush(); err != nil { - return - } - // if this is a legacy transaction receipt, we are done. - if r.TxType == 0 { - return - } - // Otherwise it's a typed transaction receipt, which has the type prefix and - // the inner list as a byte-array: tx-type || rlp(list). - // Since b contains the correct inner list, we can reuse its content. - w.Reset(b) - w.WriteUint64(uint64(r.TxType)) - w.WriteBytes(b.Bytes()) w.Flush() } @@ -227,8 +219,7 @@ func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, erro return out.Bytes(), nil } -// txTypesInBody parses the transactions list of an encoded block body, -// returning just the types. +// txTypesInBody parses the transactions list of an encoded block body, returning just the types. func txTypesInBody(body rlp.RawValue) (iter.Seq[byte], error) { bodyFields, _, err := rlp.SplitList(body) if err != nil { diff --git a/eth/protocols/eth/receipt_test.go b/eth/protocols/eth/receipt_test.go index 7c39b0fc89..5017ec4d9a 100644 --- a/eth/protocols/eth/receipt_test.go +++ b/eth/protocols/eth/receipt_test.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/trie" ) func TestTransformReceipts(t *testing.T) { @@ -64,6 +65,7 @@ func TestTransformReceipts(t *testing.T) { blockBody := types.Body{Transactions: test.txs} encBlockBody, _ := rlp.EncodeToBytes(blockBody) + // convert from storage encoding to network encoding have, err := blockReceiptsToNetwork(in, encBlockBody) if err != nil { t.Fatalf("test[%d]: blockReceiptsToNetwork error: %v", i, err) @@ -73,6 +75,7 @@ func TestTransformReceipts(t *testing.T) { t.Fatalf("test[%d]: blockReceiptsToNetwork mismatch\nhave: %x\nwant: %x\n in: %x", i, out, have, in) } + // parse as Receipts response list from network encoding var rl ReceiptList69 if err := rlp.DecodeBytes(out, &rl); err != nil { t.Fatalf("test[%d]: can't decode network receipts: %v", i, err) @@ -81,6 +84,23 @@ func TestTransformReceipts(t *testing.T) { if !bytes.Equal(storageEnc, in) { t.Fatalf("test[%d]: re-encoded receipts not equal\nhave: %x\nwant: %x", i, storageEnc, in) } + + // compute expected root hash + receipts := make(types.Receipts, len(test.input)) + for i := range test.input { + r := types.Receipt(test.input[i]) + // need to derive these fields to get the correct result from DeriveSha. + r.Type = test.txs[i].Type() + r.Bloom = types.CreateBloom(&r) + receipts[i] = &r + } + expectedHash := types.DeriveSha(receipts, trie.NewStackTrie(nil)) + + // compute root hash from ReceiptList69 and compare. + responseHash := types.DeriveSha(&rl, trie.NewStackTrie(nil)) + if responseHash != expectedHash { + t.Fatalf("test[%d]: wrong root hash from ReceiptList69\nhave: %v\nwant: %v", i, responseHash, expectedHash) + } } }