Skip to content

Commit 9e23610

Browse files
authored
Merge pull request ethereum#23104 from karalabe/tracer-context
eth/tracers: expose contextual infos (block hash, tx hash, tx index)
2 parents 10eb654 + 29905d8 commit 9e23610

File tree

4 files changed

+49
-41
lines changed

4 files changed

+49
-41
lines changed

eth/tracers/api.go

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,6 @@ type StdTraceConfig struct {
178178
TxHash common.Hash
179179
}
180180

181-
// txTraceContext is the contextual infos about a transaction before it gets run.
182-
type txTraceContext struct {
183-
index int // Index of the transaction within the block
184-
hash common.Hash // Hash of the transaction
185-
block common.Hash // Hash of the block containing the transaction
186-
}
187-
188181
// txTraceResult is the result of a single transaction trace.
189182
type txTraceResult struct {
190183
Result interface{} `json:"result,omitempty"` // Trace results produced by the tracer
@@ -272,10 +265,10 @@ func (api *API) traceChain(ctx context.Context, start, end *types.Block, config
272265
// Trace all the transactions contained within
273266
for i, tx := range task.block.Transactions() {
274267
msg, _ := tx.AsMessage(signer, task.block.BaseFee())
275-
txctx := &txTraceContext{
276-
index: i,
277-
hash: tx.Hash(),
278-
block: task.block.Hash(),
268+
txctx := &Context{
269+
BlockHash: task.block.Hash(),
270+
TxIndex: i,
271+
TxHash: tx.Hash(),
279272
}
280273
res, err := api.traceTx(localctx, msg, txctx, blockCtx, task.statedb, config)
281274
if err != nil {
@@ -524,10 +517,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
524517
// Fetch and execute the next transaction trace tasks
525518
for task := range jobs {
526519
msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
527-
txctx := &txTraceContext{
528-
index: task.index,
529-
hash: txs[task.index].Hash(),
530-
block: blockHash,
520+
txctx := &Context{
521+
BlockHash: blockHash,
522+
TxIndex: task.index,
523+
TxHash: txs[task.index].Hash(),
531524
}
532525
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
533526
if err != nil {
@@ -718,10 +711,10 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
718711
if err != nil {
719712
return nil, err
720713
}
721-
txctx := &txTraceContext{
722-
index: int(index),
723-
hash: hash,
724-
block: blockHash,
714+
txctx := &Context{
715+
BlockHash: blockHash,
716+
TxIndex: int(index),
717+
TxHash: hash,
725718
}
726719
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
727720
}
@@ -777,13 +770,13 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
777770
Reexec: config.Reexec,
778771
}
779772
}
780-
return api.traceTx(ctx, msg, new(txTraceContext), vmctx, statedb, traceConfig)
773+
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
781774
}
782775

783776
// traceTx configures a new tracer according to the provided configuration, and
784777
// executes the given message in the provided environment. The return value will
785778
// be tracer dependent.
786-
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTraceContext, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
779+
func (api *API) traceTx(ctx context.Context, message core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
787780
// Assemble the structured logger or the JavaScript tracer
788781
var (
789782
tracer vm.Tracer
@@ -800,7 +793,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac
800793
}
801794
}
802795
// Constuct the JavaScript tracer to execute with
803-
if tracer, err = New(*config.Tracer, txContext); err != nil {
796+
if tracer, err = New(*config.Tracer, txctx); err != nil {
804797
return nil, err
805798
}
806799
// Handle timeouts and RPC cancellations
@@ -823,7 +816,7 @@ func (api *API) traceTx(ctx context.Context, message core.Message, txctx *txTrac
823816
vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Debug: true, Tracer: tracer, NoBaseFee: true})
824817

825818
// Call Prepare to clear out the statedb access list
826-
statedb.Prepare(txctx.hash, txctx.block, txctx.index)
819+
statedb.Prepare(txctx.TxHash, txctx.BlockHash, txctx.TxIndex)
827820

828821
result, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
829822
if err != nil {

eth/tracers/tracer.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,10 +312,18 @@ type Tracer struct {
312312
reason error // Textual reason for the interruption
313313
}
314314

315+
// Context contains some contextual infos for a transaction execution that is not
316+
// available from within the EVM object.
317+
type Context struct {
318+
BlockHash common.Hash // Hash of the block the tx is contained within (zero if dangling tx or call)
319+
TxIndex int // Index of the transaction within a block (zero if dangling tx or call)
320+
TxHash common.Hash // Hash of the transaction being traced (zero if dangling call)
321+
}
322+
315323
// New instantiates a new tracer instance. code specifies a Javascript snippet,
316324
// which must evaluate to an expression returning an object with 'step', 'fault'
317325
// and 'result' functions.
318-
func New(code string, txCtx vm.TxContext) (*Tracer, error) {
326+
func New(code string, ctx *Context) (*Tracer, error) {
319327
// Resolve any tracers by name and assemble the tracer object
320328
if tracer, ok := tracer(code); ok {
321329
code = tracer
@@ -334,8 +342,14 @@ func New(code string, txCtx vm.TxContext) (*Tracer, error) {
334342
depthValue: new(uint),
335343
refundValue: new(uint),
336344
}
337-
tracer.ctx["gasPrice"] = txCtx.GasPrice
345+
if ctx.BlockHash != (common.Hash{}) {
346+
tracer.ctx["blockHash"] = ctx.BlockHash
338347

348+
if ctx.TxHash != (common.Hash{}) {
349+
tracer.ctx["txIndex"] = ctx.TxIndex
350+
tracer.ctx["txHash"] = ctx.TxHash
351+
}
352+
}
339353
// Set up builtins for this environment
340354
tracer.vm.PushGlobalGoFunction("toHex", func(ctx *duktape.Context) int {
341355
ctx.PushString(hexutil.Encode(popSlice(ctx)))
@@ -550,11 +564,13 @@ func (jst *Tracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr
550564
jst.ctx["to"] = to
551565
jst.ctx["input"] = input
552566
jst.ctx["gas"] = gas
567+
jst.ctx["gasPrice"] = env.TxContext.GasPrice
553568
jst.ctx["value"] = value
554569

555570
// Initialize the context
556571
jst.ctx["block"] = env.Context.BlockNumber.Uint64()
557572
jst.dbWrapper.db = env.StateDB
573+
558574
// Compute intrinsic gas
559575
isHomestead := env.ChainConfig().IsHomestead(env.Context.BlockNumber)
560576
isIstanbul := env.ChainConfig().IsIstanbul(env.Context.BlockNumber)

eth/tracers/tracer_test.go

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,14 @@ func runTrace(tracer *Tracer, vmctx *vmContext) (json.RawMessage, error) {
8080
func TestTracer(t *testing.T) {
8181
execTracer := func(code string) ([]byte, string) {
8282
t.Helper()
83-
ctx := &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
84-
tracer, err := New(code, ctx.txCtx)
83+
tracer, err := New(code, new(Context))
8584
if err != nil {
8685
t.Fatal(err)
8786
}
88-
ret, err := runTrace(tracer, ctx)
87+
ret, err := runTrace(tracer, &vmContext{
88+
blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)},
89+
txCtx: vm.TxContext{GasPrice: big.NewInt(100000)},
90+
})
8991
if err != nil {
9092
return nil, err.Error() // Stringify to allow comparison without nil checks
9193
}
@@ -132,33 +134,28 @@ func TestHalt(t *testing.T) {
132134
t.Skip("duktape doesn't support abortion")
133135

134136
timeout := errors.New("stahp")
135-
vmctx := testCtx()
136-
tracer, err := New("{step: function() { while(1); }, result: function() { return null; }}", vmctx.txCtx)
137+
tracer, err := New("{step: function() { while(1); }, result: function() { return null; }}", new(Context))
137138
if err != nil {
138139
t.Fatal(err)
139140
}
140-
141141
go func() {
142142
time.Sleep(1 * time.Second)
143143
tracer.Stop(timeout)
144144
}()
145-
146-
if _, err = runTrace(tracer, vmctx); err.Error() != "stahp in server-side tracer function 'step'" {
145+
if _, err = runTrace(tracer, testCtx()); err.Error() != "stahp in server-side tracer function 'step'" {
147146
t.Errorf("Expected timeout error, got %v", err)
148147
}
149148
}
150149

151150
func TestHaltBetweenSteps(t *testing.T) {
152-
vmctx := testCtx()
153-
tracer, err := New("{step: function() {}, fault: function() {}, result: function() { return null; }}", vmctx.txCtx)
151+
tracer, err := New("{step: function() {}, fault: function() {}, result: function() { return null; }}", new(Context))
154152
if err != nil {
155153
t.Fatal(err)
156154
}
157155
env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Debug: true, Tracer: tracer})
158156
scope := &vm.ScopeContext{
159157
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
160158
}
161-
162159
tracer.CaptureState(env, 0, 0, 0, 0, scope, nil, 0, nil)
163160
timeout := errors.New("stahp")
164161
tracer.Stop(timeout)
@@ -182,12 +179,14 @@ func TestNoStepExec(t *testing.T) {
182179
}
183180
execTracer := func(code string) []byte {
184181
t.Helper()
185-
ctx := &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
186-
tracer, err := New(code, ctx.txCtx)
182+
tracer, err := New(code, new(Context))
187183
if err != nil {
188184
t.Fatal(err)
189185
}
190-
ret, err := runEmptyTrace(tracer, ctx)
186+
ret, err := runEmptyTrace(tracer, &vmContext{
187+
blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)},
188+
txCtx: vm.TxContext{GasPrice: big.NewInt(100000)},
189+
})
191190
if err != nil {
192191
t.Fatal(err)
193192
}

eth/tracers/tracers_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func TestPrestateTracerCreate2(t *testing.T) {
173173
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false)
174174

175175
// Create the tracer, the EVM environment and run it
176-
tracer, err := New("prestateTracer", txContext)
176+
tracer, err := New("prestateTracer", new(Context))
177177
if err != nil {
178178
t.Fatalf("failed to create call tracer: %v", err)
179179
}
@@ -248,7 +248,7 @@ func TestCallTracer(t *testing.T) {
248248
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
249249

250250
// Create the tracer, the EVM environment and run it
251-
tracer, err := New("callTracer", txContext)
251+
tracer, err := New("callTracer", new(Context))
252252
if err != nil {
253253
t.Fatalf("failed to create call tracer: %v", err)
254254
}

0 commit comments

Comments
 (0)