From 7a5c0f10a09a0087a619d925eb13983a7ec5d0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20IRMAK?= Date: Sat, 21 Jun 2025 14:22:19 +0300 Subject: [PATCH] core/rawdb: allow skipping isCanon check --- core/rawdb/accessors_chain.go | 35 ++++++++++++++++++++++++++---- core/rawdb/accessors_chain_test.go | 6 +++++ core/rawdb/accessors_indexes.go | 4 ++-- core/rawdb/chain_iterator.go | 2 +- 4 files changed, 40 insertions(+), 7 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 2386246caf..b7945ba073 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -450,8 +450,8 @@ func ReadBodyRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawValue } // ReadCanonicalBodyRLP retrieves the block body (transactions and uncles) for the canonical -// block at number, in RLP encoding. -func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue { +// block at number, in RLP encoding. Optionally it takes the block hash to avoid looking it up +func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64, hash *common.Hash) rlp.RawValue { var data []byte db.ReadAncients(func(reader ethdb.AncientReaderOp) error { data, _ = reader.Ancient(ChainFreezerBodiesTable, number) @@ -461,8 +461,12 @@ func ReadCanonicalBodyRLP(db ethdb.Reader, number uint64) rlp.RawValue { // Block is not in ancients, read from leveldb by hash and number. // Note: ReadCanonicalHash cannot be used here because it also // calls ReadAncients internally. - hash, _ := db.Get(headerHashKey(number)) - data, _ = db.Get(blockBodyKey(number, common.BytesToHash(hash))) + if hash != nil { + data, _ = db.Get(blockBodyKey(number, *hash)) + } else { + hashBytes, _ := db.Get(headerHashKey(number)) + data, _ = db.Get(blockBodyKey(number, common.BytesToHash(hashBytes))) + } return nil }) return data @@ -544,6 +548,29 @@ func ReadReceiptsRLP(db ethdb.Reader, hash common.Hash, number uint64) rlp.RawVa return data } +// ReadCanonicalReceiptsRLP retrieves the receipts RLP for the canonical +// block at number, in RLP encoding. Optionally it takes the block hash to avoid looking it up +func ReadCanonicalReceiptsRLP(db ethdb.Reader, number uint64, hash *common.Hash) rlp.RawValue { + var data []byte + db.ReadAncients(func(reader ethdb.AncientReaderOp) error { + data, _ = reader.Ancient(ChainFreezerReceiptTable, number) + if len(data) > 0 { + return nil + } + // Block is not in ancients, read from leveldb by hash and number. + // Note: ReadCanonicalHash cannot be used here because it also + // calls ReadAncients internally. + if hash != nil { + data, _ = db.Get(blockReceiptsKey(number, *hash)) + } else { + hashBytes, _ := db.Get(headerHashKey(number)) + data, _ = db.Get(blockReceiptsKey(number, common.BytesToHash(hashBytes))) + } + return nil + }) + return data +} + // ReadRawReceipts retrieves all the transaction receipts belonging to a block. // The receipt metadata fields and the Bloom are not guaranteed to be populated, // so they should not be used. Use ReadReceipts instead if the metadata is needed. diff --git a/core/rawdb/accessors_chain_test.go b/core/rawdb/accessors_chain_test.go index 6d46239e27..196f3dac8f 100644 --- a/core/rawdb/accessors_chain_test.go +++ b/core/rawdb/accessors_chain_test.go @@ -441,6 +441,9 @@ func TestAncientStorage(t *testing.T) { if blob := ReadReceiptsRLP(db, hash, number); len(blob) > 0 { t.Fatalf("non existent receipts returned") } + if blob := ReadCanonicalReceiptsRLP(db, number, &hash); len(blob) > 0 { + t.Fatalf("non existent receipts returned") + } // Write and verify the header in the database WriteAncientBlocks(db, []*types.Block{block}, types.EncodeBlockReceiptLists([]types.Receipts{nil})) @@ -454,6 +457,9 @@ func TestAncientStorage(t *testing.T) { if blob := ReadReceiptsRLP(db, hash, number); len(blob) == 0 { t.Fatalf("no receipts returned") } + if blob := ReadCanonicalReceiptsRLP(db, number, &hash); len(blob) == 0 { + t.Fatalf("no receipts returned") + } // Use a fake hash for data retrieval, nothing should be returned. fakeHash := common.BytesToHash([]byte{0x01, 0x02, 0x03}) diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 3ee85b38ad..3e9a16fec6 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -181,7 +181,7 @@ func ReadTransaction(db ethdb.Reader, hash common.Hash) (*types.Transaction, com if blockHash == (common.Hash{}) { return nil, common.Hash{}, 0, 0 } - bodyRLP := ReadBodyRLP(db, blockHash, *blockNumber) + bodyRLP := ReadCanonicalBodyRLP(db, *blockNumber, &blockHash) if bodyRLP == nil { log.Error("Transaction referenced missing", "number", *blockNumber, "hash", blockHash) return nil, common.Hash{}, 0, 0 @@ -265,7 +265,7 @@ type RawReceiptContext struct { // the gas used by the associated transaction and the starting index of the logs // within the block. func ReadRawReceipt(db ethdb.Reader, blockHash common.Hash, blockNumber, txIndex uint64) (*types.Receipt, RawReceiptContext, error) { - receiptIt, err := rlp.NewListIterator(ReadReceiptsRLP(db, blockHash, blockNumber)) + receiptIt, err := rlp.NewListIterator(ReadCanonicalReceiptsRLP(db, blockNumber, &blockHash)) if err != nil { return nil, RawReceiptContext{}, err } diff --git a/core/rawdb/chain_iterator.go b/core/rawdb/chain_iterator.go index ecbc44e1f1..e7c89ca8d9 100644 --- a/core/rawdb/chain_iterator.go +++ b/core/rawdb/chain_iterator.go @@ -118,7 +118,7 @@ func iterateTransactions(db ethdb.Database, from uint64, to uint64, reverse bool } defer close(rlpCh) for n != end { - data := ReadCanonicalBodyRLP(db, n) + data := ReadCanonicalBodyRLP(db, n, nil) // Feed the block to the aggregator, or abort on interrupt select { case rlpCh <- &numberRlp{n, data}: