diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 694a3e51832bd..ea79ab448423b 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -260,7 +260,7 @@ func (b *SimulatedBackend) ForEachStorageAt(ctx context.Context, contract common // TransactionReceipt returns the receipt of a transaction. func (b *SimulatedBackend) TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) { - receipt, _, _, _ := core.GetReceipt(b.database, txHash) + receipt, _, _, _ := rawdb.ReadReceipt(b.database, txHash, b.config) return receipt, nil } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 31ba9bb4a7014..ae6217b29b047 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -813,7 +813,7 @@ func TestChainTxReorgs(t *testing.T) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt != nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.chainConfig); rcpt != nil { t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt) } } @@ -822,7 +822,7 @@ func TestChainTxReorgs(t *testing.T) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { t.Errorf("add %d: expected tx to be found", i) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.chainConfig); rcpt == nil { t.Errorf("add %d: expected receipt to be found", i) } } @@ -831,7 +831,7 @@ func TestChainTxReorgs(t *testing.T) { if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { t.Errorf("share %d: expected tx to be found", i) } - if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil { + if rcpt, _, _, _ := rawdb.ReadReceipt(db, tx.Hash(), blockchain.chainConfig); rcpt == nil { t.Errorf("share %d: expected receipt to be found", i) } } diff --git a/core/database_util.go b/core/database_util.go index d25e06ac3a6f7..4ec66f31a6b03 100644 --- a/core/database_util.go +++ b/core/database_util.go @@ -67,8 +67,7 @@ var ( BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress // used by old db, now only used for conversion - oldReceiptsPrefix = []byte("receipts-") - oldTxMetaSuffix = []byte{0x01} + oldTxMetaSuffix = []byte{0x01} ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error @@ -322,33 +321,6 @@ func GetTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, co return &tx, entry.BlockHash, entry.BlockIndex, entry.Index } -// GetReceipt retrieves a specific transaction receipt from the database, along with -// its added positional metadata. -func GetReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) { - // Retrieve the lookup metadata and resolve the receipt from the receipts - blockHash, blockNumber, receiptIndex := GetTxLookupEntry(db, hash) - - if blockHash != (common.Hash{}) { - receipts := GetBlockReceipts(db, blockHash, blockNumber) - if len(receipts) <= int(receiptIndex) { - log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex) - return nil, common.Hash{}, 0, 0 - } - return receipts[receiptIndex], blockHash, blockNumber, receiptIndex - } - // Old receipt representation, load the receipt and set an unknown metadata - data, _ := db.Get(append(oldReceiptsPrefix, hash[:]...)) - if len(data) == 0 { - return nil, common.Hash{}, 0, 0 - } - var receipt types.ReceiptForStorage - err := rlp.DecodeBytes(data, &receipt) - if err != nil { - log.Error("Invalid receipt RLP", "hash", hash, "err", err) - } - return (*types.Receipt)(&receipt), common.Hash{}, 0, 0 -} - // GetBloomBits retrieves the compressed bloom bit vector belonging to the given // section and bit index from the. func GetBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) { diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 7f94098751932..9d9802b428e34 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -17,17 +17,39 @@ package rawdb import ( + "math/big" + "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/core/types" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/log" + "github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/rlp" ) -type TxLookupEntry struct { - BlockHash common.Hash - BlockIndex uint64 - Index uint64 +// ReadTxLookupEntry retrieves the positional metadata associated with a transaction +// hash to allow retrieving the transaction or receipt by hash. +func ReadTxLookupEntry(db ethdb.Reader, hash common.Hash) *uint64 { + data, _ := db.Get(txLookupKey(hash)) + if len(data) == 0 { + return nil + } + // Database v6 tx lookup just stores the block number + if len(data) < common.HashLength { + number := new(big.Int).SetBytes(data).Uint64() + return &number + } + // Database v4-v5 tx lookup format just stores the hash + if len(data) == common.HashLength { + return ReadHeaderNumber(db, common.BytesToHash(data)) + } + // Finally try database v3 tx lookup format + var entry TxLookupEntry + if err := rlp.DecodeBytes(data, &entry); err != nil { + log.Error("Invalid transaction lookup entry RLP", "hash", hash, "blob", data, "err", err) + return nil + } + return &entry.BlockIndex } // WriteTxLookupEntriesByBlock stores a positional metadata for every transaction from @@ -54,3 +76,30 @@ func WriteTxLookupEntriesByBlock(db ethdb.KeyValueWriter, block *types.Block) { func DeleteTxLookupEntry(db ethdb.KeyValueWriter, hash common.Hash) { db.Delete(txLookupKey(hash)) } + +// ReadReceipt retrieves a specific transaction receipt from the database, along with +// its added positional metadata. +func ReadReceipt(db ethdb.Reader, hash common.Hash, config *params.ChainConfig) (*types.Receipt, common.Hash, uint64, uint64) { + // Retrieve the context of the receipt based on the transaction hash + blockNumber := ReadTxLookupEntry(db, hash) + if blockNumber == nil { + return nil, common.Hash{}, 0, 0 + } + blockHash := ReadCanonicalHash(db, *blockNumber) + if blockHash == (common.Hash{}) { + return nil, common.Hash{}, 0, 0 + } + blockHeader := ReadHeader(db, blockHash, *blockNumber) + if blockHeader == nil { + return nil, common.Hash{}, 0, 0 + } + // Read all the receipts from the block and return the one with the matching hash + receipts := ReadReceipts(db, blockHash, *blockNumber, config) + for receiptIndex, receipt := range receipts { + if receipt.TxHash == hash { + return receipt, blockHash, *blockNumber, uint64(receiptIndex) + } + } + log.Error("Receipt not found", "number", *blockNumber, "hash", blockHash, "txhash", hash) + return nil, common.Hash{}, 0, 0 +} diff --git a/core/rawdb/schema.go b/core/rawdb/schema.go index a0a1852c75500..f530cae06c62d 100644 --- a/core/rawdb/schema.go +++ b/core/rawdb/schema.go @@ -66,6 +66,12 @@ const ( freezerReceiptTable = "receipts" ) +type TxLookupEntry struct { + BlockHash common.Hash + BlockIndex uint64 + Index uint64 +} + // encodeBlockNumber encodes a block number as big endian uint64 func encodeBlockNumber(number uint64) []byte { enc := make([]byte, 8)