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
This commit is contained in:
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
Reference in New Issue
Block a user