From 81a6b08f3c84f7acc1a8059ff49bb27f4e1585ca Mon Sep 17 00:00:00 2001 From: YQ AltLayer Date: Sun, 1 Mar 2026 13:04:41 +0000 Subject: [PATCH] eth: make txIndex optional in debug_storageRangeAt The debug_storageRangeAt RPC method requires txIndex as a mandatory parameter, meaning callers can only query state before a specific transaction in a block. There is no way to query the post-block state (after the last transaction), unlike other debug methods such as debug_traceCall which allow omitting the index. Make txIndex a pointer (*int) so it becomes optional: - When provided: use stateAtTransaction to get state before that tx (existing behavior, unchanged) - When omitted (null): use stateAtBlock to get the post-block state This is consistent with how other debug API endpoints handle optional state references. Fixes #31344 --- eth/api_debug.go | 14 ++++++++++++-- internal/web3ext/web3ext.go | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/eth/api_debug.go b/eth/api_debug.go index d4ef4cc87d..8833718de7 100644 --- a/eth/api_debug.go +++ b/eth/api_debug.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rlp" @@ -211,7 +212,8 @@ type storageEntry struct { } // StorageRangeAt returns the storage at the given block height and transaction index. -func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { +// If txIndex is nil, it returns the storage at the end of the given block. +func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash, txIndex *int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) { var block *types.Block block, err := api.eth.APIBackend.BlockByNumberOrHash(ctx, blockNrOrHash) @@ -221,7 +223,15 @@ func (api *DebugAPI) StorageRangeAt(ctx context.Context, blockNrOrHash rpc.Block if block == nil { return StorageRangeResult{}, fmt.Errorf("block %v not found", blockNrOrHash) } - _, _, statedb, release, err := api.eth.stateAtTransaction(ctx, block, txIndex, 0) + var ( + statedb *state.StateDB + release tracers.StateReleaseFunc + ) + if txIndex != nil { + _, _, statedb, release, err = api.eth.stateAtTransaction(ctx, block, *txIndex, 0) + } else { + statedb, release, err = api.eth.stateAtBlock(ctx, block, 0, nil, true, false) + } if err != nil { return StorageRangeResult{}, err } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 9ba8776360..9e8392ddf3 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -414,6 +414,7 @@ web3._extend({ name: 'storageRangeAt', call: 'debug_storageRangeAt', params: 5, + inputFormatter: [null, null, null, null, null], }), new web3._extend.Method({ name: 'getModifiedAccountsByNumber',