diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 07717ec333..0b93fd6709 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -319,12 +319,15 @@ func serviceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest) continue } } else { - header := chain.GetHeaderByHash(hash) - if header.ReceiptHash != types.EmptyReceiptsHash { - body := new(types.Body) - if err := rlp.DecodeBytes(chain.GetBodyRLP(hash), &body); err == nil { - results = blockReceiptsToNetwork(results, body.Transactions) - } + body := chain.GetBodyRLP(hash) + if body == nil { + continue + } + var err error + results, err = blockReceiptsToNetwork(results, body) + if err != nil { + log.Error("Error in block receipts conversion", "hash", hash, "err", err) + continue } } receipts = append(receipts, results) @@ -424,7 +427,7 @@ func handleReceipts69(backend Backend, msg Decoder, peer *Peer) error { for i := range res.List { res.List[i].buf = buffers } - metadata := func() interface{} { + metadata := func() any { hasher := trie.NewStackTrie(nil) hashes := make([]common.Hash, len(res.List)) for i := range res.List { diff --git a/eth/protocols/eth/receipt.go b/eth/protocols/eth/receipt.go index 0a2f1cdb21..7e43ce42f9 100644 --- a/eth/protocols/eth/receipt.go +++ b/eth/protocols/eth/receipt.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io" + "iter" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" @@ -199,7 +200,14 @@ func (rl *ReceiptList69) toStorageReceiptsRLP() rlp.RawValue { // blockReceiptsToNetwork 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 blockReceiptsToNetwork(blockReceipts rlp.RawValue, txs []*types.Transaction) []byte { +func blockReceiptsToNetwork(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 enc = rlp.NewEncoderBuffer(&out) @@ -207,13 +215,43 @@ func blockReceiptsToNetwork(blockReceipts rlp.RawValue, txs []*types.Transaction ) outer := enc.List() for i := 0; it.Next(); i++ { + txType, _ := nextTxType() content, _, _ := rlp.SplitList(it.Value()) receiptList := enc.List() - enc.WriteUint64(uint64(txs[i].Type())) + enc.WriteUint64(uint64(txType)) enc.Write(content) enc.ListEnd(receiptList) } enc.ListEnd(outer) enc.Flush() - return out.Bytes() + return out.Bytes(), nil +} + +// 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 { + return nil, err + } + txsIter, err := rlp.NewListIterator(bodyFields) + if err != nil { + return nil, err + } + return func(yield func(byte) bool) { + for txsIter.Next() { + var txType byte + switch k, content, _, _ := rlp.Split(txsIter.Value()); k { + case rlp.List: + txType = 0 + case rlp.String: + if len(content) > 0 { + txType = content[0] + } + } + if !yield(txType) { + return + } + } + }, nil } diff --git a/eth/protocols/eth/receipt_test.go b/eth/protocols/eth/receipt_test.go index f73532a2e8..7c39b0fc89 100644 --- a/eth/protocols/eth/receipt_test.go +++ b/eth/protocols/eth/receipt_test.go @@ -57,11 +57,20 @@ func TestTransformReceipts(t *testing.T) { } for i, test := range tests { + // encode receipts from types object. in, _ := rlp.EncodeToBytes(test.input) - have := blockReceiptsToNetwork(in, test.txs) + + // encode block body from types object. + blockBody := types.Body{Transactions: test.txs} + encBlockBody, _ := rlp.EncodeToBytes(blockBody) + + have, err := blockReceiptsToNetwork(in, encBlockBody) + if err != nil { + t.Fatalf("test[%d]: blockReceiptsToNetwork error: %v", i, err) + } out, _ := rlp.EncodeToBytes(test.output) if !bytes.Equal(have, out) { - t.Fatalf("test[%d]: blockReceiptToNetwork mismatch\nhave: %x\nwant: %x\n in: %x", i, out, have, in) + t.Fatalf("test[%d]: blockReceiptsToNetwork mismatch\nhave: %x\nwant: %x\n in: %x", i, out, have, in) } var rl ReceiptList69