From 30f033bce79e78f7b54aacf18a37444a5f548dae Mon Sep 17 00:00:00 2001 From: Tony Chen Date: Fri, 23 May 2025 21:40:28 +0800 Subject: [PATCH] process non-EVM txs during traceBlock --- cmd/geth/logging_test.go | 4 +- cmd/geth/logtestcmd_active.go | 2 +- eth/api_backend.go | 26 +++--- eth/gasprice/feehistory.go | 2 +- eth/gasprice/gasprice.go | 5 +- eth/gasprice/gasprice_test.go | 9 +- eth/tracers/api.go | 122 +++++++++++++++++----------- eth/tracers/api_test.go | 15 ++-- eth/tracers/tracersutils/types.go | 11 +++ lib/ethapi/api.go | 28 +++---- lib/ethapi/api_test.go | 19 +++-- lib/ethapi/backend.go | 5 +- lib/ethapi/transaction_args_test.go | 9 +- 13 files changed, 153 insertions(+), 104 deletions(-) create mode 100644 eth/tracers/tracersutils/types.go diff --git a/cmd/geth/logging_test.go b/cmd/geth/logging_test.go index 50991554b4..e41d4c2213 100644 --- a/cmd/geth/logging_test.go +++ b/cmd/geth/logging_test.go @@ -21,6 +21,7 @@ package main import ( "bufio" "bytes" + "encoding/json" "fmt" "io" "math/rand" @@ -28,9 +29,8 @@ import ( "os/exec" "strings" "testing" - "encoding/json" - "github.com/ethereum/go-ethereum/internal/reexec" + "github.com/ethereum/go-ethereum/lib/reexec" ) func runSelf(args ...string) ([]byte, error) { diff --git a/cmd/geth/logtestcmd_active.go b/cmd/geth/logtestcmd_active.go index 5cce1ec6ab..f3be4cabcc 100644 --- a/cmd/geth/logtestcmd_active.go +++ b/cmd/geth/logtestcmd_active.go @@ -26,7 +26,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/lib/debug" "github.com/ethereum/go-ethereum/log" "github.com/holiman/uint256" "github.com/urfave/cli/v2" diff --git a/eth/api_backend.go b/eth/api_backend.go index 9a0c90396d..da8dce3c1d 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -34,6 +34,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/gasprice" "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/lib/ethapi" @@ -115,39 +116,39 @@ func (b *EthAPIBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*ty return b.eth.blockchain.GetHeaderByHash(hash), nil } -func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { +func (b *EthAPIBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) { // Pending block is only known by the miner if number == rpc.PendingBlockNumber { block := b.eth.miner.PendingBlock() if block == nil { - return nil, errors.New("pending block is not available") + return nil, nil, errors.New("pending block is not available") } - return block, nil + return block, nil, nil } // Otherwise resolve and return the block if number == rpc.LatestBlockNumber { header := b.eth.blockchain.CurrentBlock() - return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil, nil } if number == rpc.FinalizedBlockNumber { header := b.eth.blockchain.CurrentFinalBlock() if header == nil { - return nil, errors.New("finalized block not found") + return nil, nil, errors.New("finalized block not found") } - return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil, nil } if number == rpc.SafeBlockNumber { header := b.eth.blockchain.CurrentSafeBlock() if header == nil { - return nil, errors.New("safe block not found") + return nil, nil, errors.New("safe block not found") } - return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil + return b.eth.blockchain.GetBlock(header.Hash(), header.Number.Uint64()), nil, nil } - return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil + return b.eth.blockchain.GetBlockByNumber(uint64(number)), nil, nil } -func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return b.eth.blockchain.GetBlockByHash(hash), nil +func (b *EthAPIBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + return b.eth.blockchain.GetBlockByHash(hash), nil, nil } // GetBody returns body of a block. It does not resolve special block numbers. @@ -163,7 +164,8 @@ func (b *EthAPIBackend) GetBody(ctx context.Context, hash common.Hash, number rp func (b *EthAPIBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { if blockNr, ok := blockNrOrHash.Number(); ok { - return b.BlockByNumber(ctx, blockNr) + b, _, err := b.BlockByNumber(ctx, blockNr) + return b, err } if hash, ok := blockNrOrHash.Hash(); ok { header := b.eth.blockchain.GetHeaderByHash(hash) diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index 226991b24b..3a9535f5ff 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -273,7 +273,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks uint64, unresolvedL results <- fees } else { if len(rewardPercentiles) != 0 { - fees.block, fees.err = oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNumber)) + fees.block, _, fees.err = oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNumber)) if fees.block != nil && fees.err == nil { fees.receipts, fees.err = oracle.backend.GetReceipts(ctx, fees.block.Hash()) fees.header = fees.block.Header() diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index b719649811..6d6a4af0f0 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/common/lru" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" @@ -52,7 +53,7 @@ type Config struct { // OracleBackend includes all necessary background APIs for oracle. type OracleBackend interface { HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) - BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) + BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) PendingBlockAndReceipts() (*types.Block, types.Receipts) ChainConfig() *params.ChainConfig @@ -232,7 +233,7 @@ type results struct { // are sent by the miner itself(it doesn't make any sense to include this kind of // transaction prices for sampling), nil gasprice is returned. func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit int, ignoreUnder *big.Int, result chan results, quit chan struct{}) { - block, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) + block, _, err := oracle.backend.BlockByNumber(ctx, rpc.BlockNumber(blockNum)) if block == nil { select { case result <- results{nil, err}: diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 4ee5a0d1b2..b973d3c28b 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -29,6 +29,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" @@ -67,9 +68,9 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber return b.chain.GetHeaderByNumber(uint64(number)), nil } -func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { +func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) { if number > testHead { - return nil, nil + return nil, nil, nil } if number == rpc.EarliestBlockNumber { number = 0 @@ -87,10 +88,10 @@ func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) if b.pending { number = testHead + 1 } else { - return nil, nil + return nil, nil, nil } } - return b.chain.GetBlockByNumber(uint64(number)), nil + return b.chain.GetBlockByNumber(uint64(number)), nil, nil } func (b *testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) { diff --git a/eth/tracers/api.go b/eth/tracers/api.go index df6c7f6e65..6271890670 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/lib/ethapi" "github.com/ethereum/go-ethereum/log" @@ -80,8 +81,8 @@ type StateReleaseFunc func() type Backend interface { HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) - BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) - BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) + BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) + BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) RPCGasCap() uint64 ChainConfig() *params.ChainConfig @@ -112,28 +113,28 @@ func (api *API) chainContext(ctx context.Context) core.ChainContext { // blockByNumber is the wrapper of the chain access function offered by the backend. // It will return an error if the block is not found. -func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { - block, err := api.backend.BlockByNumber(ctx, number) +func (api *API) blockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + block, metadata, err := api.backend.BlockByNumber(ctx, number) if err != nil { - return nil, err + return nil, nil, err } if block == nil { - return nil, fmt.Errorf("block #%d not found", number) + return nil, nil, fmt.Errorf("block #%d not found", number) } - return block, nil + return block, metadata, nil } // blockByHash is the wrapper of the chain access function offered by the backend. // It will return an error if the block is not found. -func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - block, err := api.backend.BlockByHash(ctx, hash) +func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + block, metadata, err := api.backend.BlockByHash(ctx, hash) if err != nil { - return nil, err + return nil, nil, err } if block == nil { - return nil, fmt.Errorf("block %s not found", hash.Hex()) + return nil, nil, fmt.Errorf("block %s not found", hash.Hex()) } - return block, nil + return block, metadata, nil } // blockByNumberAndHash is the wrapper of the chain access function offered by @@ -141,13 +142,13 @@ func (api *API) blockByHash(ctx context.Context, hash common.Hash) (*types.Block // // Note this function is friendly for the light client which can only retrieve the // historical(before the CHT) header/block by number. -func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, error) { - block, err := api.blockByNumber(ctx, number) +func (api *API) blockByNumberAndHash(ctx context.Context, number rpc.BlockNumber, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + block, metadata, err := api.blockByNumber(ctx, number) if err != nil { - return nil, err + return nil, nil, err } if block.Hash() == hash { - return block, nil + return block, metadata, nil } return api.blockByHash(ctx, hash) } @@ -213,11 +214,11 @@ type txTraceTask struct { // TraceChain returns the structured logs created during the execution of EVM // between two blocks (excluding start) and returns them as a JSON object. func (api *API) TraceChain(ctx context.Context, start, end rpc.BlockNumber, config *TraceConfig) (*rpc.Subscription, error) { // Fetch the block interval that we want to trace - from, err := api.blockByNumber(ctx, start) + from, _, err := api.blockByNumber(ctx, start) if err != nil { return nil, err } - to, err := api.blockByNumber(ctx, end) + to, _, err := api.blockByNumber(ctx, end) if err != nil { return nil, err } @@ -348,12 +349,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed log.Info("Tracing chain segment", "start", start.NumberU64(), "end", end.NumberU64(), "current", number, "transactions", traced, "elapsed", time.Since(begin)) } // Retrieve the parent block and target block for tracing. - block, err := api.blockByNumber(ctx, rpc.BlockNumber(number)) + block, _, err := api.blockByNumber(ctx, rpc.BlockNumber(number)) if err != nil { failed = err break } - next, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1)) + next, _, err := api.blockByNumber(ctx, rpc.BlockNumber(number+1)) if err != nil { failed = err break @@ -435,21 +436,21 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed // TraceBlockByNumber returns the structured logs created during the execution of // EVM and returns them as a JSON object. func (api *API) TraceBlockByNumber(ctx context.Context, number rpc.BlockNumber, config *TraceConfig) ([]*TxTraceResult, error) { - block, err := api.blockByNumber(ctx, number) + block, metadata, err := api.blockByNumber(ctx, number) if err != nil { return nil, err } - return api.traceBlock(ctx, block, config) + return api.traceBlock(ctx, block, metadata, config) } // TraceBlockByHash returns the structured logs created during the execution of // EVM and returns them as a JSON object. func (api *API) TraceBlockByHash(ctx context.Context, hash common.Hash, config *TraceConfig) ([]*TxTraceResult, error) { - block, err := api.blockByHash(ctx, hash) + block, metadata, err := api.blockByHash(ctx, hash) if err != nil { return nil, err } - return api.traceBlock(ctx, block, config) + return api.traceBlock(ctx, block, metadata, config) } // TraceBlock returns the structured logs created during the execution of EVM @@ -459,7 +460,7 @@ func (api *API) TraceBlock(ctx context.Context, blob hexutil.Bytes, config *Trac if err := rlp.DecodeBytes(blob, block); err != nil { return nil, fmt.Errorf("could not decode block: %v", err) } - return api.traceBlock(ctx, block, config) + return api.traceBlock(ctx, block, nil, config) } // TraceBlockFromFile returns the structured logs created during the execution of @@ -480,14 +481,14 @@ func (api *API) TraceBadBlock(ctx context.Context, hash common.Hash, config *Tra if block == nil { return nil, fmt.Errorf("bad block %#x not found", hash) } - return api.traceBlock(ctx, block, config) + return api.traceBlock(ctx, block, nil, config) } // StandardTraceBlockToFile dumps the structured logs created during the // execution of EVM to the local file system and returns a list of files // to the caller. func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, config *StdTraceConfig) ([]string, error) { - block, err := api.blockByHash(ctx, hash) + block, _, err := api.blockByHash(ctx, hash) if err != nil { return nil, err } @@ -497,7 +498,7 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, // IntermediateRoots executes a block (bad- or canon- or side-), and returns a list // of intermediate roots: the stateroot after each transaction. func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) { - block, _ := api.blockByHash(ctx, hash) + block, _, _ := api.blockByHash(ctx, hash) if block == nil { // Check in the bad blocks block = rawdb.ReadBadBlock(api.backend.ChainDb(), hash) @@ -508,7 +509,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") } - parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) + parent, _, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) if err != nil { return nil, err } @@ -570,12 +571,12 @@ func (api *API) StandardTraceBadBlockToFile(ctx context.Context, hash common.Has // traceBlock configures a new tracer according to the provided configuration, and // executes all the transactions contained within. The return value will be one item // per transaction, dependent on the requested tracer. -func (api *API) traceBlock(ctx context.Context, block *types.Block, config *TraceConfig) ([]*TxTraceResult, error) { +func (api *API) traceBlock(ctx context.Context, block *types.Block, metadata []tracersutils.TraceBlockMetadata, config *TraceConfig) ([]*TxTraceResult, error) { if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") } // Prepare base state - parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) + parent, _, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) if err != nil { return nil, err } @@ -608,20 +609,47 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) results = make([]*TxTraceResult, len(txs)) ) - for i, tx := range txs { - // Generate the next state snapshot fast without tracing - msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) - txctx := &Context{ - BlockHash: blockHash, - BlockNumber: block.Number(), - TxIndex: i, - TxHash: tx.Hash(), + if len(metadata) == 0 { + for i, tx := range txs { + // Generate the next state snapshot fast without tracing + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + txctx := &Context{ + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: i, + TxHash: tx.Hash(), + } + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config) + if err != nil { + results[i] = &TxTraceResult{TxHash: tx.Hash(), Error: err.Error()} + } else { + results[i] = &TxTraceResult{TxHash: tx.Hash(), Result: res} + } } - res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config) - if err != nil { - results[i] = &TxTraceResult{TxHash: tx.Hash(), Error: err.Error()} + return results, nil + } + for _, md := range metadata { + if md.ShouldIncludeInTraceResult { + i := md.IdxInEthBlock + tx := txs[i] + // Generate the next state snapshot fast without tracing + msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) + txctx := &Context{ + BlockHash: blockHash, + BlockNumber: block.Number(), + TxIndex: i, + TxHash: tx.Hash(), + } + res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config) + if err != nil { + results[i] = &TxTraceResult{TxHash: tx.Hash(), Error: err.Error()} + } else { + results[i] = &TxTraceResult{TxHash: tx.Hash(), Result: res} + } } else { - results[i] = &TxTraceResult{TxHash: tx.Hash(), Result: res} + // should not be included in result but still needs to be run because + // these txs may affect cumulative state + md.TraceRunnable(statedb) } } return results, nil @@ -729,7 +757,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block if block.NumberU64() == 0 { return nil, errors.New("genesis is not traceable") } - parent, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) + parent, _, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(block.NumberU64()-1), block.ParentHash()) if err != nil { return nil, err } @@ -868,7 +896,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config * if config != nil && config.Reexec != nil { reexec = *config.Reexec } - block, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash) + block, _, err := api.blockByNumberAndHash(ctx, rpc.BlockNumber(blockNumber), blockHash) if err != nil { return nil, err } @@ -913,7 +941,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc release StateReleaseFunc ) if hash, ok := blockNrOrHash.Hash(); ok { - block, err = api.blockByHash(ctx, hash) + block, _, err = api.blockByHash(ctx, hash) } else if number, ok := blockNrOrHash.Number(); ok { if number == rpc.PendingBlockNumber { // We don't have access to the miner here. For tracing 'future' transactions, @@ -923,7 +951,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc // of what the next actual block is likely to contain. return nil, errors.New("tracing on top of pending is not supported") } - block, err = api.blockByNumber(ctx, number) + block, _, err = api.blockByNumber(ctx, number) } else { return nil, errors.New("invalid arguments; neither block nor hash specified") } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 4ffff3723b..0dffff4a70 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -38,6 +38,7 @@ import ( "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/tracers/logger" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/lib/ethapi" "github.com/ethereum/go-ethereum/params" @@ -101,15 +102,15 @@ func (b *testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber return b.chain.GetHeaderByNumber(uint64(number)), nil } -func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return b.chain.GetBlockByHash(hash), nil +func (b *testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + return b.chain.GetBlockByHash(hash), nil, nil } -func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { +func (b *testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) { if number == rpc.PendingBlockNumber || number == rpc.LatestBlockNumber { - return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil + return b.chain.GetBlockByNumber(b.chain.CurrentBlock().Number.Uint64()), nil, nil } - return b.chain.GetBlockByNumber(uint64(number)), nil + return b.chain.GetBlockByNumber(uint64(number)), nil, nil } func (b *testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) { @@ -1043,8 +1044,8 @@ func TestTraceChain(t *testing.T) { ref.Store(0) rel.Store(0) - from, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) - to, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) + from, _, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.start)) + to, _, _ := api.blockByNumber(context.Background(), rpc.BlockNumber(c.end)) resCh := api.traceChain(from, to, c.config, nil) next := c.start + 1 diff --git a/eth/tracers/tracersutils/types.go b/eth/tracers/tracersutils/types.go new file mode 100644 index 0000000000..698e427511 --- /dev/null +++ b/eth/tracers/tracersutils/types.go @@ -0,0 +1,11 @@ +package tracersutils + +import "github.com/ethereum/go-ethereum/core/vm" + +type TraceBlockMetadata struct { + ShouldIncludeInTraceResult bool + // must be set if shouldIncludeInTraceResult + IdxInEthBlock int + // must be set if !shouldIncludeInTraceResult + TraceRunnable func(vm.StateDB) +} diff --git a/lib/ethapi/api.go b/lib/ethapi/api.go index 2483358702..b1e1004982 100644 --- a/lib/ethapi/api.go +++ b/lib/ethapi/api.go @@ -807,7 +807,7 @@ func (s *BlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.Hash) m // - When fullTx is true all transactions in the block are returned, otherwise // only the transaction hash is returned. func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, number) + block, _, err := s.b.BlockByNumber(ctx, number) if block != nil && err == nil { response, err := s.rpcMarshalBlock(ctx, block, true, fullTx) if err == nil && number == rpc.PendingBlockNumber { @@ -824,7 +824,7 @@ func (s *BlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNu // GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full // detail, otherwise only the transaction hash is returned. func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) { - block, err := s.b.BlockByHash(ctx, hash) + block, _, err := s.b.BlockByHash(ctx, hash) if block != nil { return s.rpcMarshalBlock(ctx, block, true, fullTx) } @@ -833,7 +833,7 @@ func (s *BlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fu // GetUncleByBlockNumberAndIndex returns the uncle block for the given block hash and index. func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) (map[string]interface{}, error) { - block, err := s.b.BlockByNumber(ctx, blockNr) + block, _, err := s.b.BlockByNumber(ctx, blockNr) if block != nil { uncles := block.Uncles() if index >= hexutil.Uint(len(uncles)) { @@ -848,7 +848,7 @@ func (s *BlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context, block // GetUncleByBlockHashAndIndex returns the uncle block for the given block hash and index. func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) (map[string]interface{}, error) { - block, err := s.b.BlockByHash(ctx, blockHash) + block, _, err := s.b.BlockByHash(ctx, blockHash) if block != nil { uncles := block.Uncles() if index >= hexutil.Uint(len(uncles)) { @@ -863,7 +863,7 @@ func (s *BlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, blockHa // GetUncleCountByBlockNumber returns number of uncles in the block for the given block number func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + if block, _, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n } @@ -872,7 +872,7 @@ func (s *BlockChainAPI) GetUncleCountByBlockNumber(ctx context.Context, blockNr // GetUncleCountByBlockHash returns number of uncles in the block for the given block hash func (s *BlockChainAPI) GetUncleCountByBlockHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + if block, _, _ := s.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Uncles())) return &n } @@ -1619,7 +1619,7 @@ func NewTransactionAPI(b Backend, nonceLock *AddrLocker) *TransactionAPI { // GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number. func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + if block, _, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n } @@ -1628,7 +1628,7 @@ func (s *TransactionAPI) GetBlockTransactionCountByNumber(ctx context.Context, b // GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash. func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + if block, _, _ := s.b.BlockByHash(ctx, blockHash); block != nil { n := hexutil.Uint(len(block.Transactions())) return &n } @@ -1637,7 +1637,7 @@ func (s *TransactionAPI) GetBlockTransactionCountByHash(ctx context.Context, blo // GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index. func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + if block, _, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) } return nil @@ -1645,7 +1645,7 @@ func (s *TransactionAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context // GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index. func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + if block, _, _ := s.b.BlockByHash(ctx, blockHash); block != nil { return newRPCTransactionFromBlockIndex(block, uint64(index), s.b.ChainConfig()) } return nil @@ -1653,7 +1653,7 @@ func (s *TransactionAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, // GetRawTransactionByBlockNumberAndIndex returns the bytes of the transaction for the given block number and index. func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) hexutil.Bytes { - if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { + if block, _, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil @@ -1661,7 +1661,7 @@ func (s *TransactionAPI) GetRawTransactionByBlockNumberAndIndex(ctx context.Cont // GetRawTransactionByBlockHashAndIndex returns the bytes of the transaction for the given block hash and index. func (s *TransactionAPI) GetRawTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) hexutil.Bytes { - if block, _ := s.b.BlockByHash(ctx, blockHash); block != nil { + if block, _, _ := s.b.BlockByHash(ctx, blockHash); block != nil { return newRPCRawTransactionFromBlockIndex(block, uint64(index)) } return nil @@ -2078,7 +2078,7 @@ func (api *DebugAPI) GetRawBlock(ctx context.Context, blockNrOrHash rpc.BlockNum } hash = block.Hash() } - block, _ := api.b.BlockByHash(ctx, hash) + block, _, _ := api.b.BlockByHash(ctx, hash) if block == nil { return nil, fmt.Errorf("block #%d not found", hash) } @@ -2130,7 +2130,7 @@ func (s *DebugAPI) GetRawTransaction(ctx context.Context, hash common.Hash) (hex // PrintBlock retrieves a block and returns its pretty printed form. func (api *DebugAPI) PrintBlock(ctx context.Context, number uint64) (string, error) { - block, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) + block, _, _ := api.b.BlockByNumber(ctx, rpc.BlockNumber(number)) if block == nil { return "", fmt.Errorf("block #%d not found", number) } diff --git a/lib/ethapi/api_test.go b/lib/ethapi/api_test.go index 24772436f3..6424207755 100644 --- a/lib/ethapi/api_test.go +++ b/lib/ethapi/api_test.go @@ -42,6 +42,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/lib/blocktest" @@ -475,25 +476,27 @@ func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc } func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentBlock() } func (b testBackend) CurrentBlock() *types.Header { return b.chain.CurrentBlock() } -func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { +func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) { if number == rpc.LatestBlockNumber { head := b.chain.CurrentBlock() - return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil + return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil, nil } if number == rpc.PendingBlockNumber { - return b.pending, nil + return b.pending, nil, nil } - return b.chain.GetBlockByNumber(uint64(number)), nil + return b.chain.GetBlockByNumber(uint64(number)), nil, nil } -func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return b.chain.GetBlockByHash(hash), nil +func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + return b.chain.GetBlockByHash(hash), nil, nil } func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { if blockNr, ok := blockNrOrHash.Number(); ok { - return b.BlockByNumber(ctx, blockNr) + b, _, err := b.BlockByNumber(ctx, blockNr) + return b, err } if blockHash, ok := blockNrOrHash.Hash(); ok { - return b.BlockByHash(ctx, blockHash) + b, _, err := b.BlockByHash(ctx, blockHash) + return b, err } panic("unknown type rpc.BlockNumberOrHash") } diff --git a/lib/ethapi/backend.go b/lib/ethapi/backend.go index 28e50bcbf9..f2ff5da89e 100644 --- a/lib/ethapi/backend.go +++ b/lib/ethapi/backend.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -59,8 +60,8 @@ type Backend interface { HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) CurrentHeader() *types.Header CurrentBlock() *types.Header - BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) - BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) + BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) + BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (vm.StateDB, *types.Header, error) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (vm.StateDB, *types.Header, error) diff --git a/lib/ethapi/transaction_args_test.go b/lib/ethapi/transaction_args_test.go index de629a3ac2..f35efacc30 100644 --- a/lib/ethapi/transaction_args_test.go +++ b/lib/ethapi/transaction_args_test.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core/bloombits" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/eth/tracers/tracersutils" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/params" @@ -278,11 +279,11 @@ func (b *backendMock) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rp return nil, nil } func (b *backendMock) CurrentBlock() *types.Header { return nil } -func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) { - return nil, nil +func (b *backendMock) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + return nil, nil, nil } -func (b *backendMock) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) { - return nil, nil +func (b *backendMock) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, []tracersutils.TraceBlockMetadata, error) { + return nil, nil, nil } func (b *backendMock) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) { return nil, nil