Skip to content

Commit

Permalink
cmd, core, eth/tracers: support fancier js tracing (ethereum#15516)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
karalabe authored and mariameda committed Aug 19, 2018
1 parent 40e70bf commit 3cca2e1
Show file tree
Hide file tree
Showing 36 changed files with 121 additions and 361 deletions.
27 changes: 24 additions & 3 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 @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down
54 changes: 21 additions & 33 deletions core/vm/logger.go
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2015 The go-nilu Authors
// This file is part of the go-nilu library.
// Copyright 2015 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-nilu library is free software: you can redistribute it and/or modify
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
Expand All @@ -23,10 +23,10 @@ import (
"math/big"
"time"

"github.com/NiluPlatform/go-nilu/common"
"github.com/NiluPlatform/go-nilu/common/hexutil"
"github.com/NiluPlatform/go-nilu/common/math"
"github.com/NiluPlatform/go-nilu/core/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/types"
)

type Storage map[common.Hash]common.Hash
Expand Down Expand Up @@ -62,30 +62,22 @@ type StructLog struct {
Stack []*big.Int `json:"stack"`
Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"`
Err error `json:"-"`
Err error `json:"error"`
}

// overrides for gencodec
type structLogMarshaling struct {
Stack []*math.HexOrDecimal256
Gas math.HexOrDecimal64
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
OpName string `json:"opName"` // adds call to OpName() in MarshalJSON
ErrorString string `json:"error"` // adds call to ErrorString() in MarshalJSON
Stack []*math.HexOrDecimal256
Gas math.HexOrDecimal64
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
OpName string `json:"opName"`
}

func (s *StructLog) OpName() string {
return s.Op.String()
}

func (s *StructLog) ErrorString() string {
if s.Err != nil {
return s.Err.Error()
}
return ""
}

// Tracer is used to collect execution traces from an EVM transaction
// execution. CaptureState is called for each step of the VM with the
// current VM state.
Expand All @@ -108,8 +100,6 @@ type StructLogger struct {

logs []StructLog
changedValues map[common.Address]Storage
output []byte
err error
}

// NewStructLogger returns a new logger
Expand Down Expand Up @@ -182,19 +172,17 @@ func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost ui
}

func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
l.output = output
l.err = err
fmt.Printf("0x%x", output)
if err != nil {
fmt.Printf(" error: %v\n", err)
}
return nil
}

// StructLogs returns the captured log entries.
func (l *StructLogger) StructLogs() []StructLog { return l.logs }

// Error returns the VM error captured by the trace.
func (l *StructLogger) Error() error { return l.err }

// Output returns the VM return value captured by the trace.
func (l *StructLogger) Output() []byte { return l.output }
// StructLogs returns a list of captured log entries
func (l *StructLogger) StructLogs() []StructLog {
return l.logs
}

// WriteTrace writes a formatted trace to the given writer
func WriteTrace(writer io.Writer, logs []StructLog) {
Expand Down
Loading

0 comments on commit 3cca2e1

Please sign in to comment.