mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-28 07:36:44 +00:00
rm OnStart and onEnd
This commit is contained in:
parent
923c180058
commit
37ce159500
13 changed files with 109 additions and 161 deletions
|
|
@ -91,15 +91,8 @@ type (
|
|||
// TxEndHook is called after the execution of a transaction ends.
|
||||
TxEndHook = func(receipt *types.Receipt, err error)
|
||||
|
||||
// StartHook is invoked when the processing of the root call starts.
|
||||
StartHook = func(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
||||
|
||||
// EndHook is invoked when the processing of the top call ends.
|
||||
// See docs for `ExitHook` for info on the `reverted` parameter.
|
||||
EndHook = func(output []byte, gasUsed uint64, err error, reverted bool)
|
||||
|
||||
// EnterHook is invoked when the processing of a message starts.
|
||||
EnterHook = func(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
||||
EnterHook = func(depth int, typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
|
||||
|
||||
// ExitHook is invoked when the processing of a message ends.
|
||||
// `revert` is true when there was an error during the execution.
|
||||
|
|
@ -107,7 +100,7 @@ type (
|
|||
// ran out of gas when attempting to persist the code to database did not
|
||||
// count as a call failure and did not cause a revert of the call. This will
|
||||
// be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
|
||||
ExitHook = func(output []byte, gasUsed uint64, err error, reverted bool)
|
||||
ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool)
|
||||
|
||||
// OpcodeHook is invoked just prior to the execution of an opcode.
|
||||
OpcodeHook = func(pc uint64, op OpCode, gas, cost uint64, scope OpContext, rData []byte, depth int, err error)
|
||||
|
|
@ -167,8 +160,6 @@ type Hooks struct {
|
|||
// VM events
|
||||
OnTxStart TxStartHook
|
||||
OnTxEnd TxEndHook
|
||||
OnStart StartHook
|
||||
OnEnd EndHook
|
||||
OnEnter EnterHook
|
||||
OnExit ExitHook
|
||||
OnOpcode OpcodeHook
|
||||
|
|
|
|||
|
|
@ -181,9 +181,9 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
|
|||
func (evm *EVM) Call(caller ContractRef, 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 {
|
||||
evm.captureBegin(evm.depth == 0, CALL, caller.Address(), addr, input, gas, value.ToBig())
|
||||
evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(evm.depth == 0, CALL, startGas, leftOverGas, ret, err)
|
||||
evm.captureEnd(evm.depth, CALL, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
|
|
@ -253,9 +253,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
|
|||
func (evm *EVM) CallCode(caller ContractRef, 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 {
|
||||
evm.captureBegin(false, CALLCODE, caller.Address(), addr, input, gas, value.ToBig())
|
||||
evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(false, CALLCODE, startGas, leftOverGas, ret, err)
|
||||
evm.captureEnd(evm.depth, CALLCODE, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
|
|
@ -308,9 +308,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
// that caller is something other than a Contract.
|
||||
parent := caller.(*Contract)
|
||||
// DELEGATECALL inherits value from parent call
|
||||
evm.captureBegin(false, DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig())
|
||||
evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(false, DELEGATECALL, startGas, leftOverGas, ret, err)
|
||||
evm.captureEnd(evm.depth, DELEGATECALL, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
|
|
@ -349,9 +349,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
|
|||
func (evm *EVM) StaticCall(caller ContractRef, 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 {
|
||||
evm.captureBegin(false, STATICCALL, caller.Address(), addr, input, gas, nil)
|
||||
evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil)
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(false, STATICCALL, startGas, leftOverGas, ret, err)
|
||||
evm.captureEnd(evm.depth, STATICCALL, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
// Fail if we're trying to execute above the call depth limit
|
||||
|
|
@ -416,9 +416,9 @@ func (c *codeAndHash) Hash() common.Hash {
|
|||
// create creates a new contract using code as deployment code.
|
||||
func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) {
|
||||
if evm.Config.Tracer != nil {
|
||||
evm.captureBegin(evm.depth == 0, typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig())
|
||||
evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig())
|
||||
defer func(startGas uint64) {
|
||||
evm.captureEnd(evm.depth == 0, typ, startGas, leftOverGas, ret, err)
|
||||
evm.captureEnd(evm.depth, typ, startGas, leftOverGas, ret, err)
|
||||
}(gas)
|
||||
}
|
||||
// Depth check execution. Fail if we're trying to execute above the
|
||||
|
|
@ -518,25 +518,18 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *
|
|||
// ChainConfig returns the environment's chain configuration
|
||||
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
|
||||
|
||||
func (evm *EVM) captureBegin(isRoot bool, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) {
|
||||
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 isRoot {
|
||||
if tracer.OnStart != nil {
|
||||
tracer.OnStart(from, to, typ == CREATE || typ == CREATE2, input, startGas, value)
|
||||
}
|
||||
} else if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(tracing.OpCode(typ), from, to, input, startGas, value)
|
||||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(depth, tracing.OpCode(typ), from, to, input, startGas, value)
|
||||
}
|
||||
|
||||
if tracer.OnGasChange != nil {
|
||||
tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance)
|
||||
}
|
||||
}
|
||||
|
||||
func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas uint64, ret []byte, err error) {
|
||||
func (evm *EVM) captureEnd(depth int, typ OpCode, startGas uint64, leftOverGas uint64, ret []byte, err error) {
|
||||
tracer := evm.Config.Tracer
|
||||
|
||||
if leftOverGas != 0 && tracer.OnGasChange != nil {
|
||||
tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
|
||||
}
|
||||
|
|
@ -547,12 +540,8 @@ func (evm *EVM) captureEnd(isRoot bool, typ OpCode, startGas uint64, leftOverGas
|
|||
if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) {
|
||||
reverted = false
|
||||
}
|
||||
if isRoot {
|
||||
if tracer.OnEnd != nil {
|
||||
tracer.OnEnd(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||
}
|
||||
} else if tracer.OnExit != nil {
|
||||
tracer.OnExit(ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||
if tracer.OnExit != nil {
|
||||
tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -837,10 +837,10 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
|
|||
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
tracer.OnEnter(interpreter.evm.depth, tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
}
|
||||
if tracer.OnExit != nil {
|
||||
tracer.OnExit([]byte{}, 0, nil, false)
|
||||
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
||||
}
|
||||
}
|
||||
return nil, errStopToken
|
||||
|
|
@ -857,10 +857,10 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
|
|||
interpreter.evm.StateDB.Selfdestruct6780(scope.Contract.Address())
|
||||
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
|
||||
if tracer.OnEnter != nil {
|
||||
tracer.OnEnter(tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
tracer.OnEnter(interpreter.evm.depth, tracing.OpCode(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
|
||||
}
|
||||
if tracer.OnExit != nil {
|
||||
tracer.OnExit([]byte{}, 0, nil, false)
|
||||
tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
|
||||
}
|
||||
}
|
||||
return nil, errStopToken
|
||||
|
|
|
|||
|
|
@ -40,8 +40,6 @@ func newNoopTracer(ctx *Context, _ json.RawMessage) (*Tracer, error) {
|
|||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnTxEnd: t.CaptureTxEnd,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnd: t.CaptureEnd,
|
||||
OnEnter: t.CaptureEnter,
|
||||
OnExit: t.CaptureExit,
|
||||
OnOpcode: t.CaptureState,
|
||||
|
|
@ -82,12 +80,12 @@ func (t *NoopTracer) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
|||
func (t *NoopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *NoopTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *NoopTracer) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
}
|
||||
|
||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||
// execute any code.
|
||||
func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (t *NoopTracer) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
}
|
||||
|
||||
func (*NoopTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
|
|
|
|||
|
|
@ -226,8 +226,6 @@ func newJsTracer(code string, ctx *directory.Context, cfg json.RawMessage) (*dir
|
|||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnTxEnd: t.CaptureTxEnd,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnd: t.CaptureEnd,
|
||||
OnEnter: t.CaptureEnter,
|
||||
OnExit: t.CaptureExit,
|
||||
OnOpcode: t.CaptureState,
|
||||
|
|
@ -273,7 +271,7 @@ func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt, err error) {
|
|||
}
|
||||
|
||||
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
||||
func (t *jsTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *jsTracer) captureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
cancel := func(err error) {
|
||||
t.err = err
|
||||
t.env.VM.Cancel()
|
||||
|
|
@ -347,7 +345,7 @@ func (t *jsTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64,
|
|||
}
|
||||
|
||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||
func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (t *jsTracer) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if err != nil {
|
||||
t.ctx["error"] = t.vm.ToValue(err.Error())
|
||||
}
|
||||
|
|
@ -360,7 +358,11 @@ func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted
|
|||
}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *jsTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *jsTracer) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
if depth == 0 {
|
||||
t.captureStart(from, to, vm.OpCode(typ) == vm.CREATE, input, gas, value)
|
||||
return
|
||||
}
|
||||
if !t.traceFrame {
|
||||
return
|
||||
}
|
||||
|
|
@ -385,7 +387,11 @@ func (t *jsTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to comm
|
|||
|
||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||
// execute any code.
|
||||
func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (t *jsTracer) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth == 0 {
|
||||
t.captureEnd(output, gasUsed, err, reverted)
|
||||
return
|
||||
}
|
||||
if !t.traceFrame {
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ func runTrace(tracer *directory.Tracer, vmctx *vmContext, chaincfg *params.Chain
|
|||
}
|
||||
|
||||
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
|
||||
tracer.OnStart(contract.Caller(), contract.Address(), false, []byte{}, startGas, value.ToBig())
|
||||
tracer.OnEnter(0, tracing.OpCode(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig())
|
||||
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||
tracer.OnEnd(ret, startGas-contract.Gas, err, true)
|
||||
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
|
||||
// Rest gas assumes no refund
|
||||
tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
|
||||
if err != nil {
|
||||
|
|
@ -188,7 +188,7 @@ func TestHaltBetweenSteps(t *testing.T) {
|
|||
}
|
||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks})
|
||||
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
|
||||
tracer.OnStart(common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0))
|
||||
tracer.OnEnter(0, tracing.OpCode(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0))
|
||||
tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
|
||||
timeout := errors.New("stahp")
|
||||
tracer.Stop(timeout)
|
||||
|
|
@ -210,8 +210,8 @@ func TestNoStepExec(t *testing.T) {
|
|||
}
|
||||
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks})
|
||||
tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
|
||||
tracer.OnStart(common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0))
|
||||
tracer.OnEnd(nil, 0, nil, false)
|
||||
tracer.OnEnter(0, tracing.OpCode(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0))
|
||||
tracer.OnExit(0, nil, 0, nil, false)
|
||||
ret, err := tracer.GetResult()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -280,8 +280,8 @@ func TestEnterExit(t *testing.T) {
|
|||
scope := &vm.ScopeContext{
|
||||
Contract: vm.NewContract(&account{}, &account{}, uint256.NewInt(0), 0),
|
||||
}
|
||||
tracer.OnEnter(tracing.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
|
||||
tracer.OnExit([]byte{}, 400, nil, false)
|
||||
tracer.OnEnter(1, tracing.OpCode(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
|
||||
tracer.OnExit(1, []byte{}, 400, nil, false)
|
||||
|
||||
have, err := tracer.GetResult()
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -26,8 +26,6 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) {
|
|||
return &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnTxEnd: t.CaptureTxEnd,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnd: t.CaptureEnd,
|
||||
OnEnter: t.CaptureEnter,
|
||||
OnExit: t.CaptureExit,
|
||||
OnOpcode: t.CaptureState,
|
||||
|
|
@ -67,12 +65,12 @@ func (t *noop) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64, _ tr
|
|||
func (t *noop) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *noop) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *noop) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
}
|
||||
|
||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||
// execute any code.
|
||||
func (t *noop) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (t *noop) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
}
|
||||
|
||||
func (t *noop) CaptureTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ func (l *StructLogger) Hooks() *tracing.Hooks {
|
|||
return &tracing.Hooks{
|
||||
OnTxStart: l.CaptureTxStart,
|
||||
OnTxEnd: l.CaptureTxEnd,
|
||||
OnEnd: l.CaptureEnd,
|
||||
OnExit: l.CaptureExit,
|
||||
OnOpcode: l.CaptureState,
|
||||
}
|
||||
}
|
||||
|
|
@ -227,8 +227,11 @@ func (l *StructLogger) CaptureState(pc uint64, opcode tracing.OpCode, gas, cost
|
|||
l.logs = append(l.logs, log)
|
||||
}
|
||||
|
||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
// CaptureExit is called a call frame finishes processing.
|
||||
func (l *StructLogger) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth != 0 {
|
||||
return
|
||||
}
|
||||
l.output = output
|
||||
l.err = err
|
||||
if l.cfg.Debug {
|
||||
|
|
@ -356,10 +359,10 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger {
|
|||
func (t *mdLogger) Hooks() *tracing.Hooks {
|
||||
return &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnter: t.CaptureEnter,
|
||||
OnExit: t.CaptureExit,
|
||||
OnOpcode: t.CaptureState,
|
||||
OnFault: t.CaptureFault,
|
||||
OnEnd: t.CaptureEnd,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +370,11 @@ func (t *mdLogger) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction,
|
|||
t.env = env
|
||||
}
|
||||
|
||||
func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *mdLogger) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
if depth != 0 {
|
||||
return
|
||||
}
|
||||
create := vm.OpCode(typ) == vm.CREATE
|
||||
if !create {
|
||||
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n",
|
||||
from.String(), to.String(),
|
||||
|
|
@ -384,6 +391,13 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b
|
|||
`)
|
||||
}
|
||||
|
||||
func (t *mdLogger) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth == 0 {
|
||||
fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
|
||||
output, gasUsed, err)
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||
func (t *mdLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
stack := scope.StackData()
|
||||
|
|
@ -409,11 +423,6 @@ func (t *mdLogger) CaptureFault(pc uint64, op tracing.OpCode, gas, cost uint64,
|
|||
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
|
||||
}
|
||||
|
||||
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
|
||||
output, gasUsed, err)
|
||||
}
|
||||
|
||||
// ExecutionResult groups all structured logs emitted by the EVM
|
||||
// while replaying a transaction in debug mode as well as transaction
|
||||
// execution status, the amount of gas used and the return value
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger {
|
|||
func (l *JSONLogger) Hooks() *tracing.Hooks {
|
||||
return &tracing.Hooks{
|
||||
OnTxStart: l.CaptureTxStart,
|
||||
OnEnd: l.CaptureEnd,
|
||||
OnExit: l.CaptureExit,
|
||||
OnOpcode: l.CaptureState,
|
||||
OnFault: l.CaptureFault,
|
||||
}
|
||||
|
|
@ -87,7 +87,10 @@ func (l *JSONLogger) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64
|
|||
}
|
||||
|
||||
// CaptureEnd is triggered at end of execution.
|
||||
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (l *JSONLogger) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth > 0 {
|
||||
return
|
||||
}
|
||||
type endLog struct {
|
||||
Output string `json:"output"`
|
||||
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
|
||||
|
|
|
|||
|
|
@ -64,7 +64,6 @@ func newFourByteTracer(ctx *directory.Context, _ json.RawMessage) (*directory.Tr
|
|||
return &directory.Tracer{
|
||||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnter: t.CaptureEnter,
|
||||
},
|
||||
GetResult: t.GetResult,
|
||||
|
|
@ -94,16 +93,8 @@ func (t *fourByteTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transa
|
|||
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
||||
}
|
||||
|
||||
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||
func (t *fourByteTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
// Save the outer calldata
|
||||
if len(input) >= 4 {
|
||||
t.store(input[0:4], len(input)-4)
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *fourByteTracer) CaptureEnter(opcode tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *fourByteTracer) CaptureEnter(depth int, opcode tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
// Skip if tracing was interrupted
|
||||
if t.interrupt.Load() {
|
||||
return
|
||||
|
|
|
|||
|
|
@ -130,11 +130,8 @@ func newCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trac
|
|||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnTxEnd: t.CaptureTxEnd,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnd: t.CaptureEnd,
|
||||
OnEnter: t.CaptureEnter,
|
||||
OnExit: t.CaptureExit,
|
||||
OnOpcode: t.CaptureState,
|
||||
OnLog: t.OnLog,
|
||||
},
|
||||
GetResult: t.GetResult,
|
||||
|
|
@ -151,38 +148,13 @@ func newCallTracerObject(ctx *directory.Context, cfg json.RawMessage) (*callTrac
|
|||
}
|
||||
// First callframe contains tx context info
|
||||
// and is populated on start and end.
|
||||
return &callTracer{callstack: make([]callFrame, 1), config: config}, nil
|
||||
}
|
||||
|
||||
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||
func (t *callTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
toCopy := to
|
||||
t.callstack[0] = callFrame{
|
||||
Type: vm.CALL,
|
||||
From: from,
|
||||
To: &toCopy,
|
||||
Input: common.CopyBytes(input),
|
||||
Gas: t.gasLimit,
|
||||
Value: value,
|
||||
}
|
||||
if create {
|
||||
t.callstack[0].Type = vm.CREATE
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||
func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
t.callstack[0].processOutput(output, err, reverted)
|
||||
}
|
||||
|
||||
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
|
||||
func (t *callTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
return &callTracer{callstack: make([]callFrame, 0, 1), config: config}, nil
|
||||
}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *callTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
t.depth++
|
||||
if t.config.OnlyTopCall {
|
||||
func (t *callTracer) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
t.depth = depth
|
||||
if t.config.OnlyTopCall && depth > 0 {
|
||||
return
|
||||
}
|
||||
// Skip if tracing was interrupted
|
||||
|
|
@ -199,30 +171,47 @@ func (t *callTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to co
|
|||
Gas: gas,
|
||||
Value: value,
|
||||
}
|
||||
if depth == 0 {
|
||||
call.Gas = t.gasLimit
|
||||
}
|
||||
t.callstack = append(t.callstack, call)
|
||||
}
|
||||
|
||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||
// execute any code.
|
||||
func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
t.depth--
|
||||
func (t *callTracer) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if depth == 0 {
|
||||
t.captureEnd(output, gasUsed, err, reverted)
|
||||
return
|
||||
}
|
||||
|
||||
t.depth = depth - 1
|
||||
if t.config.OnlyTopCall {
|
||||
return
|
||||
}
|
||||
|
||||
size := len(t.callstack)
|
||||
if size <= 1 {
|
||||
return
|
||||
}
|
||||
// pop call
|
||||
// Pop call.
|
||||
call := t.callstack[size-1]
|
||||
t.callstack = t.callstack[:size-1]
|
||||
size -= 1
|
||||
|
||||
call.GasUsed = gasUsed
|
||||
call.processOutput(output, err, reverted)
|
||||
// Nest call into parent.
|
||||
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
|
||||
}
|
||||
|
||||
func (t *callTracer) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
if len(t.callstack) != 1 {
|
||||
return
|
||||
}
|
||||
t.callstack[0].processOutput(output, err, reverted)
|
||||
}
|
||||
|
||||
func (t *callTracer) CaptureTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
|
||||
t.gasLimit = tx.Gas()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,8 +144,6 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.
|
|||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: ft.CaptureTxStart,
|
||||
OnTxEnd: ft.CaptureTxEnd,
|
||||
OnStart: ft.CaptureStart,
|
||||
OnEnd: ft.CaptureEnd,
|
||||
OnEnter: ft.CaptureEnter,
|
||||
OnExit: ft.CaptureExit,
|
||||
OnOpcode: ft.CaptureState,
|
||||
|
|
@ -156,16 +154,6 @@ func newFlatCallTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.
|
|||
}, nil
|
||||
}
|
||||
|
||||
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||
func (t *flatCallTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
t.tracer.CaptureStart(from, to, create, input, gas, value)
|
||||
}
|
||||
|
||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||
func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
t.tracer.CaptureEnd(output, gasUsed, err, reverted)
|
||||
}
|
||||
|
||||
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
|
||||
func (t *flatCallTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
|
||||
|
|
@ -177,9 +165,12 @@ func (t *flatCallTracer) CaptureFault(pc uint64, op tracing.OpCode, gas, cost ui
|
|||
}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *flatCallTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
t.tracer.CaptureEnter(typ, from, to, input, gas, value)
|
||||
func (t *flatCallTracer) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
t.tracer.CaptureEnter(depth, typ, from, to, input, gas, value)
|
||||
|
||||
if depth == 0 {
|
||||
return
|
||||
}
|
||||
// Child calls must have a value, even if it's zero.
|
||||
// Practically speaking, only STATICCALL has nil value. Set it to zero.
|
||||
if t.tracer.callstack[len(t.tracer.callstack)-1].Value == nil && value == nil {
|
||||
|
|
@ -189,9 +180,12 @@ func (t *flatCallTracer) CaptureEnter(typ tracing.OpCode, from common.Address, t
|
|||
|
||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||
// execute any code.
|
||||
func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
t.tracer.CaptureExit(output, gasUsed, err, reverted)
|
||||
func (t *flatCallTracer) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
t.tracer.CaptureExit(depth, output, gasUsed, err, reverted)
|
||||
|
||||
if depth == 0 {
|
||||
return
|
||||
}
|
||||
// Parity traces don't include CALL/STATICCALLs to precompiles.
|
||||
// By default we remove them from the callstack.
|
||||
if t.config.IncludePrecompiles {
|
||||
|
|
|
|||
|
|
@ -61,8 +61,6 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace
|
|||
Hooks: &tracing.Hooks{
|
||||
OnTxStart: t.CaptureTxStart,
|
||||
OnTxEnd: t.CaptureTxEnd,
|
||||
OnStart: t.CaptureStart,
|
||||
OnEnd: t.CaptureEnd,
|
||||
OnEnter: t.CaptureEnter,
|
||||
OnExit: t.CaptureExit,
|
||||
OnOpcode: t.CaptureState,
|
||||
|
|
@ -80,24 +78,6 @@ func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (*directory.Trace
|
|||
}, nil
|
||||
}
|
||||
|
||||
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
|
||||
func (t *muxTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||
for _, t := range t.tracers {
|
||||
if t.OnStart != nil {
|
||||
t.OnStart(from, to, create, input, gas, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||
func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
for _, t := range t.tracers {
|
||||
if t.OnEnd != nil {
|
||||
t.OnEnd(output, gasUsed, err, reverted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
|
||||
func (t *muxTracer) CaptureState(pc uint64, op tracing.OpCode, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||
for _, t := range t.tracers {
|
||||
|
|
@ -135,20 +115,20 @@ func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason)
|
|||
}
|
||||
|
||||
// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
|
||||
func (t *muxTracer) CaptureEnter(typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
func (t *muxTracer) CaptureEnter(depth int, typ tracing.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
|
||||
for _, t := range t.tracers {
|
||||
if t.OnEnter != nil {
|
||||
t.OnEnter(typ, from, to, input, gas, value)
|
||||
t.OnEnter(depth, typ, from, to, input, gas, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CaptureExit is called when EVM exits a scope, even if the scope didn't
|
||||
// execute any code.
|
||||
func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
func (t *muxTracer) CaptureExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
|
||||
for _, t := range t.tracers {
|
||||
if t.OnExit != nil {
|
||||
t.OnExit(output, gasUsed, err, reverted)
|
||||
t.OnExit(depth, output, gasUsed, err, reverted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue