eth: API error code for pruned blocks

This commit is contained in:
Sina Mahmoodi 2025-03-12 12:44:12 +01:00 committed by Felix Lange
parent f0cdc40ceb
commit 1dcc65d429
4 changed files with 70 additions and 29 deletions

View file

@ -86,6 +86,11 @@ func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
return bc.hc.GetHeaderByNumber(number)
}
// GetBlockNumber retrieves the block number associated with a block hash.
func (bc *BlockChain) GetBlockNumber(hash common.Hash) *uint64 {
return bc.hc.GetBlockNumber(hash)
}
// GetHeadersFrom returns a contiguous segment of headers, in rlp-form, going
// backwards from the given number.
func (bc *BlockChain) GetHeadersFrom(number, count uint64) []rlp.RawValue {
@ -437,3 +442,10 @@ func (bc *BlockChain) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscript
func (bc *BlockChain) SubscribeBlockProcessingEvent(ch chan<- bool) event.Subscription {
return bc.scope.Track(bc.blockProcFeed.Subscribe(ch))
}
// HistoryCutoff returns the tail of the block history.
func (bc *BlockChain) HistoryCutoff() uint64 {
// Only nofreezedb returns an error.
tail, _ := bc.db.Tail()
return tail
}

View file

@ -187,3 +187,5 @@ func WriteTransitionStatus(db ethdb.KeyValueWriter, data []byte) {
log.Crit("Failed to store the eth2 transition status", "err", err)
}
}
// ReadHistoryTail retrieves the first

View file

@ -143,11 +143,25 @@ func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumbe
}
return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil
}
return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil
bn := uint64(number)
if number == rpc.EarliestBlockNumber {
bn = b.eth.blockchain.HistoryCutoff()
}
if bn < b.eth.blockchain.HistoryCutoff() {
return nil, &prunedHistoryError{}
}
return b.eth.blockchain.GetBlockByNumber(bn), nil
}
func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
return b.eth.blockchain.GetBlockByHash(hash), nil
number := b.eth.blockchain.GetBlockNumber(hash)
if number == nil {
return nil, nil
}
if *number < b.eth.blockchain.HistoryCutoff() {
return nil, &prunedHistoryError{}
}
return b.eth.blockchain.GetBlock(hash, *number), nil
}
// GetBody returns body of a block. It does not resolve special block numbers.
@ -173,6 +187,9 @@ func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash r
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
return nil, errors.New("hash is not currently canonical")
}
if header.Number.Uint64() < b.eth.blockchain.HistoryCutoff() {
return nil, &prunedHistoryError{}
}
block := b.eth.blockchain.GetBlock(hash, header.Number.Uint64())
if block == nil {
return nil, errors.New("header found, but block body is missing")
@ -421,3 +438,8 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
}
type prunedHistoryError struct{}
func (e *prunedHistoryError) Error() string { return "Pruned history unavailable" }
func (e *prunedHistoryError) ErrorCode() int { return 4444 }

View file

@ -549,21 +549,23 @@ func (api *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, block
}
// GetUncleCountByBlockNumber returns number of uncles in the block for the given block number
func (api *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil {
func (api *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error) {
block, err := api.b.BlockByNumber(ctx, blockNr)
if block != nil {
n := hexutil.Uint(len(block.Uncles()))
return &n
return &n, nil
}
return nil
return nil, err
}
// GetUncleCountByBlockHash returns number of uncles in the block for the given block hash
func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil {
func (api *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) (*hexutil.Uint, error) {
block, err := api.b.BlockByHash(ctx, blockHash)
if block != nil {
n := hexutil.Uint(len(block.Uncles()))
return &n
return &n, nil
}
return nil
return nil, err
}
// GetCode returns the code stored at the given address in the state for the given block number.
@ -596,9 +598,7 @@ func (api *BlockChainAPI) GetStorageAt(ctx context.Context, address common.Addre
func (api *BlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) ([]map[string]interface{}, error) {
block, err := api.b.BlockByNumberOrHash(ctx, blockNrOrHash)
if block == nil || err != nil {
// When the block doesn't exist, the RPC method should return JSON null
// as per specification.
return nil, nil
return nil, err
}
receipts, err := api.b.GetReceipts(ctx, block.Hash())
if err != nil {
@ -1258,37 +1258,41 @@ func NewTransactionAPI(b Backend, nonceLock *AddrLocker) *TransactionAPI {
}
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
func (api *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint {
if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil {
func (api *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*hexutil.Uint, error) {
block, err := api.b.BlockByNumber(ctx, blockNr)
if block != nil {
n := hexutil.Uint(len(block.Transactions()))
return &n
return &n, nil
}
return nil
return nil, err
}
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
func (api *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint {
if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil {
func (api *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) (*hexutil.Uint, error) {
block, err := api.b.BlockByHash(ctx, blockHash)
if block != nil {
n := hexutil.Uint(len(block.Transactions()))
return &n
return &n, nil
}
return nil
return nil, err
}
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction {
if block, _ := api.b.BlockByNumber(ctx, blockNr); block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig())
func (api *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (*RPCTransaction, error) {
block, err := api.b.BlockByNumber(ctx, blockNr)
if block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()), nil
}
return nil
return nil, err
}
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction {
if block, _ := api.b.BlockByHash(ctx, blockHash); block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig())
func (api *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (*RPCTransaction, error) {
block, err := api.b.BlockByHash(ctx, blockHash)
if block != nil {
return newRPCTransactionFromBlockIndex(block, uint64(index), api.b.ChainConfig()), nil
}
return nil
return nil, err
}
// GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index.
@ -1365,6 +1369,7 @@ func (api *TransactionAPI) GetRawTransactionByHash(ctx context.Context, hash com
// GetTransactionReceipt returns the transaction receipt for the given transaction hash.
func (api *TransactionAPI) GetTransactionReceipt(ctx context.Context, hash common.Hash) (map[string]interface{}, error) {
// TODO(s1na): transaction lookup should be pruned as well.
found, tx, blockHash, blockNumber, index, err := api.b.GetTransaction(ctx, hash)
if err != nil {
return nil, NewTxIndexingError() // transaction is not fully indexed