Skip to content

Commit df21d1a

Browse files
committed
eth/tracers, core: use scopecontext in tracers, provide statedb in capturestart
1 parent e862cbf commit df21d1a

File tree

12 files changed

+384
-365
lines changed

12 files changed

+384
-365
lines changed

core/vm/eips.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@ func enable1884(jt *JumpTable) {
7676
}
7777
}
7878

79-
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
80-
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(callContext.contract.Address()))
81-
callContext.stack.push(balance)
79+
func opSelfBalance(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
80+
balance, _ := uint256.FromBig(interpreter.evm.StateDB.GetBalance(scope.Contract.Address()))
81+
scope.Stack.push(balance)
8282
return nil, nil
8383
}
8484

@@ -95,9 +95,9 @@ func enable1344(jt *JumpTable) {
9595
}
9696

9797
// opChainID implements CHAINID opcode
98-
func opChainID(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
98+
func opChainID(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
9999
chainId, _ := uint256.FromBig(interpreter.evm.chainConfig.ChainID)
100-
callContext.stack.push(chainId)
100+
scope.Stack.push(chainId)
101101
return nil, nil
102102
}
103103

core/vm/evm.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
239239
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
240240
// Calling a non existing account, don't do anything, but ping the tracer
241241
if evm.vmConfig.Debug && evm.depth == 0 {
242-
evm.vmConfig.Tracer.CaptureStart(caller.Address(), addr, false, input, gas, value)
242+
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
243243
evm.vmConfig.Tracer.CaptureEnd(ret, 0, 0, nil)
244244
}
245245
return nil, gas, nil
@@ -250,7 +250,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
250250

251251
// Capture the tracer start/end events in debug mode
252252
if evm.vmConfig.Debug && evm.depth == 0 {
253-
evm.vmConfig.Tracer.CaptureStart(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
255255
evm.vmConfig.Tracer.CaptureEnd(ret, startGas-gas, time.Since(startTime), err)
256256
}(gas, time.Now())
@@ -472,7 +472,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
472472
}
473473

474474
if evm.vmConfig.Debug && evm.depth == 0 {
475-
evm.vmConfig.Tracer.CaptureStart(caller.Address(), address, true, codeAndHash.code, gas, value)
475+
evm.vmConfig.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
476476
}
477477
start := time.Now()
478478

core/vm/instructions.go

Lines changed: 212 additions & 212 deletions
Large diffs are not rendered by default.

core/vm/instructions_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func testTwoOperandOp(t *testing.T, tests []TwoOperandTestcase, opFn executionFu
104104
expected := new(uint256.Int).SetBytes(common.Hex2Bytes(test.Expected))
105105
stack.push(x)
106106
stack.push(y)
107-
opFn(&pc, evmInterpreter, &callCtx{nil, stack, nil})
107+
opFn(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
108108
if len(stack.data) != 1 {
109109
t.Errorf("Expected one item on stack after %v, got %d: ", name, len(stack.data))
110110
}
@@ -219,7 +219,7 @@ func TestAddMod(t *testing.T) {
219219
stack.push(z)
220220
stack.push(y)
221221
stack.push(x)
222-
opAddmod(&pc, evmInterpreter, &callCtx{nil, stack, nil})
222+
opAddmod(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
223223
actual := stack.pop()
224224
if actual.Cmp(expected) != 0 {
225225
t.Errorf("Testcase %d, expected %x, got %x", i, expected, actual)
@@ -241,7 +241,7 @@ func getResult(args []*twoOperandParams, opFn executionFunc) []TwoOperandTestcas
241241
y := new(uint256.Int).SetBytes(common.Hex2Bytes(param.y))
242242
stack.push(x)
243243
stack.push(y)
244-
opFn(&pc, interpreter, &callCtx{nil, stack, nil})
244+
opFn(&pc, interpreter, &ScopeContext{nil, stack, nil})
245245
actual := stack.pop()
246246
result[i] = TwoOperandTestcase{param.x, param.y, fmt.Sprintf("%064x", actual)}
247247
}
@@ -299,7 +299,7 @@ func opBenchmark(bench *testing.B, op executionFunc, args ...string) {
299299
a.SetBytes(arg)
300300
stack.push(a)
301301
}
302-
op(&pc, evmInterpreter, &callCtx{nil, stack, nil})
302+
op(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
303303
stack.pop()
304304
}
305305
}
@@ -525,12 +525,12 @@ func TestOpMstore(t *testing.T) {
525525
pc := uint64(0)
526526
v := "abcdef00000000000000abba000000000deaf000000c0de00100000000133700"
527527
stack.pushN(*new(uint256.Int).SetBytes(common.Hex2Bytes(v)), *new(uint256.Int))
528-
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
528+
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
529529
if got := common.Bytes2Hex(mem.GetCopy(0, 32)); got != v {
530530
t.Fatalf("Mstore fail, got %v, expected %v", got, v)
531531
}
532532
stack.pushN(*new(uint256.Int).SetUint64(0x1), *new(uint256.Int))
533-
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
533+
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
534534
if common.Bytes2Hex(mem.GetCopy(0, 32)) != "0000000000000000000000000000000000000000000000000000000000000001" {
535535
t.Fatalf("Mstore failed to overwrite previous value")
536536
}
@@ -553,7 +553,7 @@ func BenchmarkOpMstore(bench *testing.B) {
553553
bench.ResetTimer()
554554
for i := 0; i < bench.N; i++ {
555555
stack.pushN(*value, *memStart)
556-
opMstore(&pc, evmInterpreter, &callCtx{mem, stack, nil})
556+
opMstore(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
557557
}
558558
}
559559

@@ -572,7 +572,7 @@ func BenchmarkOpSHA3(bench *testing.B) {
572572
bench.ResetTimer()
573573
for i := 0; i < bench.N; i++ {
574574
stack.pushN(*uint256.NewInt().SetUint64(32), *start)
575-
opSha3(&pc, evmInterpreter, &callCtx{mem, stack, nil})
575+
opSha3(&pc, evmInterpreter, &ScopeContext{mem, stack, nil})
576576
}
577577
}
578578

core/vm/interpreter.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,12 +62,12 @@ type Interpreter interface {
6262
CanRun([]byte) bool
6363
}
6464

65-
// callCtx contains the things that are per-call, such as stack and memory,
65+
// ScopeContext contains the things that are per-call, such as stack and memory,
6666
// but not transients like pc and gas
67-
type callCtx struct {
68-
memory *Memory
69-
stack *Stack
70-
contract *Contract
67+
type ScopeContext struct {
68+
Memory *Memory
69+
Stack *Stack
70+
Contract *Contract
7171
}
7272

7373
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
@@ -163,10 +163,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
163163
op OpCode // current opcode
164164
mem = NewMemory() // bound memory
165165
stack = newstack() // local stack
166-
callContext = &callCtx{
167-
memory: mem,
168-
stack: stack,
169-
contract: contract,
166+
callContext = &ScopeContext{
167+
Memory: mem,
168+
Stack: stack,
169+
Contract: contract,
170170
}
171171
// For optimisation reason we're using uint64 as the program counter.
172172
// It's theoretically possible to go above 2^64. The YP defines the PC
@@ -191,9 +191,9 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
191191
defer func() {
192192
if err != nil {
193193
if !logged {
194-
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, mem, stack, in.returnData, contract, in.evm.depth, err)
194+
in.cfg.Tracer.CaptureState(in.evm, pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
195195
} else {
196-
in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, mem, stack, contract, in.evm.depth, err)
196+
in.cfg.Tracer.CaptureFault(in.evm, pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
197197
}
198198
}
199199
}()
@@ -275,7 +275,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
275275
}
276276

277277
if in.cfg.Debug {
278-
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, stack, in.returnData, contract, in.evm.depth, err)
278+
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
279279
logged = true
280280
}
281281

core/vm/jump_table.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
)
2222

2323
type (
24-
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error)
24+
executionFunc func(pc *uint64, interpreter *EVMInterpreter, callContext *ScopeContext) ([]byte, error)
2525
gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64
2626
// memorySizeFunc returns the required size, and whether the operation overflowed a uint64
2727
memorySizeFunc func(*Stack) (size uint64, overflow bool)

core/vm/logger.go

Lines changed: 18 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ package vm
1818

1919
import (
2020
"encoding/hex"
21-
"errors"
2221
"fmt"
2322
"io"
2423
"math/big"
@@ -32,8 +31,6 @@ import (
3231
"github.com/ethereum/go-ethereum/params"
3332
)
3433

35-
var errTraceLimitReached = errors.New("the number of logs reached the specified limit")
36-
3734
// Storage represents a contract's storage.
3835
type Storage map[common.Hash]common.Hash
3936

@@ -107,10 +104,10 @@ func (s *StructLog) ErrorString() string {
107104
// Note that reference types are actual VM data structures; make copies
108105
// if you need to retain them beyond the current call.
109106
type Tracer interface {
110-
CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error
111-
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error
112-
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
113-
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
107+
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
108+
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
109+
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
110+
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
114111
}
115112

116113
// StructLogger is an EVM state logger and implements Tracer.
@@ -139,17 +136,19 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
139136
}
140137

141138
// CaptureStart implements the Tracer interface to initialize the tracing operation.
142-
func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
143-
return nil
139+
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
144140
}
145141

146142
// CaptureState logs a new structured log message and pushes it out to the environment
147143
//
148144
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
149-
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error {
145+
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
146+
memory := scope.Memory
147+
stack := scope.Stack
148+
contract := scope.Contract
150149
// check if already accumulated the specified number of logs
151150
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
152-
return errTraceLimitReached
151+
return
153152
}
154153
// Copy a snapshot of the current memory state to a new buffer
155154
var mem []byte
@@ -199,17 +198,15 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
199198
// create a new snapshot of the EVM.
200199
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
201200
l.logs = append(l.logs, log)
202-
return nil
203201
}
204202

205203
// CaptureFault implements the Tracer interface to trace an execution fault
206204
// while running an opcode.
207-
func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
208-
return nil
205+
func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
209206
}
210207

211208
// CaptureEnd is called after the call finishes to finalize the tracing.
212-
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
209+
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
213210
l.output = output
214211
l.err = err
215212
if l.cfg.Debug {
@@ -218,7 +215,6 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration
218215
fmt.Printf(" error: %v\n", err)
219216
}
220217
}
221-
return nil
222218
}
223219

224220
// StructLogs returns the captured log entries.
@@ -292,7 +288,7 @@ func NewMarkdownLogger(cfg *LogConfig, writer io.Writer) *mdLogger {
292288
return l
293289
}
294290

295-
func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
291+
func (t *mdLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
296292
if !create {
297293
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `0x%x`\nGas: `%d`\nValue `%v` wei\n",
298294
from.String(), to.String(),
@@ -307,10 +303,11 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b
307303
| Pc | Op | Cost | Stack | RStack | Refund |
308304
|-------|-------------|------|-----------|-----------|---------|
309305
`)
310-
return nil
311306
}
312307

313-
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error {
308+
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
309+
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
310+
stack := scope.Stack
314311
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost)
315312

316313
if !t.cfg.DisableStack {
@@ -327,18 +324,13 @@ func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64
327324
if err != nil {
328325
fmt.Fprintf(t.out, "Error: %v\n", err)
329326
}
330-
return nil
331327
}
332328

333-
func (t *mdLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
334-
329+
func (t *mdLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error) {
335330
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
336-
337-
return nil
338331
}
339332

340-
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) error {
333+
func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, tm time.Duration, err error) {
341334
fmt.Fprintf(t.out, "\nOutput: `0x%x`\nConsumed gas: `%d`\nError: `%v`\n",
342335
output, gasUsed, err)
343-
return nil
344336
}

core/vm/logger_json.go

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,16 @@ func NewJSONLogger(cfg *LogConfig, writer io.Writer) *JSONLogger {
4141
return l
4242
}
4343

44-
func (l *JSONLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error {
45-
return nil
44+
func (l *JSONLogger) CaptureStart(env *EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
4645
}
4746

47+
func (l *JSONLogger) CaptureFault(*EVM, uint64, OpCode, uint64, uint64, *ScopeContext, int, error) {}
48+
4849
// CaptureState outputs state information on the logger.
49-
func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rData []byte, contract *Contract, depth int, err error) error {
50+
func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
51+
memory := scope.Memory
52+
stack := scope.Stack
53+
5054
log := StructLog{
5155
Pc: pc,
5256
Op: op,
@@ -72,24 +76,19 @@ func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint
7276
if !l.cfg.DisableReturnData {
7377
log.ReturnData = rData
7478
}
75-
return l.encoder.Encode(log)
76-
}
77-
78-
// CaptureFault outputs state information on the logger.
79-
func (l *JSONLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
80-
return nil
79+
l.encoder.Encode(log)
8180
}
8281

8382
// CaptureEnd is triggered at end of execution.
84-
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error {
83+
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
8584
type endLog struct {
8685
Output string `json:"output"`
8786
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
8887
Time time.Duration `json:"time"`
8988
Err string `json:"error,omitempty"`
9089
}
9190
if err != nil {
92-
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
91+
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, err.Error()})
9392
}
94-
return l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
93+
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t, ""})
9594
}

core/vm/logger_test.go

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,20 @@ func TestStoreCapture(t *testing.T) {
5353
var (
5454
env = NewEVM(BlockContext{}, TxContext{}, &dummyStatedb{}, params.TestChainConfig, Config{})
5555
logger = NewStructLogger(nil)
56-
mem = NewMemory()
57-
stack = newstack()
5856
contract = NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 0)
57+
scope = &ScopeContext{
58+
Memory: NewMemory(),
59+
Stack: newstack(),
60+
Contract: contract,
61+
}
5962
)
60-
stack.push(uint256.NewInt().SetUint64(1))
61-
stack.push(uint256.NewInt())
63+
scope.Stack.push(uint256.NewInt().SetUint64(1))
64+
scope.Stack.push(uint256.NewInt())
6265
var index common.Hash
63-
logger.CaptureState(env, 0, SSTORE, 0, 0, mem, stack, nil, contract, 0, nil)
66+
logger.CaptureState(env, 0, SSTORE, 0, 0, scope, nil, 0, nil)
6467
if len(logger.storage[contract.Address()]) == 0 {
65-
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(), len(logger.storage[contract.Address()]))
68+
t.Fatalf("expected exactly 1 changed value on address %x, got %d", contract.Address(),
69+
len(logger.storage[contract.Address()]))
6670
}
6771
exp := common.BigToHash(big.NewInt(1))
6872
if logger.storage[contract.Address()][index] != exp {

0 commit comments

Comments
 (0)