Skip to content

core/vm, eth/tracers: simplify interpreter loop #32160

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
snapshot = statedb.Snapshot()
prevGas = gaspool.Gas()
)
if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil {
if evm.Config.Tracer.OnTxStart != nil {
evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
}
// (ret []byte, usedGas uint64, failed bool, err error)
Expand All @@ -265,7 +265,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
gaspool.SetGas(prevGas)
if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxEnd != nil {
if evm.Config.Tracer.OnTxEnd != nil {
evm.Config.Tracer.OnTxEnd(nil, err)
}
continue
Expand Down Expand Up @@ -311,7 +311,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
//receipt.BlockNumber
receipt.TransactionIndex = uint(txIndex)
receipts = append(receipts, receipt)
if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxEnd != nil {
if evm.Config.Tracer.OnTxEnd != nil {
evm.Config.Tracer.OnTxEnd(receipt, nil)
}
}
Expand Down
31 changes: 18 additions & 13 deletions cmd/evm/internal/t8ntool/file_tracer.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import (
// and on tx end it closes the file.
type fileWritingTracer struct {
txIndex int // transaction counter
inner *tracing.Hooks // inner hooks
inner tracing.Hooks // inner hooks
destination io.WriteCloser // the currently open file (if any)
baseDir string // baseDir to write output-files to
suffix string // suffix is the suffix to use when creating files
Expand All @@ -58,7 +58,7 @@ func (l *fileWritingTracer) Write(p []byte) (n int, err error) {

// newFileWriter creates a set of hooks which wraps inner hooks (typically a logger),
// and writes the output to a file, one file per transaction.
func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) *tracing.Hooks {
func newFileWriter(baseDir string, innerFn func(out io.Writer) tracing.Hooks) tracing.Hooks {
t := &fileWritingTracer{
baseDir: baseDir,
suffix: "jsonl",
Expand All @@ -69,7 +69,7 @@ func newFileWriter(baseDir string, innerFn func(out io.Writer) *tracing.Hooks) *

// newResultWriter creates a set of hooks wraps and invokes an underlying tracer,
// and writes the result (getResult-output) to file, one per transaction.
func newResultWriter(baseDir string, tracer *tracers.Tracer) *tracing.Hooks {
func newResultWriter(baseDir string, tracer *tracers.Tracer) tracing.Hooks {
t := &fileWritingTracer{
baseDir: baseDir,
getResult: tracer.GetResult,
Expand All @@ -91,15 +91,15 @@ func (l *fileWritingTracer) OnTxStart(env *tracing.VMContext, tx *types.Transact
log.Info("Created tracing-file", "path", fname)
l.destination = traceFile
}
if l.inner != nil && l.inner.OnTxStart != nil {
if l.inner.OnTxStart != nil {
l.inner.OnTxStart(env, tx, from)
}
}

// OnTxEnd writes result (if getResult exist), closes any currently open output-file,
// and invokes the inner OnTxEnd handler.
func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) {
if l.inner != nil && l.inner.OnTxEnd != nil {
if l.inner.OnTxEnd != nil {
l.inner.OnTxEnd(receipt, err)
}
if l.getResult != nil && l.destination != nil {
Expand All @@ -114,39 +114,44 @@ func (l *fileWritingTracer) OnTxEnd(receipt *types.Receipt, err error) {
l.txIndex++
}

func (l *fileWritingTracer) hooks() *tracing.Hooks {
return &tracing.Hooks{
func (l *fileWritingTracer) hooks() tracing.Hooks {
return tracing.Hooks{
OnTxStart: l.OnTxStart,
OnTxEnd: l.OnTxEnd,
OnEnter: func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
if l.inner != nil && l.inner.OnEnter != nil {
if l.inner.OnEnter != nil {
l.inner.OnEnter(depth, typ, from, to, input, gas, value)
}
},
OnExit: func(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
if l.inner != nil && l.inner.OnExit != nil {
if l.inner.OnExit != nil {
l.inner.OnExit(depth, output, gasUsed, err, reverted)
}
},
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
if l.inner != nil && l.inner.OnOpcode != nil {
if l.inner.OnOpcode != nil {
l.inner.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
}
},
OnFault: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
if l.inner != nil && l.inner.OnFault != nil {
if l.inner.OnFault != nil {
l.inner.OnFault(pc, op, gas, cost, scope, depth, err)
}
},
OnSystemCallStart: func() {
if l.inner != nil && l.inner.OnSystemCallStart != nil {
if l.inner.OnSystemCallStart != nil {
l.inner.OnSystemCallStart()
}
},
OnSystemCallEnd: func() {
if l.inner != nil && l.inner.OnSystemCallEnd != nil {
if l.inner.OnSystemCallEnd != nil {
l.inner.OnSystemCallEnd()
}
},
OnGasChange: func(old, new uint64, reason tracing.GasChangeReason) {
if l.inner.OnGasChange != nil {
l.inner.OnGasChange(old, new, reason)
}
},
}
}
4 changes: 2 additions & 2 deletions cmd/evm/internal/t8ntool/transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ func Transition(ctx *cli.Context) error {
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
}
if ctx.Bool(TraceEnableCallFramesFlag.Name) {
vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks {
vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) tracing.Hooks {
return logger.NewJSONLoggerWithCallFrames(logConfig, out)
})
} else {
vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) *tracing.Hooks {
vmConfig.Tracer = newFileWriter(baseDir, func(out io.Writer) tracing.Hooks {
return logger.NewJSONLogger(logConfig, out)
})
}
Expand Down
6 changes: 3 additions & 3 deletions cmd/evm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func main() {
}

// tracerFromFlags parses the cli flags and returns the specified tracer.
func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
func tracerFromFlags(ctx *cli.Context) tracing.Hooks {
config := &logger.Config{
EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name),
DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
Expand All @@ -248,15 +248,15 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
default:
fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format)
os.Exit(1)
return nil
return tracing.Hooks{}
}
// Deprecated ways of configuring tracing.
case ctx.Bool(MachineFlag.Name):
return logger.NewJSONLogger(config, os.Stderr)
case ctx.Bool(DebugFlag.Name):
return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
default:
return nil
return tracing.Hooks{}
}
}

Expand Down
10 changes: 5 additions & 5 deletions cmd/evm/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, exe

func runCmd(ctx *cli.Context) error {
var (
tracer *tracing.Hooks
tracer tracing.Hooks
prestate *state.StateDB
chainConfig *params.ChainConfig
sender = common.BytesToAddress([]byte("sender"))
Expand Down Expand Up @@ -363,11 +363,11 @@ allocations: %d
allocated bytes: %d
`, stats.GasUsed, stats.Time, stats.Allocs, stats.BytesAllocated)
}
if tracer == nil {
if len(output) > 0 {
fmt.Printf("%#x\n", output)
if err != nil {
fmt.Printf(" error: %v\n", err)
}
}
if err != nil {
fmt.Printf(" error: %v\n", err)
}

return nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,7 @@
{"pc":38,"op":82,"gas":"0x65ee4","gasCost":"0x6","memSize":0,"stack":["0x10","0x0"],"depth":2,"refund":0,"opName":"MSTORE"}
{"pc":39,"op":96,"gas":"0x65ede","gasCost":"0x3","memSize":32,"stack":[],"depth":2,"refund":0,"opName":"PUSH1"}
{"pc":41,"op":96,"gas":"0x65edb","gasCost":"0x3","memSize":32,"stack":["0x20"],"depth":2,"refund":0,"opName":"PUSH1"}
{"pc":43,"op":253,"gas":"0x65ed8","gasCost":"0x0","memSize":32,"stack":["0x20","0x0"],"depth":2,"refund":0,"opName":"REVERT"}
{"pc":43,"op":253,"gas":"0x65ed8","gasCost":"0x0","memSize":32,"stack":[],"depth":2,"refund":0,"opName":"REVERT","error":"execution reverted"}
{"pc":43,"op":253,"gas":"0x65ed8","gasCost":"0x0","memSize":32,"stack":["0x20","0x0"],"depth":2,"refund":0,"opName":"REVERT","error":"execution reverted"}
{"output":"0000000000000000000000000000000000000000000000000000000000000010","gasUsed":"0x2e44","error":"execution reverted"}
{"pc":69,"op":96,"gas":"0x67976","gasCost":"0x3","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"PUSH1"}
{"pc":71,"op":85,"gas":"0x67973","gasCost":"0x1388","memSize":0,"stack":["0x0","0x2"],"depth":1,"refund":4800,"opName":"SSTORE"}
Expand Down
2 changes: 1 addition & 1 deletion cmd/evm/testdata/evmrun/7.out.2.txt
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,7 @@ Pre-execution info:
| 20 | PUSH1 | 3 | 19900 |[0x0,0x0,0x0,0x0,0x0] |
| 22 | GAS | 2 | 19900 |[0x0,0x0,0x0,0x0,0x0,0xf9] |
| 23 | CALLCODE | 100 | 19900 |[0x0,0x0,0x0,0x0,0x0,0xf9,0x885] |
Error: out of gas: out of gas
Error: at pc=23, op=242: out of gas: out of gas
| 1786 | POP | 2 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26,0x0] |
| 1787 | POP | 2 | 0 |[0x94a843a7335fc63be036fbdecc40b1365f3c5f26] |
| 1788 | STOP | 0 | 0 | [] |
Expand Down
16 changes: 8 additions & 8 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ type BlockChain struct {
validator Validator // Block and state validator interface
prefetcher Prefetcher
processor Processor // Block transaction processor interface
logger *tracing.Hooks
logger tracing.Hooks

lastForkReadyAlert time.Time // Last time there was a fork readiness print out
}
Expand Down Expand Up @@ -489,10 +489,10 @@ func NewBlockChain(db ethdb.Database, genesis *Genesis, engine consensus.Engine,
// it in advance.
bc.engine.VerifyHeader(bc, bc.CurrentHeader())

if bc.logger != nil && bc.logger.OnBlockchainInit != nil {
if bc.logger.OnBlockchainInit != nil {
bc.logger.OnBlockchainInit(chainConfig)
}
if bc.logger != nil && bc.logger.OnGenesisBlock != nil {
if bc.logger.OnGenesisBlock != nil {
if block := bc.CurrentBlock(); block.Number.Uint64() == 0 {
alloc, err := getGenesisState(bc.db, block.Hash())
if err != nil {
Expand Down Expand Up @@ -1309,7 +1309,7 @@ func (bc *BlockChain) Stop() {
}
}
// Allow tracers to clean-up and release resources.
if bc.logger != nil && bc.logger.OnClose != nil {
if bc.logger.OnClose != nil {
bc.logger.OnClose()
}
// Close the trie database, release all the held resources as the last step.
Expand Down Expand Up @@ -1860,7 +1860,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
return nil, it.index, err
}
stats.processed++
if bc.logger != nil && bc.logger.OnSkippedBlock != nil {
if bc.logger.OnSkippedBlock != nil {
bc.logger.OnSkippedBlock(tracing.BlockEvent{
Block: block,
Finalized: bc.CurrentFinalBlock(),
Expand Down Expand Up @@ -1996,7 +1996,7 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
go func(start time.Time, throwaway *state.StateDB, block *types.Block) {
// Disable tracing for prefetcher executions.
vmCfg := bc.cfg.VmConfig
vmCfg.Tracer = nil
vmCfg.Tracer = tracing.Hooks{}
bc.prefetcher.Prefetch(block, throwaway, vmCfg, &interrupt)

blockPrefetchExecuteTimer.Update(time.Since(start))
Expand Down Expand Up @@ -2024,14 +2024,14 @@ func (bc *BlockChain) processBlock(parentRoot common.Hash, block *types.Block, s
defer statedb.StopPrefetcher()
}

if bc.logger != nil && bc.logger.OnBlockStart != nil {
if bc.logger.OnBlockStart != nil {
bc.logger.OnBlockStart(tracing.BlockEvent{
Block: block,
Finalized: bc.CurrentFinalBlock(),
Safe: bc.CurrentSafeBlock(),
})
}
if bc.logger != nil && bc.logger.OnBlockEnd != nil {
if bc.logger.OnBlockEnd != nil {
defer func() {
bc.logger.OnBlockEnd(blockEndErr)
}()
Expand Down
10 changes: 3 additions & 7 deletions core/state/statedb_hooked.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,12 @@ import (
// on state operations.
type hookedStateDB struct {
inner *StateDB
hooks *tracing.Hooks
hooks tracing.Hooks
}

// NewHookedState wraps the given stateDb with the given hooks
func NewHookedState(stateDb *StateDB, hooks *tracing.Hooks) *hookedStateDB {
s := &hookedStateDB{stateDb, hooks}
if s.hooks == nil {
s.hooks = new(tracing.Hooks)
}
return s
func NewHookedState(stateDb *StateDB, hooks tracing.Hooks) *hookedStateDB {
return &hookedStateDB{stateDb, hooks}
}

func (s *hookedStateDB) CreateAccount(addr common.Address) {
Expand Down
4 changes: 2 additions & 2 deletions core/state/statedb_hooked_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestBurn(t *testing.T) {

var burned = new(uint256.Int)
s, _ := New(types.EmptyRootHash, NewDatabaseForTesting())
hooked := NewHookedState(s, &tracing.Hooks{
hooked := NewHookedState(s, tracing.Hooks{
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
if reason == tracing.BalanceDecreaseSelfdestructBurn {
burned.Add(burned, uint256.MustFromBig(prev))
Expand Down Expand Up @@ -94,7 +94,7 @@ func TestHooks(t *testing.T) {
emitF := func(format string, a ...any) {
result = append(result, fmt.Sprintf(format, a...))
}
sdb := NewHookedState(inner, &tracing.Hooks{
sdb := NewHookedState(inner, tracing.Hooks{
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
emitF("%v.balance: %v->%v (%v)", addr, prev, new, reason)
},
Expand Down
40 changes: 16 additions & 24 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg

// Apply pre-execution system calls.
var tracingStateDB = vm.StateDB(statedb)
if hooks := cfg.Tracer; hooks != nil {
tracingStateDB = state.NewHookedState(statedb, hooks)
if cfg.Tracer.HooksState() {
tracingStateDB = state.NewHookedState(statedb, cfg.Tracer)
}
context = NewEVMBlockContext(header, p.chain, nil)
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
Expand Down Expand Up @@ -137,13 +137,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// and uses the input parameters for its environment similar to ApplyTransaction. However,
// this method takes an already created EVM instance as input.
func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, blockTime uint64, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
if hooks := evm.Config.Tracer; hooks != nil {
if hooks.OnTxStart != nil {
hooks.OnTxStart(evm.GetVMContext(), tx, msg.From)
}
if hooks.OnTxEnd != nil {
defer func() { hooks.OnTxEnd(receipt, err) }()
}
if evm.Config.Tracer.OnTxStart != nil {
evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
}
if evm.Config.Tracer.OnTxEnd != nil {
defer func() { evm.Config.Tracer.OnTxEnd(receipt, err) }()
}
// Apply the transaction to the current state (included in the env).
result, err := ApplyMessage(evm, msg, gp)
Expand Down Expand Up @@ -215,11 +213,9 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil {
defer tracer.OnSystemCallEnd()
}
onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext())
if evm.Config.Tracer.OnSystemCallEnd != nil {
defer evm.Config.Tracer.OnSystemCallEnd()
}
msg := &Message{
From: params.SystemAddress,
Expand All @@ -239,11 +235,9 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
// ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935/7709.
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil {
defer tracer.OnSystemCallEnd()
}
onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext())
if evm.Config.Tracer.OnSystemCallEnd != nil {
defer evm.Config.Tracer.OnSystemCallEnd()
}
msg := &Message{
From: params.SystemAddress,
Expand Down Expand Up @@ -279,11 +273,9 @@ func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) error {
}

func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) error {
if tracer := evm.Config.Tracer; tracer != nil {
onSystemCallStart(tracer, evm.GetVMContext())
if tracer.OnSystemCallEnd != nil {
defer tracer.OnSystemCallEnd()
}
onSystemCallStart(&evm.Config.Tracer, evm.GetVMContext())
if evm.Config.Tracer.OnSystemCallEnd != nil {
defer evm.Config.Tracer.OnSystemCallEnd()
}
msg := &Message{
From: params.SystemAddress,
Expand Down
Loading