Skip to content

Commit

Permalink
eth, les: properly init statedb accesslist during tracing (ethereum#2…
Browse files Browse the repository at this point in the history
…2480)

* eth/state, les/state: properly init statedb accesslist when tracing, fixes ethereum#22475

* eth: review comments

* eth/tracers: fix compilation err

* eth/tracers: apply @karalabe's suggested fix
  • Loading branch information
holiman authored and atif-konasl committed Oct 15, 2021
1 parent 1e08590 commit eb2e13a
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 9 deletions.
1 change: 1 addition & 0 deletions eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ func (eth *Ethereum) stateAtTransaction(block *types.Block, txIndex int, reexec
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
statedb.Prepare(tx.Hash(), block.Hash(), idx)
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
release()
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
Expand Down
45 changes: 36 additions & 9 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,13 @@ type StdTraceConfig struct {
TxHash common.Hash
}

// txTraceContext is the contextual infos about a transaction before it gets run.
type txTraceContext struct {
index int // Index of the transaction within the block
hash common.Hash // Hash of the transaction
block common.Hash // Hash of the block containing the transaction
}

// txTraceResult is the result of a single transaction trace.
type txTraceResult struct {
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
Expand Down Expand Up @@ -266,7 +273,12 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
msg, _ := tx.AsMessage(signer)
res, err := api.traceTx(ctx, msg, blockCtx, task.statedb, config)
txctx := &txTraceContext{
index: i,
hash: tx.Hash(),
block: task.block.Hash(),
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
if err != nil {
task.results[i] = &txTraceResult{Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
Expand Down Expand Up @@ -478,14 +490,20 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
threads = len(txs)
}
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
blockHash := block.Hash()
for th := 0; th < threads; th++ {
pend.Add(1)
go func() {
defer pend.Done()
// Fetch and execute the next transaction trace tasks
for task := range jobs {
msg, _ := txs[task.index].AsMessage(signer)
res, err := api.traceTx(ctx, msg, blockCtx, task.statedb, config)
txctx := &txTraceContext{
index: task.index,
hash: txs[task.index].Hash(),
block: blockHash,
}
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
if err != nil {
results[task.index] = &txTraceResult{Error: err.Error()}
continue
Expand All @@ -502,9 +520,8 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac

// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer)
txContext := core.NewEVMTxContext(msg)

vmenv := vm.NewEVM(blockCtx, txContext, statedb, api.backend.ChainConfig(), vm.Config{})
statedb.Prepare(tx.Hash(), block.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
failed = err
break
Expand Down Expand Up @@ -619,6 +636,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
}
// Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.Prepare(tx.Hash(), block.Hash(), i)
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
if writer != nil {
writer.Flush()
Expand Down Expand Up @@ -678,7 +696,12 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
}
defer release()

return api.traceTx(ctx, msg, vmctx, statedb, config)
txctx := &txTraceContext{
index: int(index),
hash: hash,
block: blockHash,
}
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
}

// TraceCall lets you trace a given eth_call. It collects the structured logs
Expand Down Expand Up @@ -713,13 +736,14 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.CallArgs, blockNrOrHa
// Execute the trace
msg := args.ToMessage(api.backend.RPCGasCap())
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
return api.traceTx(ctx, msg, vmctx, statedb, config)

return api.traceTx(ctx, msg, new(txTraceContext), vmctx, statedb, config)
}

// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (api *API) traceTx(ctx context.Context, message core.Message, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTraceContext, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
// Assemble the structured logger or the JavaScript tracer
var (
tracer vm.Tracer
Expand Down Expand Up @@ -753,9 +777,12 @@ func (api *API) traceTx(ctx context.Context, message core.Message, vmctx vm.Bloc
default:
tracer = vm.NewStructLogger(config.LogConfig)
}

// Run the transaction with tracing enabled.
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer})

// Call Prepare to clear out the statedb access list
statedb.Prepare(txctx.hash, txctx.block, txctx.index)

result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
if err != nil {
return nil, fmt.Errorf("tracing failed: %v", err)
Expand Down
1 change: 1 addition & 0 deletions les/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
msg, _ := tx.AsMessage(signer)
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
statedb.Prepare(tx.Hash(), block.Hash(), idx)
if idx == txIndex {
return msg, context, statedb, func() {}, nil
}
Expand Down

0 comments on commit eb2e13a

Please sign in to comment.