check progress at the end

This commit is contained in:
Sina Mahmoodi 2025-05-02 11:38:13 +02:00
parent 0fab68d072
commit c134d6b40e
6 changed files with 57 additions and 47 deletions

View file

@ -275,17 +275,17 @@ func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, max
// // from the node's perspective. This can be due to // // from the node's perspective. This can be due to
// the transaction indexer not being finished. The caller must explicitly check // the transaction indexer not being finished. The caller must explicitly check
// the indexer progress. // the indexer progress.
func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction, error) { func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLookupEntry, *types.Transaction) {
bc.txLookupLock.RLock() bc.txLookupLock.RLock()
defer bc.txLookupLock.RUnlock() defer bc.txLookupLock.RUnlock()
// Short circuit if the txlookup already in the cache, retrieve otherwise // Short circuit if the txlookup already in the cache, retrieve otherwise
if item, exist := bc.txLookupCache.Get(hash); exist { if item, exist := bc.txLookupCache.Get(hash); exist {
return item.lookup, item.transaction, nil return item.lookup, item.transaction
} }
tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash) tx, blockHash, blockNumber, txIndex := rawdb.ReadTransaction(bc.db, hash)
if tx == nil { if tx == nil {
return nil, nil, nil return nil, nil
} }
lookup := &rawdb.LegacyTxLookupEntry{ lookup := &rawdb.LegacyTxLookupEntry{
BlockHash: blockHash, BlockHash: blockHash,
@ -296,11 +296,11 @@ func (bc *BlockChain) GetTransactionLookup(hash common.Hash) (*rawdb.LegacyTxLoo
lookup: lookup, lookup: lookup,
transaction: tx, transaction: tx,
}) })
return lookup, tx, nil return lookup, tx
} }
// TxIndexDone returns true if the transaction indexer has finished indexing. // TxIndexDone returns true if the transaction indexer has finished indexing.
func (bc *BlockChain) TxIndexDone(ctx context.Context) (bool, error) { func (bc *BlockChain) TxIndexDone(ctx context.Context) bool {
progress, err := bc.TxIndexProgress(ctx) progress, err := bc.TxIndexProgress(ctx)
if err != nil { if err != nil {
// No error is returned if the transaction indexing progress is unreachable // No error is returned if the transaction indexing progress is unreachable
@ -310,12 +310,12 @@ func (bc *BlockChain) TxIndexDone(ctx context.Context) (bool, error) {
// //
// In such scenarios, the transaction is treated as unreachable, though // In such scenarios, the transaction is treated as unreachable, though
// this is clearly an unintended and unexpected situation. // this is clearly an unintended and unexpected situation.
return true, nil return true
} }
if !progress.Done() { if !progress.Done() {
return false, nil return false
} }
return true, nil return true
} }
// HasState checks if state trie is fully present in the database or not. // HasState checks if state trie is fully present in the database or not.

View file

@ -349,22 +349,21 @@ func (b *EthAPIBackend) GetPoolTransaction(hash common.Hash) *types.Transaction
// GetTransaction retrieves the lookup along with the transaction itself associate // GetTransaction retrieves the lookup along with the transaction itself associate
// with the given transaction hash. // with the given transaction hash.
// //
// An error will be returned if the transaction is not found, and background // A null will be returned in the transaction is not found. The transaction is not existent
// indexing for transactions is still in progress. The error is used to indicate the // // from the node's perspective. This can be due to
// scenario explicitly that the transaction might be reachable shortly. // the transaction indexer not being finished. The caller must explicitly check
// // the indexer progress.
// A null will be returned in the transaction is not found and background transaction func (b *EthAPIBackend) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64) {
// indexing is already finished. The transaction is not existent from the perspective lookup, tx := b.eth.blockchain.GetTransactionLookup(txHash)
// of node.
func (b *EthAPIBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
lookup, tx, err := b.eth.blockchain.GetTransactionLookup(ctx, txHash)
if err != nil {
return false, nil, common.Hash{}, 0, 0, err
}
if lookup == nil || tx == nil { if lookup == nil || tx == nil {
return false, nil, common.Hash{}, 0, 0, nil return false, nil, common.Hash{}, 0, 0
} }
return true, tx, lookup.BlockHash, lookup.BlockIndex, lookup.Index, nil return true, tx, lookup.BlockHash, lookup.BlockIndex, lookup.Index
}
// TxIndexDone returns true if the transaction indexer has finished indexing.
func (b *EthAPIBackend) TxIndexDone(ctx context.Context) bool {
return b.eth.blockchain.TxIndexDone(ctx)
} }
func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) { func (b *EthAPIBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {

View file

@ -82,7 +82,8 @@ type Backend interface {
HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error)
BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error)
BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error)
GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64)
TxIndexDone(ctx context.Context) bool
RPCGasCap() uint64 RPCGasCap() uint64
ChainConfig() *params.ChainConfig ChainConfig() *params.ChainConfig
Engine() consensus.Engine Engine() consensus.Engine
@ -858,12 +859,13 @@ func containsTx(block *types.Block, hash common.Hash) bool {
// TraceTransaction returns the structured logs created during the execution of EVM // TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object. // and returns them as a JSON object.
func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) { func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *TraceConfig) (interface{}, error) {
found, _, blockHash, blockNumber, index, err := api.backend.GetTransaction(ctx, hash) found, _, blockHash, blockNumber, index := api.backend.GetTransaction(hash)
if err != nil {
return nil, ethapi.NewTxIndexingError()
}
// Only mined txes are supported
if !found { if !found {
// Warn in case tx indexer is not done.
if !api.backend.TxIndexDone(ctx) {
return nil, ethapi.NewTxIndexingError()
}
// Only mined txes are supported
return nil, errTxNotFound return nil, errTxNotFound
} }
// It shouldn't happen in practice. // It shouldn't happen in practice.

View file

@ -229,7 +229,7 @@ func (t *Transaction) resolve(ctx context.Context) (*types.Transaction, *Block)
return t.tx, t.block return t.tx, t.block
} }
// Try to return an already finalized transaction // Try to return an already finalized transaction
found, tx, blockHash, _, index, _ := t.r.backend.GetTransaction(ctx, t.hash) found, tx, blockHash, _, index := t.r.backend.GetTransaction(t.hash)
if found { if found {
t.tx = tx t.tx = tx
blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false) blockNrOrHash := rpc.BlockNumberOrHashWithHash(blockHash, false)

View file

@ -1333,16 +1333,18 @@ func (api *TransactionAPI) GetTransactionCount(ctx context.Context, address comm
// GetTransactionByHash returns the transaction for the given hash // GetTransactionByHash returns the transaction for the given hash
func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) { func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
// Try to return an already finalized transaction // Try to return an already finalized transaction
found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) found, tx, blockHash, blockNumber, index := api.b.GetTransaction(hash)
if !found { if !found {
// No finalized transaction, try to retrieve it from the pool // No finalized transaction, try to retrieve it from the pool
if tx := api.b.GetPoolTransaction(hash); tx != nil { if tx := api.b.GetPoolTransaction(hash); tx != nil {
return NewRPCPendingTransaction(tx, api.b.CurrentHeader(), api.b.ChainConfig()), nil return NewRPCPendingTransaction(tx, api.b.CurrentHeader(), api.b.ChainConfig()), nil
} }
if err == nil { // If also not in the pool there is a chance the tx indexer is still in progress.
return nil, nil if !api.b.TxIndexDone(ctx) {
return nil, NewTxIndexingError()
} }
return nil, NewTxIndexingError() // If the transaction is not found in the pool and the indexer is done, return nil
return nil, nil
} }
header, err := api.b.HeaderByHash(ctx, blockHash) header, err := api.b.HeaderByHash(ctx, blockHash)
if err != nil { if err != nil {
@ -1354,27 +1356,31 @@ func (api *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common
// GetRawTransactionByHash returns the bytes of the transaction for the given hash. // GetRawTransactionByHash returns the bytes of the transaction for the given hash.
func (api *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { func (api *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
// Retrieve a finalized transaction, or a pooled otherwise // Retrieve a finalized transaction, or a pooled otherwise
found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) found, tx, _, _, _ := api.b.GetTransaction(hash)
if !found { if !found {
if tx = api.b.GetPoolTransaction(hash); tx != nil { if tx = api.b.GetPoolTransaction(hash); tx != nil {
return tx.MarshalBinary() return tx.MarshalBinary()
} }
if err == nil { // If also not in the pool there is a chance the tx indexer is still in progress.
return nil, nil if !api.b.TxIndexDone(ctx) {
return nil, NewTxIndexingError()
} }
return nil, NewTxIndexingError() // If the transaction is not found in the pool and the indexer is done, return nil
return nil, nil
} }
return tx.MarshalBinary() return tx.MarshalBinary()
} }
// GetTransactionReceipt returns the transaction receipt for the given transaction hash. // GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) { func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash) found, tx, blockHash, blockNumber, index := api.b.GetTransaction(hash)
if err != nil {
return nil, NewTxIndexingError() // transaction is not fully indexed
}
if !found { if !found {
return nil, nil // transaction is not existent or reachable // Make sure indexer is done.
if !api.b.TxIndexDone(ctx) {
return nil, NewTxIndexingError()
}
// No such tx.
return nil, nil
} }
header, err := api.b.HeaderByHash(ctx, blockHash) header, err := api.b.HeaderByHash(ctx, blockHash)
if err != nil { if err != nil {
@ -1774,15 +1780,17 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block
// GetRawTransaction returns the bytes of the transaction for the given hash. // GetRawTransaction returns the bytes of the transaction for the given hash.
func (api *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) { func (api *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
// Retrieve a finalized transaction, or a pooled otherwise // Retrieve a finalized transaction, or a pooled otherwise
found, tx, _, _, _, err := api.b.GetTransaction(ctx, hash) found, tx, _, _, _ := api.b.GetTransaction(hash)
if !found { if !found {
if tx = api.b.GetPoolTransaction(hash); tx != nil { if tx = api.b.GetPoolTransaction(hash); tx != nil {
return tx.MarshalBinary() return tx.MarshalBinary()
} }
if err == nil { // If also not in the pool there is a chance the tx indexer is still in progress.
return nil, nil if !api.b.TxIndexDone(ctx) {
return nil, NewTxIndexingError()
} }
return nil, NewTxIndexingError() // Transaction is not found in the pool and the indexer is done.
return nil, nil
} }
return tx.MarshalBinary() return tx.MarshalBinary()
} }

View file

@ -74,7 +74,8 @@ type Backend interface {
// Transaction pool API // Transaction pool API
SendTx(ctx context.Context, signedTx *types.Transaction) error SendTx(ctx context.Context, signedTx *types.Transaction) error
GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) GetTransaction(txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64)
TxIndexDone(ctx context.Context) bool
GetPoolTransactions() (types.Transactions, error) GetPoolTransactions() (types.Transactions, error)
GetPoolTransaction(txHash common.Hash) *types.Transaction GetPoolTransaction(txHash common.Hash) *types.Transaction
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)