diff --git a/core/blockchain_reader.go b/core/blockchain_reader.go index 4894523b0e..a594f9f065 100644 --- a/core/blockchain_reader.go +++ b/core/blockchain_reader.go @@ -321,6 +321,25 @@ func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, max return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical) } +// HasCanonicalTransaction is a lightweight check to see if a transaction is present +// in the indexed part of the canonical chain without retrieving the transaction itself. +// It's view is limited to the indexed part of the chain, so very old transactions +// might fail the check if the indexer was constrained, or indexing is still in progress. +func (bc *BlockChain) HasCanonicalTransaction(hash common.Hash) bool { + bc.txLookupLock.RLock() + defer bc.txLookupLock.RUnlock() + + // Check in memory cache first + if _, exist := bc.txLookupCache.Get(hash); exist { + return true + } + // Fallback to database lookup, without reading the transaction itself + if rawdb.HasCanonicalTransaction(bc.db, hash) { + return true + } + return false +} + // GetCanonicalTransaction retrieves the lookup along with the transaction // itself associate with the given transaction hash. // diff --git a/core/rawdb/accessors_indexes.go b/core/rawdb/accessors_indexes.go index 10eb454015..e769d2e9d1 100644 --- a/core/rawdb/accessors_indexes.go +++ b/core/rawdb/accessors_indexes.go @@ -174,6 +174,12 @@ func findTxInBlockBody(blockbody rlp.RawValue, target common.Hash) (*types.Trans return nil, 0, errors.New("transaction not found") } +// HasCanonicalTransaction checks whether a specific transaction is in the database. +func HasCanonicalTransaction(db ethdb.Reader, hash common.Hash) bool { + blockNumber := ReadTxLookupEntry(db, hash) + return blockNumber != nil +} + // ReadCanonicalTransaction retrieves a specific transaction from the database, along // with its added positional metadata. Notably, only the transaction in the canonical // chain is visible.