mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-24 13:46:43 +00:00
core, eth: use tracing.Hooks by value
the main motivation was to make Contract.UseGas and Contract.RefundGas inlinable.
This commit is contained in:
parent
83aa643621
commit
57fa10b206
43 changed files with 241 additions and 254 deletions
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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",
|
||||
|
|
@ -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,
|
||||
|
|
@ -91,7 +91,7 @@ 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ func (l *fileWritingTracer) OnTxStart(env *tracing.VMContext, tx *types.Transact
|
|||
// 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 {
|
||||
|
|
@ -114,37 +114,37 @@ 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()
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
@ -248,7 +248,7 @@ 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):
|
||||
|
|
@ -256,7 +256,7 @@ func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
|
|||
case ctx.Bool(DebugFlag.Name):
|
||||
return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
|
||||
default:
|
||||
return nil
|
||||
return tracing.Hooks{}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -329,7 +329,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
|
||||
}
|
||||
|
|
@ -491,10 +491,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 {
|
||||
|
|
@ -1311,7 +1311,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.
|
||||
|
|
@ -1862,7 +1862,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(),
|
||||
|
|
@ -1998,7 +1998,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))
|
||||
|
|
@ -2026,14 +2026,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)
|
||||
}()
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
@ -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)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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.HasStateHooks() {
|
||||
tracingStateDB = state.NewHookedState(statedb, cfg.Tracer)
|
||||
}
|
||||
context = NewEVMBlockContext(header, p.chain, nil)
|
||||
evm := vm.NewEVM(context, tracingStateDB, p.config, cfg)
|
||||
|
|
@ -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)
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ func (st *stateTransition) buyGas() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil {
|
||||
if st.evm.Config.Tracer.OnGasChange != nil {
|
||||
st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
|
||||
}
|
||||
st.gasRemaining = st.msg.GasLimit
|
||||
|
|
@ -456,8 +456,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas)
|
||||
}
|
||||
}
|
||||
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
||||
t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
|
||||
if st.evm.Config.Tracer.OnGasChange != nil {
|
||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
|
||||
}
|
||||
st.gasRemaining -= gas
|
||||
|
||||
|
|
@ -530,8 +530,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
|
|||
if st.gasUsed() < floorDataGas {
|
||||
prev := st.gasRemaining
|
||||
st.gasRemaining = st.initialGas - floorDataGas
|
||||
if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
|
||||
t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor)
|
||||
if st.evm.Config.Tracer.OnGasChange != nil {
|
||||
st.evm.Config.Tracer.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor)
|
||||
}
|
||||
}
|
||||
if peakGasUsed < floorDataGas {
|
||||
|
|
@ -640,7 +640,7 @@ func (st *stateTransition) calcRefund() uint64 {
|
|||
if refund > st.state.GetRefund() {
|
||||
refund = st.state.GetRefund()
|
||||
}
|
||||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 {
|
||||
if st.evm.Config.Tracer.OnGasChange != nil && refund > 0 {
|
||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds)
|
||||
}
|
||||
return refund
|
||||
|
|
@ -653,7 +653,7 @@ func (st *stateTransition) returnGas() {
|
|||
remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
|
||||
st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn)
|
||||
|
||||
if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 {
|
||||
if st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 {
|
||||
st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,8 @@ type (
|
|||
)
|
||||
|
||||
type Hooks struct {
|
||||
// VM events
|
||||
// VM events, make sure to update HasVMHooks
|
||||
// if you ever add a new hook here
|
||||
OnTxStart TxStartHook
|
||||
OnTxEnd TxEndHook
|
||||
OnEnter EnterHook
|
||||
|
|
@ -206,7 +207,8 @@ type Hooks struct {
|
|||
OnSystemCallStart OnSystemCallStartHook
|
||||
OnSystemCallStartV2 OnSystemCallStartHookV2
|
||||
OnSystemCallEnd OnSystemCallEndHook
|
||||
// State events
|
||||
// State events, make sure to update HasStateHooks
|
||||
// if you ever add a new hook here
|
||||
OnBalanceChange BalanceChangeHook
|
||||
OnNonceChange NonceChangeHook
|
||||
OnNonceChangeV2 NonceChangeHookV2
|
||||
|
|
@ -217,6 +219,27 @@ type Hooks struct {
|
|||
OnBlockHashRead BlockHashReadHook
|
||||
}
|
||||
|
||||
// HasVMHooks returns if any of the VM events are being hooked
|
||||
func (h *Hooks) HasVMHooks() bool {
|
||||
return h.OnTxStart != nil ||
|
||||
h.OnTxEnd != nil ||
|
||||
h.OnEnter != nil ||
|
||||
h.OnExit != nil ||
|
||||
h.OnOpcode != nil ||
|
||||
h.OnFault != nil ||
|
||||
h.OnGasChange != nil
|
||||
}
|
||||
|
||||
// HasStateHooks returns if any of the state events are being hooked
|
||||
func (h *Hooks) HasStateHooks() bool {
|
||||
return h.OnBalanceChange != nil ||
|
||||
h.OnNonceChange != nil ||
|
||||
h.OnNonceChangeV2 != nil ||
|
||||
h.OnCodeChange != nil ||
|
||||
h.OnStorageChange != nil ||
|
||||
h.OnLog != nil
|
||||
}
|
||||
|
||||
// BalanceChangeReason is used to indicate the reason for a balance change, useful
|
||||
// for tracing and reporting.
|
||||
type BalanceChangeReason byte
|
||||
|
|
|
|||
|
|
@ -126,24 +126,24 @@ func (c *Contract) Caller() common.Address {
|
|||
}
|
||||
|
||||
// UseGas attempts the use gas and subtracts it and returns true on success
|
||||
func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) {
|
||||
func (c *Contract) UseGas(gas uint64, onGasChange tracing.GasChangeHook, reason tracing.GasChangeReason) (ok bool) {
|
||||
if c.Gas < gas {
|
||||
return false
|
||||
}
|
||||
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
|
||||
logger.OnGasChange(c.Gas, c.Gas-gas, reason)
|
||||
if onGasChange != nil && reason != tracing.GasChangeIgnored {
|
||||
onGasChange(c.Gas, c.Gas-gas, reason)
|
||||
}
|
||||
c.Gas -= gas
|
||||
return true
|
||||
}
|
||||
|
||||
// RefundGas refunds gas to the contract
|
||||
func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
|
||||
func (c *Contract) RefundGas(gas uint64, onGasChange tracing.GasChangeHook, reason tracing.GasChangeReason) {
|
||||
if gas == 0 {
|
||||
return
|
||||
}
|
||||
if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
|
||||
logger.OnGasChange(c.Gas, c.Gas+gas, reason)
|
||||
if onGasChange != nil && reason != tracing.GasChangeIgnored {
|
||||
onGasChange(c.Gas, c.Gas+gas, reason)
|
||||
}
|
||||
c.Gas += gas
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,13 +257,13 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
|
|||
// - the returned bytes,
|
||||
// - the _remaining_ gas,
|
||||
// - any error that occurred
|
||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
|
||||
func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, onGasChange tracing.GasChangeHook) (ret []byte, remainingGas uint64, err error) {
|
||||
gasCost := p.RequiredGas(input)
|
||||
if suppliedGas < gasCost {
|
||||
return nil, 0, ErrOutOfGas
|
||||
}
|
||||
if logger != nil && logger.OnGasChange != nil {
|
||||
logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
|
||||
if onGasChange != nil {
|
||||
onGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
|
||||
}
|
||||
suppliedGas -= gasCost
|
||||
output, err := p.Run(input)
|
||||
|
|
|
|||
|
|
@ -358,7 +358,7 @@ func opExtCodeCopyEIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeC
|
|||
code := interpreter.evm.StateDB.GetCode(addr)
|
||||
paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64())
|
||||
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas)
|
||||
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
|
||||
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeUnspecified)
|
||||
if consumed < wanted {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
|
|
@ -384,7 +384,7 @@ func opPush1EIP4762(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
|||
// advanced past this boundary.
|
||||
contractAddr := scope.Contract.Address()
|
||||
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
|
||||
scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
|
||||
scope.Contract.UseGas(wanted, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeUnspecified)
|
||||
if consumed < wanted {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
|
|
@ -412,7 +412,7 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc {
|
|||
if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall {
|
||||
contractAddr := scope.Contract.Address()
|
||||
consumed, wanted := interpreter.evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas)
|
||||
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer, tracing.GasChangeUnspecified)
|
||||
scope.Contract.UseGas(consumed, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeUnspecified)
|
||||
if consumed < wanted {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,6 +125,9 @@ type EVM struct {
|
|||
// jumpDests is the aggregated result of JUMPDEST analysis made through
|
||||
// the life cycle of EVM.
|
||||
jumpDests map[common.Hash]bitvec
|
||||
|
||||
// tracingEnabled is used to shortcircuit some of the tracing calls
|
||||
tracingEnabled bool
|
||||
}
|
||||
|
||||
// NewEVM constructs an EVM instance with the supplied block context, state
|
||||
|
|
@ -133,12 +136,13 @@ type EVM struct {
|
|||
// needed by calling evm.SetTxContext.
|
||||
func NewEVM(blockCtx BlockContext, statedb StateDB, chainConfig *params.ChainConfig, config Config) *EVM {
|
||||
evm := &EVM{
|
||||
Context: blockCtx,
|
||||
StateDB: statedb,
|
||||
Config: config,
|
||||
chainConfig: chainConfig,
|
||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
||||
jumpDests: make(map[common.Hash]bitvec),
|
||||
Context: blockCtx,
|
||||
StateDB: statedb,
|
||||
Config: config,
|
||||
chainConfig: chainConfig,
|
||||
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
|
||||
jumpDests: make(map[common.Hash]bitvec),
|
||||
tracingEnabled: config.Tracer.HasVMHooks(),
|
||||
}
|
||||
evm.precompiles = activePrecompiledContracts(evm.chainRules)
|
||||
evm.interpreter = NewEVMInterpreter(evm)
|
||||
|
|
@ -186,8 +190,8 @@ func isSystemCall(caller common.Address) bool {
|
|||
// the necessary steps to create accounts and reverses the state in case of an
|
||||
// execution error or failed value transfer.
|
||||
func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Capture the tracer start/end events in debug mode
|
||||
if evm.Config.Tracer != nil {
|
||||
if evm.tracingEnabled {
|
||||
// Capture the tracer start/end events in debug mode
|
||||
evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
|
||||
|
|
@ -230,7 +234,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
evm.Context.Transfer(evm.StateDB, caller, addr, value)
|
||||
|
||||
if isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange)
|
||||
} else {
|
||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
code := evm.resolveCode(addr)
|
||||
|
|
@ -251,7 +255,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
|
||||
|
|
@ -272,8 +276,8 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g
|
|||
// CallCode differs from Call in the sense that it executes the given address'
|
||||
// code with the caller as context.
|
||||
func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
if evm.tracingEnabled {
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
|
||||
|
|
@ -294,7 +298,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange)
|
||||
} else {
|
||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
|
|
@ -306,7 +310,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas = 0
|
||||
|
|
@ -321,8 +325,8 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt
|
|||
// DelegateCall differs from CallCode in the sense that it executes the given address'
|
||||
// code with the caller as context and the caller is set to the caller of the caller.
|
||||
func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
if evm.tracingEnabled {
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
// DELEGATECALL inherits value from parent call
|
||||
evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
|
|
@ -337,7 +341,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
|
||||
// It is allowed to call precompiles, even via delegatecall
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange)
|
||||
} else {
|
||||
// Initialise a new contract and make initialise the delegate values
|
||||
//
|
||||
|
|
@ -350,7 +354,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
gas = 0
|
||||
|
|
@ -364,8 +368,8 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address,
|
|||
// Opcodes that attempt to perform such modifications will result in exceptions
|
||||
// instead of performing the modifications.
|
||||
func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
if evm.Config.Tracer != nil {
|
||||
if evm.tracingEnabled {
|
||||
// Invoke tracer hooks that signal entering/exiting a call frame
|
||||
evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil)
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
|
||||
|
|
@ -389,7 +393,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
evm.StateDB.AddBalance(addr, new(uint256.Int), tracing.BalanceChangeTouchAccount)
|
||||
|
||||
if p, isPrecompile := evm.precompile(addr); isPrecompile {
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
|
||||
ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer.OnGasChange)
|
||||
} else {
|
||||
// Initialise a new contract and set the code that is to be used by the EVM.
|
||||
// The contract is a scoped environment for this execution context only.
|
||||
|
|
@ -405,7 +409,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
if err != nil {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
|
||||
|
|
@ -417,7 +421,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b
|
|||
|
||||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) {
|
||||
if evm.Config.Tracer != nil {
|
||||
if evm.tracingEnabled {
|
||||
evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
|
||||
|
|
@ -443,7 +447,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
|||
if statelessGas > gas {
|
||||
return nil, common.Address{}, 0, ErrOutOfGas
|
||||
}
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck)
|
||||
}
|
||||
gas = gas - statelessGas
|
||||
|
|
@ -464,7 +468,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
|||
if evm.StateDB.GetNonce(address) != 0 ||
|
||||
(contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code
|
||||
(storageRoot != (common.Hash{}) && storageRoot != types.EmptyRootHash) { // non-empty storage
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
return nil, common.Address{}, 0, ErrContractAddressCollision
|
||||
|
|
@ -491,7 +495,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
|||
if consumed < wanted {
|
||||
return nil, common.Address{}, 0, ErrOutOfGas
|
||||
}
|
||||
if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(gas, gas-consumed, tracing.GasChangeWitnessContractInit)
|
||||
}
|
||||
gas = gas - consumed
|
||||
|
|
@ -511,7 +515,7 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui
|
|||
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
|
||||
evm.StateDB.RevertToSnapshot(snapshot)
|
||||
if err != ErrExecutionReverted {
|
||||
contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution)
|
||||
contract.UseGas(contract.Gas, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallFailedExecution)
|
||||
}
|
||||
}
|
||||
return ret, address, contract.Gas, err
|
||||
|
|
@ -537,12 +541,12 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b
|
|||
|
||||
if !evm.chainRules.IsEIP4762 {
|
||||
createDataGas := uint64(len(ret)) * params.CreateDataGas
|
||||
if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
|
||||
if !contract.UseGas(createDataGas, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallCodeStorage) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
} else {
|
||||
consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas)
|
||||
contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk)
|
||||
contract.UseGas(consumed, evm.Config.Tracer.OnGasChange, tracing.GasChangeWitnessCodeChunk)
|
||||
if len(ret) > 0 && (consumed < wanted) {
|
||||
return ret, ErrCodeStoreOutOfGas
|
||||
}
|
||||
|
|
@ -601,29 +605,21 @@ func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash {
|
|||
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||
|
||||
func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) {
|
||||
tracer := evm.Config.Tracer
|
||||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value)
|
||||
if evm.Config.Tracer.OnEnter != nil {
|
||||
evm.Config.Tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value)
|
||||
}
|
||||
if tracer.OnGasChange != nil {
|
||||
tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance)
|
||||
if evm.Config.Tracer.OnGasChange != nil {
|
||||
evm.Config.Tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) {
|
||||
tracer := evm.Config.Tracer
|
||||
if leftOverGas != 0 && tracer.OnGasChange != nil {
|
||||
tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
|
||||
if evm.Config.Tracer.OnGasChange != nil && leftOverGas != 0 {
|
||||
evm.Config.Tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
|
||||
}
|
||||
var reverted bool
|
||||
if err != nil {
|
||||
reverted = true
|
||||
}
|
||||
if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) {
|
||||
reverted = false
|
||||
}
|
||||
if tracer.OnExit != nil {
|
||||
tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||
if evm.Config.Tracer.OnExit != nil {
|
||||
reverted := err != nil && (evm.chainRules.IsHomestead || !errors.Is(err, ErrCodeStoreOutOfGas))
|
||||
evm.Config.Tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -443,8 +443,8 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
if witness := interpreter.evm.StateDB.Witness(); witness != nil {
|
||||
witness.AddBlockHash(num64)
|
||||
}
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil && tracer.OnBlockHashRead != nil {
|
||||
tracer.OnBlockHashRead(num64, res)
|
||||
if interpreter.evm.Config.Tracer.OnBlockHashRead != nil {
|
||||
interpreter.evm.Config.Tracer.OnBlockHashRead(num64, res)
|
||||
}
|
||||
num.SetBytes(res[:])
|
||||
} else {
|
||||
|
|
@ -670,7 +670,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
|||
// reuse size int for stackvalue
|
||||
stackvalue := size
|
||||
|
||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation)
|
||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallContractCreation)
|
||||
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract.Address(), input, gas, &value)
|
||||
// Push item on the stack based on the returned error. If the ruleset is
|
||||
|
|
@ -686,7 +686,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
|
|||
}
|
||||
scope.Stack.push(&stackvalue)
|
||||
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
if suberr == ErrExecutionReverted {
|
||||
interpreter.returnData = res // set REVERT data to return data buffer
|
||||
|
|
@ -710,7 +710,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
|||
|
||||
// Apply EIP150
|
||||
gas -= gas / 64
|
||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
|
||||
scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallContractCreation2)
|
||||
// reuse size int for stackvalue
|
||||
stackvalue := size
|
||||
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract.Address(), input, gas,
|
||||
|
|
@ -722,7 +722,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
|
|||
stackvalue.SetBytes(addr.Bytes())
|
||||
}
|
||||
scope.Stack.push(&stackvalue)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
if suberr == ErrExecutionReverted {
|
||||
interpreter.returnData = res // set REVERT data to return data buffer
|
||||
|
|
@ -762,7 +762,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
|
|||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
interpreter.returnData = ret
|
||||
return ret, nil
|
||||
|
|
@ -795,7 +795,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
|
|||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
interpreter.returnData = ret
|
||||
return ret, nil
|
||||
|
|
@ -824,7 +824,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
|||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
interpreter.returnData = ret
|
||||
return ret, nil
|
||||
|
|
@ -853,7 +853,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
|
|||
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
|
||||
}
|
||||
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
|
||||
scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer.OnGasChange, tracing.GasChangeCallLeftOverRefunded)
|
||||
|
||||
interpreter.returnData = ret
|
||||
return ret, nil
|
||||
|
|
@ -890,13 +890,11 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
|||
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
|
||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
|
||||
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
}
|
||||
if tracer.OnExit != nil {
|
||||
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
||||
}
|
||||
if interpreter.evm.Config.Tracer.OnEnter != nil {
|
||||
interpreter.evm.Config.Tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
}
|
||||
if interpreter.evm.Config.Tracer.OnExit != nil {
|
||||
interpreter.evm.Config.Tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
||||
}
|
||||
return nil, errStopToken
|
||||
}
|
||||
|
|
@ -910,13 +908,11 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
|||
interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
|
||||
interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
|
||||
interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address())
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
}
|
||||
if tracer.OnExit != nil {
|
||||
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
||||
}
|
||||
if interpreter.evm.Config.Tracer.OnEnter != nil {
|
||||
interpreter.evm.Config.Tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
}
|
||||
if interpreter.evm.Config.Tracer.OnExit != nil {
|
||||
interpreter.evm.Config.Tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
||||
}
|
||||
return nil, errStopToken
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import (
|
|||
|
||||
// Config are the configuration options for the Interpreter
|
||||
type Config struct {
|
||||
Tracer *tracing.Hooks
|
||||
Tracer tracing.Hooks
|
||||
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
|
||||
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
|
||||
ExtraEips []int // Additional EIPS that are to be enabled
|
||||
|
|
@ -202,7 +202,6 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
gasCopy uint64 // for EVMLogger to log gas remaining before execution
|
||||
logged bool // deferred EVMLogger should ignore already logged steps
|
||||
res []byte // result of the opcode execution function
|
||||
debug = in.evm.Config.Tracer != nil
|
||||
)
|
||||
// Don't move this deferred function, it's placed before the OnOpcode-deferred method,
|
||||
// so that it gets executed _after_: the OnOpcode needs the stacks before
|
||||
|
|
@ -213,36 +212,32 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
}()
|
||||
contract.Input = input
|
||||
|
||||
if debug {
|
||||
defer func() { // this deferred method handles exit-with-error
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if !logged && in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
}
|
||||
if logged && in.evm.Config.Tracer.OnFault != nil {
|
||||
in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
|
||||
}
|
||||
}()
|
||||
}
|
||||
defer func() { // this deferred method handles exit-with-error
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
if !logged && in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
}
|
||||
if logged && in.evm.Config.Tracer.OnFault != nil {
|
||||
in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
|
||||
}
|
||||
}()
|
||||
// The Interpreter main run loop (contextual). This loop runs until either an
|
||||
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
|
||||
// the execution of one of the operations or until the done flag is set by the
|
||||
// parent context.
|
||||
_ = jumpTable[0] // nil-check the jumpTable out of the loop
|
||||
for {
|
||||
if debug {
|
||||
// Capture pre-execution values for tracing.
|
||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||
}
|
||||
// Capture pre-execution values for tracing.
|
||||
logged, pcCopy, gasCopy = false, pc, contract.Gas
|
||||
|
||||
if in.evm.chainRules.IsEIP4762 && !contract.IsDeployment && !contract.IsSystemCall {
|
||||
// if the PC ends up in a new "chunk" of verkleized code, charge the
|
||||
// associated costs.
|
||||
contractAddr := contract.Address()
|
||||
consumed, wanted := in.evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas)
|
||||
contract.UseGas(consumed, in.evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk)
|
||||
contract.UseGas(consumed, in.evm.Config.Tracer.OnGasChange, tracing.GasChangeWitnessCodeChunk)
|
||||
if consumed < wanted {
|
||||
return nil, ErrOutOfGas
|
||||
}
|
||||
|
|
@ -301,14 +296,12 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
}
|
||||
|
||||
// Do tracing before potential memory expansion
|
||||
if debug {
|
||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
||||
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
logged = true
|
||||
}
|
||||
if in.evm.Config.Tracer.OnGasChange != nil {
|
||||
in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
|
||||
}
|
||||
if in.evm.Config.Tracer.OnOpcode != nil {
|
||||
in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
|
||||
logged = true
|
||||
}
|
||||
if memorySize > 0 {
|
||||
mem.Resize(memorySize)
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc, addressPosition int) g
|
|||
evm.StateDB.AddAddressToAccessList(addr)
|
||||
// Charge the remaining difference here already, to correctly calculate available
|
||||
// gas for call
|
||||
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||
if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
|
||||
return 0, ErrOutOfGas
|
||||
}
|
||||
}
|
||||
|
|
@ -265,7 +265,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
|
|||
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
|
||||
// Charge the remaining difference here already, to correctly calculate available
|
||||
// gas for call
|
||||
if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||
if !contract.UseGas(coldCost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
|
||||
return 0, ErrOutOfGas
|
||||
}
|
||||
total += coldCost
|
||||
|
|
@ -280,7 +280,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
|
|||
evm.StateDB.AddAddressToAccessList(target)
|
||||
cost = params.ColdAccountAccessCostEIP2929
|
||||
}
|
||||
if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
|
||||
if !contract.UseGas(cost, evm.Config.Tracer.OnGasChange, tracing.GasChangeCallStorageColdAccess) {
|
||||
return 0, ErrOutOfGas
|
||||
}
|
||||
total += cost
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||
vmenv = NewEnv(cfg)
|
||||
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
if cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
|
||||
}
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
|
|
@ -148,7 +148,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
|
|||
cfg.GasLimit,
|
||||
uint256.MustFromBig(cfg.Value),
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil {
|
||||
if cfg.EVMConfig.Tracer.OnTxEnd != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err)
|
||||
}
|
||||
return ret, cfg.State, err
|
||||
|
|
@ -168,7 +168,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
|||
vmenv = NewEnv(cfg)
|
||||
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
if cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
|
||||
}
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
|
|
@ -182,7 +182,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
|
|||
cfg.GasLimit,
|
||||
uint256.MustFromBig(cfg.Value),
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil {
|
||||
if cfg.EVMConfig.Tracer.OnTxEnd != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err)
|
||||
}
|
||||
return code, address, leftOverGas, err
|
||||
|
|
@ -201,7 +201,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
|||
statedb = cfg.State
|
||||
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
if cfg.EVMConfig.Tracer.OnTxStart != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
|
||||
}
|
||||
// Execute the preparatory steps for state transition which includes:
|
||||
|
|
@ -217,7 +217,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
|
|||
cfg.GasLimit,
|
||||
uint256.MustFromBig(cfg.Value),
|
||||
)
|
||||
if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil {
|
||||
if cfg.EVMConfig.Tracer.OnTxEnd != nil {
|
||||
cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err)
|
||||
}
|
||||
return ret, leftOverGas, err
|
||||
|
|
|
|||
|
|
@ -666,7 +666,7 @@ func TestColdAccountAccessCost(t *testing.T) {
|
|||
var have = uint64(0)
|
||||
Execute(tc.code, nil, &Config{
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: &tracing.Hooks{
|
||||
Tracer: tracing.Hooks{
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
// Uncomment to investigate failures:
|
||||
//t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
|
||||
|
|
@ -920,7 +920,7 @@ func TestDelegatedAccountAccessCost(t *testing.T) {
|
|||
ChainConfig: params.MergedTestChainConfig,
|
||||
State: statedb,
|
||||
EVMConfig: vm.Config{
|
||||
Tracer: &tracing.Hooks{
|
||||
Tracer: tracing.Hooks{
|
||||
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
// Uncomment to investigate failures:
|
||||
t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ func newStateTracer(ctx *Context, cfg json.RawMessage, chainCfg *params.ChainCon
|
|||
GetResult: func() (json.RawMessage, error) {
|
||||
return json.Marshal(t)
|
||||
},
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
|
||||
t.Balance[addr] = (*hexutil.Big)(new)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ type Context struct {
|
|||
// This involves a method to retrieve results and one to
|
||||
// stop tracing.
|
||||
type Tracer struct {
|
||||
*tracing.Hooks
|
||||
tracing.Hooks
|
||||
GetResult func() (json.RawMessage, error)
|
||||
// Stop terminates execution of the tracer at the first opportune moment.
|
||||
Stop func(err error)
|
||||
|
|
|
|||
|
|
@ -121,10 +121,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to create call tracer: %v", err)
|
||||
}
|
||||
logState := vm.StateDB(st.StateDB)
|
||||
if tracer.Hooks != nil {
|
||||
logState = state.NewHookedState(st.StateDB, tracer.Hooks)
|
||||
}
|
||||
logState := state.NewHookedState(st.StateDB, tracer.Hooks)
|
||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
|
|
@ -355,11 +352,7 @@ func TestInternals(t *testing.T) {
|
|||
}, false, rawdb.HashScheme)
|
||||
defer st.Close()
|
||||
|
||||
logState := vm.StateDB(st.StateDB)
|
||||
if hooks := tc.tracer.Hooks; hooks != nil {
|
||||
logState = state.NewHookedState(st.StateDB, hooks)
|
||||
}
|
||||
|
||||
logState := state.NewHookedState(st.StateDB, tc.tracer.Hooks)
|
||||
tx, err := types.SignNewTx(key, signer, &types.LegacyTx{
|
||||
To: &to,
|
||||
Value: big.NewInt(0),
|
||||
|
|
|
|||
|
|
@ -114,10 +114,7 @@ func TestErc7562Tracer(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to create erc7562 tracer: %v", err)
|
||||
}
|
||||
logState := vm.StateDB(st.StateDB)
|
||||
if tracer.Hooks != nil {
|
||||
logState = state.NewHookedState(st.StateDB, tracer.Hooks)
|
||||
}
|
||||
logState := state.NewHookedState(st.StateDB, tracer.Hooks)
|
||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainCo
|
|||
t.logValue = t.log.setupObject()
|
||||
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
OnEnter: t.OnEnter,
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
)
|
||||
|
||||
type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error)
|
||||
type ctorFunc func(config json.RawMessage) (tracing.Hooks, error)
|
||||
|
||||
// LiveDirectory is the collection of tracers which can be used
|
||||
// during normal block import operations.
|
||||
|
|
@ -39,12 +39,12 @@ func (d *liveDirectory) Register(name string, f ctorFunc) {
|
|||
}
|
||||
|
||||
// New instantiates a tracer by name.
|
||||
func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) {
|
||||
func (d *liveDirectory) New(name string, config json.RawMessage) (tracing.Hooks, error) {
|
||||
if len(config) == 0 {
|
||||
config = json.RawMessage("{}")
|
||||
}
|
||||
if f, ok := d.elems[name]; ok {
|
||||
return f(config)
|
||||
}
|
||||
return nil, errors.New("not found")
|
||||
return tracing.Hooks{}, errors.New("not found")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ func init() {
|
|||
// as soon as we have a real live tracer.
|
||||
type noop struct{}
|
||||
|
||||
func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) {
|
||||
func newNoopTracer(_ json.RawMessage) (tracing.Hooks, error) {
|
||||
t := &noop{}
|
||||
return &tracing.Hooks{
|
||||
return tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
OnEnter: t.OnEnter,
|
||||
|
|
|
|||
|
|
@ -92,13 +92,13 @@ type supplyTracerConfig struct {
|
|||
MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes.
|
||||
}
|
||||
|
||||
func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
|
||||
func newSupplyTracer(cfg json.RawMessage) (tracing.Hooks, error) {
|
||||
var config supplyTracerConfig
|
||||
if err := json.Unmarshal(cfg, &config); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse config: %v", err)
|
||||
return tracing.Hooks{}, fmt.Errorf("failed to parse config: %v", err)
|
||||
}
|
||||
if config.Path == "" {
|
||||
return nil, errors.New("supply tracer output path is required")
|
||||
return tracing.Hooks{}, errors.New("supply tracer output path is required")
|
||||
}
|
||||
|
||||
// Store traces in a rotating file
|
||||
|
|
@ -113,7 +113,7 @@ func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
|
|||
delta: newSupplyInfo(),
|
||||
logger: logger,
|
||||
}
|
||||
return &tracing.Hooks{
|
||||
return tracing.Hooks{
|
||||
OnBlockchainInit: t.onBlockchainInit,
|
||||
OnBlockStart: t.onBlockStart,
|
||||
OnBlockEnd: t.onBlockEnd,
|
||||
|
|
|
|||
|
|
@ -119,8 +119,8 @@ func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Add
|
|||
}
|
||||
}
|
||||
|
||||
func (a *AccessListTracer) Hooks() *tracing.Hooks {
|
||||
return &tracing.Hooks{
|
||||
func (a *AccessListTracer) Hooks() tracing.Hooks {
|
||||
return tracing.Hooks{
|
||||
OnOpcode: a.OnOpcode,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -244,8 +244,8 @@ func NewStructLogger(cfg *Config) *StructLogger {
|
|||
return logger
|
||||
}
|
||||
|
||||
func (l *StructLogger) Hooks() *tracing.Hooks {
|
||||
return &tracing.Hooks{
|
||||
func (l *StructLogger) Hooks() tracing.Hooks {
|
||||
return tracing.Hooks{
|
||||
OnTxStart: l.OnTxStart,
|
||||
OnTxEnd: l.OnTxEnd,
|
||||
OnSystemCallStartV2: l.OnSystemCallStart,
|
||||
|
|
@ -426,8 +426,8 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger {
|
|||
return l
|
||||
}
|
||||
|
||||
func (t *mdLogger) Hooks() *tracing.Hooks {
|
||||
return &tracing.Hooks{
|
||||
func (t *mdLogger) Hooks() tracing.Hooks {
|
||||
return tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnSystemCallStartV2: t.OnSystemCallStart,
|
||||
OnSystemCallEnd: t.OnSystemCallEnd,
|
||||
|
|
|
|||
|
|
@ -58,17 +58,17 @@ type jsonLogger struct {
|
|||
encoder *json.Encoder
|
||||
cfg *Config
|
||||
env *tracing.VMContext
|
||||
hooks *tracing.Hooks
|
||||
hooks tracing.Hooks
|
||||
}
|
||||
|
||||
// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects
|
||||
// into the provided stream.
|
||||
func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks {
|
||||
func NewJSONLogger(cfg *Config, writer io.Writer) tracing.Hooks {
|
||||
l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg}
|
||||
if l.cfg == nil {
|
||||
l.cfg = &Config{}
|
||||
}
|
||||
l.hooks = &tracing.Hooks{
|
||||
l.hooks = tracing.Hooks{
|
||||
OnTxStart: l.OnTxStart,
|
||||
OnSystemCallStart: l.onSystemCallStart,
|
||||
OnExit: l.OnExit,
|
||||
|
|
@ -80,12 +80,12 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks {
|
|||
|
||||
// NewJSONLoggerWithCallFrames creates a new EVM tracer that prints execution steps as JSON objects
|
||||
// into the provided stream. It also includes call frames in the output.
|
||||
func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) *tracing.Hooks {
|
||||
func NewJSONLoggerWithCallFrames(cfg *Config, writer io.Writer) tracing.Hooks {
|
||||
l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg}
|
||||
if l.cfg == nil {
|
||||
l.cfg = &Config{}
|
||||
}
|
||||
l.hooks = &tracing.Hooks{
|
||||
l.hooks = tracing.Hooks{
|
||||
OnTxStart: l.OnTxStart,
|
||||
OnSystemCallStart: l.onSystemCallStart,
|
||||
OnEnter: l.OnEnter,
|
||||
|
|
@ -129,10 +129,10 @@ func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracin
|
|||
|
||||
func (l *jsonLogger) onSystemCallStart() {
|
||||
// Process no events while in system call.
|
||||
hooks := *l.hooks
|
||||
*l.hooks = tracing.Hooks{
|
||||
hooks := l.hooks
|
||||
l.hooks = tracing.Hooks{
|
||||
OnSystemCallEnd: func() {
|
||||
*l.hooks = hooks
|
||||
l.hooks = hooks
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ func newFourByteTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
|
|||
chainConfig: chainConfig,
|
||||
}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnEnter: t.OnEnter,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *param
|
|||
return nil, err
|
||||
}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
OnEnter: t.OnEnter,
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
|
|||
|
||||
ft := &flatCallTracer{tracer: t, ctx: ctx, config: config, chainConfig: chainConfig}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: ft.OnTxStart,
|
||||
OnTxEnd: ft.OnTxEnd,
|
||||
OnEnter: ft.OnEnter,
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ func newErc7562Tracer(ctx *tracers.Context, cfg json.RawMessage, _ *params.Chain
|
|||
return nil, err
|
||||
}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnOpcode: t.OnOpcode,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params
|
|||
|
||||
t := &muxTracer{names: names, tracers: objects}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
OnEnter: t.OnEnter,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ type noopTracer struct{}
|
|||
func newNoopTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
|
||||
t := &noopTracer{}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
OnEnter: t.OnEnter,
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *p
|
|||
deleted: make(map[common.Address]bool),
|
||||
}
|
||||
return &tracers.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
Hooks: tracing.Hooks{
|
||||
OnTxStart: t.OnTxStart,
|
||||
OnTxEnd: t.OnTxEnd,
|
||||
OnOpcode: t.OnOpcode,
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common
|
|||
}
|
||||
}
|
||||
|
||||
func (t *tracer) Hooks() *tracing.Hooks {
|
||||
return &tracing.Hooks{
|
||||
func (t *tracer) Hooks() tracing.Hooks {
|
||||
return tracing.Hooks{
|
||||
OnEnter: t.onEnter,
|
||||
OnExit: t.onExit,
|
||||
OnLog: t.onLog,
|
||||
|
|
|
|||
|
|
@ -255,8 +255,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
|||
senders = make(map[common.Hash]common.Address)
|
||||
)
|
||||
tracingStateDB := vm.StateDB(sim.state)
|
||||
if hooks := tracer.Hooks(); hooks != nil {
|
||||
tracingStateDB = state.NewHookedState(sim.state, hooks)
|
||||
if tracer != nil {
|
||||
tracingStateDB = state.NewHookedState(sim.state, tracer.Hooks())
|
||||
}
|
||||
evm := vm.NewEVM(blockContext, tracingStateDB, sim.chainConfig, *vmConfig)
|
||||
// It is possible to override precompiles with EVM bytecode, or
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/tracing"
|
||||
)
|
||||
|
||||
func TestBlockchain(t *testing.T) {
|
||||
|
|
@ -105,7 +106,7 @@ func execBlockTest(t *testing.T, bt *testMatcher, test *BlockTest) {
|
|||
}
|
||||
for _, snapshot := range snapshotConf {
|
||||
for _, dbscheme := range dbschemeConf {
|
||||
if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, nil, nil)); err != nil {
|
||||
if err := bt.checkFailure(t, test.Run(snapshot, dbscheme, true, tracing.Hooks{}, nil)); err != nil {
|
||||
t.Errorf("test with config {snapshotter:%v, scheme:%v} failed: %v", snapshot, dbscheme, err)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ type btHeaderMarshaling struct {
|
|||
ExcessBlobGas *math.HexOrDecimal64
|
||||
}
|
||||
|
||||
func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) {
|
||||
func (t *BlockTest) Run(snapshotter bool, scheme string, witness bool, tracer tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) {
|
||||
config, ok := Forks[t.json.Network]
|
||||
if !ok {
|
||||
return UnsupportedForkError{t.json.Network}
|
||||
|
|
|
|||
|
|
@ -323,8 +323,8 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
|||
|
||||
evm := vm.NewEVM(context, st.StateDB, config, vmconfig)
|
||||
|
||||
if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil {
|
||||
tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)
|
||||
if evm.Config.Tracer.OnTxStart != nil {
|
||||
evm.Config.Tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)
|
||||
}
|
||||
// Execute the message.
|
||||
snapshot := st.StateDB.Snapshot()
|
||||
|
|
@ -333,7 +333,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
|||
vmRet, err := core.ApplyMessage(evm, msg, gaspool)
|
||||
if err != nil {
|
||||
st.StateDB.RevertToSnapshot(snapshot)
|
||||
if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil {
|
||||
if evm.Config.Tracer.OnTxEnd != nil {
|
||||
evm.Config.Tracer.OnTxEnd(nil, err)
|
||||
}
|
||||
return st, common.Hash{}, 0, err
|
||||
|
|
@ -347,9 +347,9 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
|||
|
||||
// Commit state mutations into database.
|
||||
root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()), config.IsCancun(block.Number(), block.Time()))
|
||||
if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil {
|
||||
if evm.Config.Tracer.OnTxEnd != nil {
|
||||
receipt := &types.Receipt{GasUsed: vmRet.UsedGas}
|
||||
tracer.OnTxEnd(receipt, nil)
|
||||
evm.Config.Tracer.OnTxEnd(receipt, nil)
|
||||
}
|
||||
return st, root, vmRet.UsedGas, nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue