Skip to content

Commit

Permalink
cmd, core, eth/tracers: support fancier js tracing
Browse files Browse the repository at this point in the history
  • Loading branch information
karalabe committed Nov 18, 2017
1 parent 0dbf55d commit 2d49a70
Show file tree
Hide file tree
Showing 11 changed files with 584 additions and 33 deletions.
5 changes: 5 additions & 0 deletions cmd/evm/json_logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package main
import (
"encoding/json"
"io"
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -35,6 +36,10 @@ func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger {
return &JSONLogger{json.NewEncoder(writer), cfg}
}

func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
return nil
}

// CaptureState outputs state information on the logger.
func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
log := vm.StructLog{
Expand Down
18 changes: 18 additions & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package vm
import (
"math/big"
"sync/atomic"
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -167,6 +168,11 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
}
start := time.Now()

ret, err = run(evm, snapshot, 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
Expand All @@ -177,6 +183,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
contract.UseGas(contract.Gas)
}
}
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
}
return ret, contract.Gas, err
}

Expand Down Expand Up @@ -334,6 +343,12 @@ 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, snapshot, contract, nil)
// check whether the max code size has been exceeded
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
Expand Down Expand Up @@ -363,6 +378,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
}

Expand Down
5 changes: 5 additions & 0 deletions core/vm/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ 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
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
}
Expand Down Expand Up @@ -111,6 +112,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.
Expand Down
13 changes: 8 additions & 5 deletions eth/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner"
Expand Down Expand Up @@ -483,21 +484,23 @@ func (t *timeoutError) Error() string {
// TraceTransaction returns the structured logs created during the execution of EVM
// and returns them as a JSON object.
func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.Hash, config *TraceArgs) (interface{}, error) {
var tracer vm.Tracer
var (
tracer vm.Tracer
err error
)
if config != nil && config.Tracer != nil {
timeout := defaultTraceTimeout
if config.Timeout != nil {
var err error
if timeout, err = time.ParseDuration(*config.Timeout); err != nil {
return nil, err
}
}

var err error
if tracer, ok := tracers.Tracer(*config.Tracer); ok {
*config.Tracer = tracer
}
if tracer, err = ethapi.NewJavascriptTracer(*config.Tracer); err != nil {
return nil, err
}

// Handle timeouts and RPC cancellations
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)
go func() {
Expand Down
Loading

0 comments on commit 2d49a70

Please sign in to comment.