diff --git a/cmd/rpcdaemon/commands/debug_api.go b/cmd/rpcdaemon/commands/debug_api.go index 018c36c86..ea64337ae 100644 --- a/cmd/rpcdaemon/commands/debug_api.go +++ b/cmd/rpcdaemon/commands/debug_api.go @@ -27,6 +27,7 @@ type PrivateDebugAPI interface { GetModifiedAccountsByNumber(ctx context.Context, startNum rpc.BlockNumber, endNum *rpc.BlockNumber) ([]common.Address, error) GetModifiedAccountsByHash(_ context.Context, startHash common.Hash, endHash *common.Hash) ([]common.Address, error) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHash rpc.BlockNumberOrHash, config *eth.TraceConfig) (interface{}, error) + AccountAt(ctx context.Context, blockHash common.Hash, txIndex uint64, account common.Address) (*AccountResult, error) } // PrivateDebugAPIImpl is implementation of the PrivateDebugAPI interface based on remote Db access @@ -204,3 +205,40 @@ func (api *PrivateDebugAPIImpl) GetModifiedAccountsByHash(ctx context.Context, s return changeset.GetModifiedAccounts(tx, startNum, endNum) } + +func (api *PrivateDebugAPIImpl) AccountAt(ctx context.Context, blockHash common.Hash, txIndex uint64, address common.Address) (*AccountResult, error) { + tx, err := api.dbReader.Begin(ctx, ethdb.RO) + if err != nil { + return nil, err + } + defer tx.Rollback() + + bc := adapter.NewBlockGetter(tx) + cc := adapter.NewChainContext(tx) + genesis, err := rawdb.ReadBlockByNumber(tx, 0) + if err != nil { + return nil, err + } + genesisHash := genesis.Hash() + chainConfig, err := rawdb.ReadChainConfig(tx, genesisHash) + if err != nil { + return nil, err + } + _, _, ibs, _, err := transactions.ComputeTxEnv(ctx, bc, chainConfig, cc, tx.(ethdb.HasTx).Tx(), blockHash, txIndex) + if err != nil { + return nil, err + } + result := &AccountResult{} + result.Balance.ToInt().Set(ibs.GetBalance(address).ToBig()) + result.Nonce = hexutil.Uint64(ibs.GetNonce(address)) + result.Code = ibs.GetCode(address) + result.CodeHash = ibs.GetCodeHash(address) + return result, nil +} + +type AccountResult struct { + Balance hexutil.Big `json:"balance"` + Nonce hexutil.Uint64 `json:"nonce"` + Code hexutil.Bytes `json:"code"` + CodeHash common.Hash `json:"codeHash"` +} diff --git a/turbo/transactions/tracing.go b/turbo/transactions/tracing.go index fb061096f..b5abe1d4c 100644 --- a/turbo/transactions/tracing.go +++ b/turbo/transactions/tracing.go @@ -34,7 +34,7 @@ type BlockGetter interface { } // computeTxEnv returns the execution environment of a certain transaction. -func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.ChainConfig, chain core.ChainContext, tx ethdb.Tx, blockHash common.Hash, txIndex uint64) (core.Message, vm.Context, *state.IntraBlockState, *state2.StateReader, error) { +func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.ChainConfig, chain core.ChainContext, dbtx ethdb.Tx, blockHash common.Hash, txIndex uint64) (core.Message, vm.Context, *state.IntraBlockState, *state2.StateReader, error) { // Create the parent state database block, err := blockGetter.GetBlockByHash(blockHash) if err != nil { @@ -48,7 +48,7 @@ func ComputeTxEnv(ctx context.Context, blockGetter BlockGetter, cfg *params.Chai return nil, vm.Context{}, nil, nil, fmt.Errorf("parent %x not found", block.ParentHash()) } - statedb, reader := state2.ComputeIntraBlockState(tx, parent) + statedb, reader := state2.ComputeIntraBlockState(dbtx, parent) if txIndex == 0 && len(block.Transactions()) == 0 { return nil, vm.Context{}, statedb, reader, nil