Skip to content

Commit f138d1f

Browse files
authored
Merge pull request #12 from node-real/tracer_add_statediff
add statediff tracer
2 parents defed6f + da210ce commit f138d1f

File tree

15 files changed

+503
-70
lines changed

15 files changed

+503
-70
lines changed

core/state_transition.go

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,10 @@ The state transitioning model does all the necessary work to work out a valid ne
3939
3) Create a new state object if the recipient is \0*32
4040
4) Value transfer
4141
== If contract creation ==
42-
4a) Attempt to run transaction data
43-
4b) If valid, use result as code for the new state object
42+
43+
4a) Attempt to run transaction data
44+
4b) If valid, use result as code for the new state object
45+
4446
== end ==
4547
5) Run Script section
4648
6) Derive new state root
@@ -213,13 +215,13 @@ func (st *StateTransition) preCheck() error {
213215
// TransitionDb will transition the state by applying the current message and
214216
// returning the evm execution result with following fields.
215217
//
216-
// - used gas:
217-
// total gas used (including gas being refunded)
218-
// - returndata:
219-
// the returned data from evm
220-
// - concrete execution error:
221-
// various **EVM** error which aborts the execution,
222-
// e.g. ErrOutOfGas, ErrExecutionReverted
218+
// - used gas:
219+
// total gas used (including gas being refunded)
220+
// - returndata:
221+
// the returned data from evm
222+
// - concrete execution error:
223+
// various **EVM** error which aborts the execution,
224+
// e.g. ErrOutOfGas, ErrExecutionReverted
223225
//
224226
// However if any consensus issue encountered, return the error directly with
225227
// nil evm execution result.
@@ -238,6 +240,14 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
238240
if err := st.preCheck(); err != nil {
239241
return nil, err
240242
}
243+
244+
if st.evm.VmConfig.Debug {
245+
st.evm.VmConfig.Tracer.CaptureTxStart(st.initialGas)
246+
defer func() {
247+
st.evm.VmConfig.Tracer.CaptureTxEnd(st.gas)
248+
}()
249+
}
250+
241251
msg := st.msg
242252
sender := vm.AccountRef(msg.From())
243253
homestead := st.evm.ChainConfig().IsHomestead(st.evm.Context.BlockNumber)

core/vm/access_list_tracer.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,12 @@ func (a *AccessListTracer) AccessList() types.AccessList {
180180
func (a *AccessListTracer) Equal(other *AccessListTracer) bool {
181181
return a.list.equal(other.list)
182182
}
183+
184+
// CaptureTxStart implements the Tracer interface and is invoked at the beginning of
185+
// transaction processing.
186+
func (t *AccessListTracer) CaptureTxStart(gasLimit uint64) {
187+
}
188+
189+
// CaptureTxStart implements the Tracer interface and is invoked at the end of
190+
// transaction processing.
191+
func (t *AccessListTracer) CaptureTxEnd(restGas uint64) {}

core/vm/evm.go

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ type EVM struct {
134134
chainRules params.Rules
135135
// virtual machine configuration options used to initialise the
136136
// evm.
137-
vmConfig Config
137+
VmConfig Config
138138
// global (to this context) ethereum virtual machine
139139
// used throughout the execution of the tx.
140140
interpreters []Interpreter
@@ -155,7 +155,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
155155
evm.Context = blockCtx
156156
evm.TxContext = txCtx
157157
evm.StateDB = statedb
158-
evm.vmConfig = vmConfig
158+
evm.VmConfig = vmConfig
159159
evm.chainConfig = chainConfig
160160
evm.chainRules = chainConfig.Rules(blockCtx.BlockNumber)
161161
evm.interpreters = make([]Interpreter, 0, 1)
@@ -215,7 +215,7 @@ func (evm *EVM) Interpreter() Interpreter {
215215
// the necessary steps to create accounts and reverses the state in case of an
216216
// execution error or failed value transfer.
217217
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
218-
if evm.vmConfig.NoRecursion && evm.depth > 0 {
218+
if evm.VmConfig.NoRecursion && evm.depth > 0 {
219219
return nil, gas, nil
220220
}
221221
// Fail if we're trying to execute above the call depth limit
@@ -232,13 +232,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
232232
if !evm.StateDB.Exist(addr) {
233233
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
234234
// Calling a non existing account, don't do anything, but ping the tracer
235-
if evm.vmConfig.Debug {
235+
if evm.VmConfig.Debug {
236236
if evm.depth == 0 {
237-
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
238-
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
237+
evm.VmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
238+
evm.VmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
239239
} else {
240-
evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
241-
evm.vmConfig.Tracer.CaptureExit(ret, 0, nil)
240+
evm.VmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
241+
evm.VmConfig.Tracer.CaptureExit(ret, 0, nil)
242242
}
243243
}
244244
return nil, gas, nil
@@ -248,17 +248,17 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
248248
evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)
249249

250250
// Capture the tracer start/end events in debug mode
251-
if evm.vmConfig.Debug {
251+
if evm.VmConfig.Debug {
252252
if evm.depth == 0 {
253-
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
253+
evm.VmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
254254
defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
255-
evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
255+
evm.VmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
256256
}(gas, time.Now())
257257
} else {
258258
// Handle tracer events for entering and exiting a call frame
259-
evm.vmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
259+
evm.VmConfig.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
260260
defer func(startGas uint64) {
261-
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
261+
evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
262262
}(gas)
263263
}
264264
}
@@ -304,7 +304,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
304304
// CallCode differs from Call in the sense that it executes the given address'
305305
// code with the caller as context.
306306
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
307-
if evm.vmConfig.NoRecursion && evm.depth > 0 {
307+
if evm.VmConfig.NoRecursion && evm.depth > 0 {
308308
return nil, gas, nil
309309
}
310310
// Fail if we're trying to execute above the call depth limit
@@ -321,10 +321,10 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
321321
var snapshot = evm.StateDB.Snapshot()
322322

323323
// Invoke tracer hooks that signal entering/exiting a call frame
324-
if evm.vmConfig.Debug {
325-
evm.vmConfig.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
324+
if evm.VmConfig.Debug {
325+
evm.VmConfig.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
326326
defer func(startGas uint64) {
327-
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
327+
evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
328328
}(gas)
329329
}
330330

@@ -355,7 +355,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
355355
// DelegateCall differs from CallCode in the sense that it executes the given address'
356356
// code with the caller as context and the caller is set to the caller of the caller.
357357
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
358-
if evm.vmConfig.NoRecursion && evm.depth > 0 {
358+
if evm.VmConfig.NoRecursion && evm.depth > 0 {
359359
return nil, gas, nil
360360
}
361361
// Fail if we're trying to execute above the call depth limit
@@ -365,10 +365,10 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
365365
var snapshot = evm.StateDB.Snapshot()
366366

367367
// Invoke tracer hooks that signal entering/exiting a call frame
368-
if evm.vmConfig.Debug {
369-
evm.vmConfig.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil)
368+
if evm.VmConfig.Debug {
369+
evm.VmConfig.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, nil)
370370
defer func(startGas uint64) {
371-
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
371+
evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
372372
}(gas)
373373
}
374374

@@ -397,7 +397,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
397397
// Opcodes that attempt to perform such modifications will result in exceptions
398398
// instead of performing the modifications.
399399
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
400-
if evm.vmConfig.NoRecursion && evm.depth > 0 {
400+
if evm.VmConfig.NoRecursion && evm.depth > 0 {
401401
return nil, gas, nil
402402
}
403403
// Fail if we're trying to execute above the call depth limit
@@ -418,10 +418,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
418418
evm.StateDB.AddBalance(addr, big0)
419419

420420
// Invoke tracer hooks that signal entering/exiting a call frame
421-
if evm.vmConfig.Debug {
422-
evm.vmConfig.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
421+
if evm.VmConfig.Debug {
422+
evm.VmConfig.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
423423
defer func(startGas uint64) {
424-
evm.vmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
424+
evm.VmConfig.Tracer.CaptureExit(ret, startGas-gas, err)
425425
}(gas)
426426
}
427427

@@ -498,15 +498,15 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
498498
contract := NewContract(caller, AccountRef(address), value, gas)
499499
contract.SetCodeOptionalHash(&address, codeAndHash)
500500

501-
if evm.vmConfig.NoRecursion && evm.depth > 0 {
501+
if evm.VmConfig.NoRecursion && evm.depth > 0 {
502502
return nil, address, gas, nil
503503
}
504504

505-
if evm.vmConfig.Debug {
505+
if evm.VmConfig.Debug {
506506
if evm.depth == 0 {
507-
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
507+
evm.VmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
508508
} else {
509-
evm.vmConfig.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
509+
evm.VmConfig.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
510510
}
511511
}
512512

@@ -546,11 +546,11 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
546546
}
547547
}
548548

549-
if evm.vmConfig.Debug {
549+
if evm.VmConfig.Debug {
550550
if evm.depth == 0 {
551-
evm.vmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
551+
evm.VmConfig.Tracer.CaptureEnd(ret, gas-contract.Gas, time.Since(start), err)
552552
} else {
553-
evm.vmConfig.Tracer.CaptureExit(ret, gas-contract.Gas, err)
553+
evm.VmConfig.Tracer.CaptureExit(ret, gas-contract.Gas, err)
554554
}
555555
}
556556
return ret, address, contract.Gas, err

core/vm/instructions.go

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
244244
interpreter.hasher.Read(interpreter.hasherBuf[:])
245245

246246
evm := interpreter.evm
247-
if evm.vmConfig.EnablePreimageRecording {
247+
if evm.VmConfig.EnablePreimageRecording {
248248
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
249249
}
250250

@@ -390,16 +390,21 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
390390
// opExtCodeHash returns the code hash of a specified account.
391391
// There are several cases when the function is called, while we can relay everything
392392
// to `state.GetCodeHash` function to ensure the correctness.
393-
// (1) Caller tries to get the code hash of a normal contract account, state
393+
//
394+
// (1) Caller tries to get the code hash of a normal contract account, state
395+
//
394396
// should return the relative code hash and set it as the result.
395397
//
396-
// (2) Caller tries to get the code hash of a non-existent account, state should
398+
// (2) Caller tries to get the code hash of a non-existent account, state should
399+
//
397400
// return common.Hash{} and zero will be set as the result.
398401
//
399-
// (3) Caller tries to get the code hash for an account without contract code,
402+
// (3) Caller tries to get the code hash for an account without contract code,
403+
//
400404
// state should return emptyCodeHash(0xc5d246...) as the result.
401405
//
402-
// (4) Caller tries to get the code hash of a precompiled account, the result
406+
// (4) Caller tries to get the code hash of a precompiled account, the result
407+
//
403408
// should be zero or emptyCodeHash.
404409
//
405410
// It is worth noting that in order to avoid unnecessary create and clean,
@@ -408,10 +413,12 @@ func opExtCodeCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
408413
// If the precompile account is not transferred any amount on a private or
409414
// customized chain, the return value will be zero.
410415
//
411-
// (5) Caller tries to get the code hash for an account which is marked as suicided
416+
// (5) Caller tries to get the code hash for an account which is marked as suicided
417+
//
412418
// in the current transaction, the code hash of this account should be returned.
413419
//
414-
// (6) Caller tries to get the code hash for an account which is marked as deleted,
420+
// (6) Caller tries to get the code hash for an account which is marked as deleted,
421+
//
415422
// this account should be regarded as a non-existent account and zero should be returned.
416423
func opExtCodeHash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
417424
slot := scope.Stack.peek()

core/vm/logger.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,10 @@ func (s *StructLog) ErrorString() string {
105105
// Note that reference types are actual VM data structures; make copies
106106
// if you need to retain them beyond the current call.
107107
type EVMLogger interface {
108+
// Transaction level
109+
CaptureTxStart(gasLimit uint64)
110+
CaptureTxEnd(restGas uint64)
111+
108112
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
109113
CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
110114
CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
@@ -147,6 +151,10 @@ func (l *StructLogger) Reset() {
147151
l.err = nil
148152
}
149153

154+
func (*StructLogger) CaptureTxStart(gasLimit uint64) {}
155+
156+
func (*StructLogger) CaptureTxEnd(restGas uint64) {}
157+
150158
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
151159
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
152160
l.env = env
@@ -307,6 +315,15 @@ func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger {
307315
return l
308316
}
309317

318+
// CaptureTxStart implements the Tracer interface and is invoked at the beginning of
319+
// transaction processing.
320+
func (t *mdLogger) CaptureTxStart(gasLimit uint64) {
321+
}
322+
323+
// CaptureTxStart implements the Tracer interface and is invoked at the end of
324+
// transaction processing.
325+
func (t *mdLogger) CaptureTxEnd(restGas uint64) {}
326+
310327
func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
311328
t.env = env
312329
if !create {

core/vm/logger_json.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger {
4242
return l
4343
}
4444

45+
// CaptureTxStart implements the Tracer interface and is invoked at the beginning of
46+
// transaction processing.
47+
func (t *JSONLogger) CaptureTxStart(gasLimit uint64) {
48+
}
49+
50+
// CaptureTxStart implements the Tracer interface and is invoked at the end of
51+
// transaction processing.
52+
func (t *JSONLogger) CaptureTxEnd(restGas uint64) {}
53+
4554
func (l *JSONLogger) CaptureStart(env *EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
4655
l.env = env
4756
}

eth/tracers/api.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"bufio"
2121
"bytes"
2222
"context"
23+
"encoding/json"
2324
"errors"
2425
"fmt"
2526
"io/ioutil"
@@ -172,6 +173,8 @@ type TraceConfig struct {
172173
Tracer *string
173174
Timeout *string
174175
Reexec *uint64
176+
177+
TracerConfig json.RawMessage
175178
}
176179

177180
// TraceCallConfig is the config for traceCall API. It holds one more
@@ -935,7 +938,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Contex
935938
return nil, err
936939
}
937940
}
938-
if t, err := New(*config.Tracer, txctx); err != nil {
941+
if t, err := New(*config.Tracer, txctx, config.TracerConfig); err != nil {
939942
return nil, err
940943
} else {
941944
deadlineCtx, cancel := context.WithTimeout(ctx, timeout)

eth/tracers/js/tracer.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ type jsTracer struct {
424424
// New instantiates a new tracer instance. code specifies a Javascript snippet,
425425
// which must evaluate to an expression returning an object with 'step', 'fault'
426426
// and 'result' functions.
427-
func newJsTracer(code string, ctx *tracers2.Context) (tracers2.Tracer, error) {
427+
func newJsTracer(code string, ctx *tracers2.Context, cfg json.RawMessage) (tracers2.Tracer, error) {
428428
if c, ok := assetTracers[code]; ok {
429429
code = c
430430
}
@@ -679,6 +679,15 @@ func wrapError(context string, err error) error {
679679
return fmt.Errorf("%v in server-side tracer function '%v'", err, context)
680680
}
681681

682+
// CaptureTxStart implements the Tracer interface and is invoked at the beginning of
683+
// transaction processing.
684+
func (jst *jsTracer) CaptureTxStart(gasLimit uint64) {
685+
}
686+
687+
// CaptureTxStart implements the Tracer interface and is invoked at the end of
688+
// transaction processing.
689+
func (t *jsTracer) CaptureTxEnd(restGas uint64) {}
690+
682691
// CaptureStart implements the Tracer interface to initialize the tracing operation.
683692
func (jst *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
684693
jst.env = env

0 commit comments

Comments
 (0)