diff options
author | Péter Szilágyi <peterke@gmail.com> | 2017-12-21 19:56:11 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-12-21 19:56:11 +0800 |
commit | 5258785c81959109138ebeca613f12c277188abc (patch) | |
tree | b3d21fc2f38927841f44541a3717b69f5a3c5ec1 /core | |
parent | 1a5425779b026587e36f5d21a6e50efe17cc6a9d (diff) | |
download | dexon-5258785c81959109138ebeca613f12c277188abc.tar dexon-5258785c81959109138ebeca613f12c277188abc.tar.gz dexon-5258785c81959109138ebeca613f12c277188abc.tar.bz2 dexon-5258785c81959109138ebeca613f12c277188abc.tar.lz dexon-5258785c81959109138ebeca613f12c277188abc.tar.xz dexon-5258785c81959109138ebeca613f12c277188abc.tar.zst dexon-5258785c81959109138ebeca613f12c277188abc.zip |
cmd, core, eth/tracers: support fancier js tracing (#15516)
* cmd, core, eth/tracers: support fancier js tracing
* eth, internal/web3ext: rework trace API, concurrency, chain tracing
* eth/tracers: add three more JavaScript tracers
* eth/tracers, vendor: swap ottovm to duktape for tracing
* core, eth, internal: finalize call tracer and needed extras
* eth, tests: prestate tracer, call test suite, rewinding
* vendor: fix windows builds for tracer js engine
* vendor: temporary duktape fix
* eth/tracers: fix up 4byte and evmdis tracer
* vendor: pull in latest duktape with my upstream fixes
* eth: fix some review comments
* eth: rename rewind to reexec to make it more obvious
* core/vm: terminate tracing using defers
Diffstat (limited to 'core')
-rw-r--r-- | core/vm/evm.go | 27 | ||||
-rw-r--r-- | core/vm/interpreter.go | 17 | ||||
-rw-r--r-- | core/vm/logger.go | 10 |
3 files changed, 45 insertions, 9 deletions
diff --git a/core/vm/evm.go b/core/vm/evm.go index cbb5a03ce..a3f3a97cb 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -19,6 +19,7 @@ package vm import ( "math/big" "sync/atomic" + "time" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -165,13 +166,23 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas } evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value) - // initialise a new contract and set the code that is to be used by the - // E The contract is a scoped environment for this execution context - // only. + // 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. contract := NewContract(caller, to, value, gas) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + start := time.Now() + + // Capture the tracer start/end events in debug mode + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value) + + defer func() { // Lazy evaluation of the parameters + evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + }() + } ret, err = run(evm, contract, input) + // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in homestead this also counts for code storage gas errors. @@ -338,7 +349,14 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, contractAddr, gas, nil } + + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value) + } + start := time.Now() + ret, err = run(evm, contract, nil) + // check whether the max code size has been exceeded maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize // if the contract creation ran successfully and no errors were returned @@ -367,6 +385,9 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I if maxCodeSizeExceeded && err == nil { err = errMaxCodeSizeExceeded } + if evm.vmConfig.Debug && evm.depth == 0 { + evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err) + } return ret, contractAddr, contract.Gas, err } diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 455f970dd..482e67a3a 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -144,12 +144,17 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er ) contract.Input = input - defer func() { - if err != nil && !logged && in.cfg.Debug { - in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) - } - }() - + if in.cfg.Debug { + defer func() { + if err != nil { + if !logged { + in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err) + } else { + in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, 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 diff --git a/core/vm/logger.go b/core/vm/logger.go index 75309da92..1a6e43ee3 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -84,7 +84,9 @@ func (s *StructLog) OpName() string { // Note that reference types are actual VM data structures; make copies // if you need to retain them beyond the current call. type Tracer interface { + CaptureStart(from common.Address, to common.Address, call bool, input []byte, gas uint64, value *big.Int) error CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error + CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error } @@ -111,6 +113,10 @@ func NewStructLogger(cfg *LogConfig) *StructLogger { return logger } +func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error { + return nil +} + // CaptureState logs a new structured log message and pushes it out to the environment // // CaptureState also tracks SSTORE ops to track dirty values. @@ -161,6 +167,10 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui return nil } +func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { + return nil +} + func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { fmt.Printf("0x%x", output) if err != nil { |