core, core/rawdb, eth/sync: no tx indexing during snap sync (#28703)
This change simplifies the logic for indexing transactions and enhances the UX when transaction is not found by returning more information to users. Transaction indexing is now considered as a part of the initial sync, and `eth.syncing` will thus be `true` if transaction indexing is not yet finished. API consumers can use the syncing status to determine if the node is ready to serve users.
This commit is contained in:
+51
-83
@@ -27,7 +27,6 @@ import (
|
||||
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
"github.com/ethereum/go-ethereum/accounts"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/ethereum/go-ethereum/accounts/scwallet"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
@@ -134,26 +133,28 @@ func (s *EthereumAPI) Syncing() (interface{}, error) {
|
||||
progress := s.b.SyncProgress()
|
||||
|
||||
// Return not syncing if the synchronisation already completed
|
||||
if progress.CurrentBlock >= progress.HighestBlock {
|
||||
if progress.Done() {
|
||||
return false, nil
|
||||
}
|
||||
// Otherwise gather the block sync stats
|
||||
return map[string]interface{}{
|
||||
"startingBlock": hexutil.Uint64(progress.StartingBlock),
|
||||
"currentBlock": hexutil.Uint64(progress.CurrentBlock),
|
||||
"highestBlock": hexutil.Uint64(progress.HighestBlock),
|
||||
"syncedAccounts": hexutil.Uint64(progress.SyncedAccounts),
|
||||
"syncedAccountBytes": hexutil.Uint64(progress.SyncedAccountBytes),
|
||||
"syncedBytecodes": hexutil.Uint64(progress.SyncedBytecodes),
|
||||
"syncedBytecodeBytes": hexutil.Uint64(progress.SyncedBytecodeBytes),
|
||||
"syncedStorage": hexutil.Uint64(progress.SyncedStorage),
|
||||
"syncedStorageBytes": hexutil.Uint64(progress.SyncedStorageBytes),
|
||||
"healedTrienodes": hexutil.Uint64(progress.HealedTrienodes),
|
||||
"healedTrienodeBytes": hexutil.Uint64(progress.HealedTrienodeBytes),
|
||||
"healedBytecodes": hexutil.Uint64(progress.HealedBytecodes),
|
||||
"healedBytecodeBytes": hexutil.Uint64(progress.HealedBytecodeBytes),
|
||||
"healingTrienodes": hexutil.Uint64(progress.HealingTrienodes),
|
||||
"healingBytecode": hexutil.Uint64(progress.HealingBytecode),
|
||||
"startingBlock": hexutil.Uint64(progress.StartingBlock),
|
||||
"currentBlock": hexutil.Uint64(progress.CurrentBlock),
|
||||
"highestBlock": hexutil.Uint64(progress.HighestBlock),
|
||||
"syncedAccounts": hexutil.Uint64(progress.SyncedAccounts),
|
||||
"syncedAccountBytes": hexutil.Uint64(progress.SyncedAccountBytes),
|
||||
"syncedBytecodes": hexutil.Uint64(progress.SyncedBytecodes),
|
||||
"syncedBytecodeBytes": hexutil.Uint64(progress.SyncedBytecodeBytes),
|
||||
"syncedStorage": hexutil.Uint64(progress.SyncedStorage),
|
||||
"syncedStorageBytes": hexutil.Uint64(progress.SyncedStorageBytes),
|
||||
"healedTrienodes": hexutil.Uint64(progress.HealedTrienodes),
|
||||
"healedTrienodeBytes": hexutil.Uint64(progress.HealedTrienodeBytes),
|
||||
"healedBytecodes": hexutil.Uint64(progress.HealedBytecodes),
|
||||
"healedBytecodeBytes": hexutil.Uint64(progress.HealedBytecodeBytes),
|
||||
"healingTrienodes": hexutil.Uint64(progress.HealingTrienodes),
|
||||
"healingBytecode": hexutil.Uint64(progress.HealingBytecode),
|
||||
"txIndexFinishedBlocks": hexutil.Uint64(progress.TxIndexFinishedBlocks),
|
||||
"txIndexRemainingBlocks": hexutil.Uint64(progress.TxIndexRemainingBlocks),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -1133,37 +1134,6 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash
|
||||
return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap)
|
||||
}
|
||||
|
||||
func newRevertError(revert []byte) *revertError {
|
||||
err := vm.ErrExecutionReverted
|
||||
|
||||
reason, errUnpack := abi.UnpackRevert(revert)
|
||||
if errUnpack == nil {
|
||||
err = fmt.Errorf("%w: %v", vm.ErrExecutionReverted, reason)
|
||||
}
|
||||
return &revertError{
|
||||
error: err,
|
||||
reason: hexutil.Encode(revert),
|
||||
}
|
||||
}
|
||||
|
||||
// revertError is an API error that encompasses an EVM revertal with JSON error
|
||||
// code and a binary data blob.
|
||||
type revertError struct {
|
||||
error
|
||||
reason string // revert reason hex encoded
|
||||
}
|
||||
|
||||
// ErrorCode returns the JSON error code for a revertal.
|
||||
// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
|
||||
func (e *revertError) ErrorCode() int {
|
||||
return 3
|
||||
}
|
||||
|
||||
// ErrorData returns the hex encoded revert reason.
|
||||
func (e *revertError) ErrorData() interface{} {
|
||||
return e.reason
|
||||
}
|
||||
|
||||
// Call executes the given transaction on the state for the given block number.
|
||||
//
|
||||
// Additionally, the caller can specify a batch of contract for fields overriding.
|
||||
@@ -1652,50 +1622,48 @@ func (s *TransactionAPI) GetTransactionCount(ctx context.Context, address common
|
||||
// GetTransactionByHash returns the transaction for the given hash
|
||||
func (s *TransactionAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) (*RPCTransaction, error) {
|
||||
// Try to return an already finalized transaction
|
||||
tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
||||
found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
||||
if !found {
|
||||
// No finalized transaction, try to retrieve it from the pool
|
||||
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
||||
return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil
|
||||
}
|
||||
if err == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, NewTxIndexingError()
|
||||
}
|
||||
header, err := s.b.HeaderByHash(ctx, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tx != nil {
|
||||
header, err := s.b.HeaderByHash(ctx, blockHash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil
|
||||
}
|
||||
// No finalized transaction, try to retrieve it from the pool
|
||||
if tx := s.b.GetPoolTransaction(hash); tx != nil {
|
||||
return NewRPCPendingTransaction(tx, s.b.CurrentHeader(), s.b.ChainConfig()), nil
|
||||
}
|
||||
|
||||
// Transaction unknown, return as such
|
||||
return nil, nil
|
||||
return newRPCTransaction(tx, blockHash, blockNumber, header.Time, index, header.BaseFee, s.b.ChainConfig()), nil
|
||||
}
|
||||
|
||||
// GetRawTransactionByHash returns the bytes of the transaction for the given hash.
|
||||
func (s *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
|
||||
// Retrieve a finalized transaction, or a pooled otherwise
|
||||
tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tx == nil {
|
||||
if tx = s.b.GetPoolTransaction(hash); tx == nil {
|
||||
// Transaction not found anywhere, abort
|
||||
found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
|
||||
if !found {
|
||||
if tx = s.b.GetPoolTransaction(hash); tx != nil {
|
||||
return tx.MarshalBinary()
|
||||
}
|
||||
if err == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, NewTxIndexingError()
|
||||
}
|
||||
// Serialize to RLP and return
|
||||
return tx.MarshalBinary()
|
||||
}
|
||||
|
||||
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
|
||||
func (s *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
|
||||
tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
||||
if tx == nil || err != nil {
|
||||
// When the transaction doesn't exist, the RPC method should return JSON null
|
||||
// as per specification.
|
||||
return nil, nil
|
||||
found, tx, blockHash, blockNumber, index, err := s.b.GetTransaction(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, NewTxIndexingError() // transaction is not fully indexed
|
||||
}
|
||||
if !found {
|
||||
return nil, nil // transaction is not existent or reachable
|
||||
}
|
||||
header, err := s.b.HeaderByHash(ctx, blockHash)
|
||||
if err != nil {
|
||||
@@ -2085,15 +2053,15 @@ func (api *DebugAPI) GetRawReceipts(ctx context.Context, blockNrOrHash rpc.Block
|
||||
// GetRawTransaction returns the bytes of the transaction for the given hash.
|
||||
func (s *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hexutil.Bytes, error) {
|
||||
// Retrieve a finalized transaction, or a pooled otherwise
|
||||
tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if tx == nil {
|
||||
if tx = s.b.GetPoolTransaction(hash); tx == nil {
|
||||
// Transaction not found anywhere, abort
|
||||
found, tx, _, _, _, err := s.b.GetTransaction(ctx, hash)
|
||||
if !found {
|
||||
if tx = s.b.GetPoolTransaction(hash); tx != nil {
|
||||
return tx.MarshalBinary()
|
||||
}
|
||||
if err == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, NewTxIndexingError()
|
||||
}
|
||||
return tx.MarshalBinary()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user