Skip to content

Commit 5fb8ebc

Browse files
authored
eth/tracers: tx-level state in debug_traceCall (#28460)
1 parent dd0d0a2 commit 5fb8ebc

File tree

2 files changed

+125
-9
lines changed

2 files changed

+125
-9
lines changed

eth/tracers/api.go

+15-3
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ type TraceCallConfig struct {
164164
TraceConfig
165165
StateOverrides *ethapi.StateOverride
166166
BlockOverrides *ethapi.BlockOverrides
167+
TxIndex *hexutil.Uint
167168
}
168169

169170
// StdTraceConfig holds extra parameters to standard-json trace functions.
@@ -863,11 +864,17 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
863864
// TraceCall lets you trace a given eth_call. It collects the structured logs
864865
// created during the execution of EVM if the given transaction was added on
865866
// top of the provided block and returns them as a JSON object.
867+
// If no transaction index is specified, the trace will be conducted on the state
868+
// after executing the specified block. However, if a transaction index is provided,
869+
// the trace will be conducted on the state after executing the specified transaction
870+
// within the specified block.
866871
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
867872
// Try to retrieve the specified block
868873
var (
869-
err error
870-
block *types.Block
874+
err error
875+
block *types.Block
876+
statedb *state.StateDB
877+
release StateReleaseFunc
871878
)
872879
if hash, ok := blockNrOrHash.Hash(); ok {
873880
block, err = api.blockByHash(ctx, hash)
@@ -892,7 +899,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
892899
if config != nil && config.Reexec != nil {
893900
reexec = *config.Reexec
894901
}
895-
statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
902+
903+
if config != nil && config.TxIndex != nil {
904+
_, _, statedb, release, err = api.backend.StateAtTransaction(ctx, block, int(*config.TxIndex), reexec)
905+
} else {
906+
statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
907+
}
896908
if err != nil {
897909
return nil, err
898910
}

eth/tracers/api_test.go

+110-6
Original file line numberDiff line numberDiff line change
@@ -200,13 +200,51 @@ func TestTraceCall(t *testing.T) {
200200
}
201201
genBlocks := 10
202202
signer := types.HomesteadSigner{}
203+
nonce := uint64(0)
203204
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
204205
// Transfer from account[0] to account[1]
205206
// value: 1000 wei
206207
// fee: 0 wei
207-
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
208+
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
209+
Nonce: nonce,
210+
To: &accounts[1].addr,
211+
Value: big.NewInt(1000),
212+
Gas: params.TxGas,
213+
GasPrice: b.BaseFee(),
214+
Data: nil}),
215+
signer, accounts[0].key)
208216
b.AddTx(tx)
217+
nonce++
218+
219+
if i == genBlocks-2 {
220+
// Transfer from account[0] to account[2]
221+
tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{
222+
Nonce: nonce,
223+
To: &accounts[2].addr,
224+
Value: big.NewInt(1000),
225+
Gas: params.TxGas,
226+
GasPrice: b.BaseFee(),
227+
Data: nil}),
228+
signer, accounts[0].key)
229+
b.AddTx(tx)
230+
nonce++
231+
232+
// Transfer from account[0] to account[1] again
233+
tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{
234+
Nonce: nonce,
235+
To: &accounts[1].addr,
236+
Value: big.NewInt(1000),
237+
Gas: params.TxGas,
238+
GasPrice: b.BaseFee(),
239+
Data: nil}),
240+
signer, accounts[0].key)
241+
b.AddTx(tx)
242+
nonce++
243+
}
209244
})
245+
246+
uintPtr := func(i int) *hexutil.Uint { x := hexutil.Uint(i); return &x }
247+
210248
defer backend.teardown()
211249
api := NewAPI(backend)
212250
var testSuite = []struct {
@@ -240,6 +278,51 @@ func TestTraceCall(t *testing.T) {
240278
expectErr: nil,
241279
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
242280
},
281+
// Upon the last state, default to the post block's state
282+
{
283+
blockNumber: rpc.BlockNumber(genBlocks - 1),
284+
call: ethapi.TransactionArgs{
285+
From: &accounts[2].addr,
286+
To: &accounts[0].addr,
287+
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
288+
},
289+
config: nil,
290+
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
291+
},
292+
// Before the first transaction, should be failed
293+
{
294+
blockNumber: rpc.BlockNumber(genBlocks - 1),
295+
call: ethapi.TransactionArgs{
296+
From: &accounts[2].addr,
297+
To: &accounts[0].addr,
298+
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
299+
},
300+
config: &TraceCallConfig{TxIndex: uintPtr(0)},
301+
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
302+
},
303+
// Before the target transaction, should be failed
304+
{
305+
blockNumber: rpc.BlockNumber(genBlocks - 1),
306+
call: ethapi.TransactionArgs{
307+
From: &accounts[2].addr,
308+
To: &accounts[0].addr,
309+
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
310+
},
311+
config: &TraceCallConfig{TxIndex: uintPtr(1)},
312+
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
313+
},
314+
// After the target transaction, should be succeed
315+
{
316+
blockNumber: rpc.BlockNumber(genBlocks - 1),
317+
call: ethapi.TransactionArgs{
318+
From: &accounts[2].addr,
319+
To: &accounts[0].addr,
320+
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
321+
},
322+
config: &TraceCallConfig{TxIndex: uintPtr(2)},
323+
expectErr: nil,
324+
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
325+
},
243326
// Standard JSON trace upon the non-existent block, error expects
244327
{
245328
blockNumber: rpc.BlockNumber(genBlocks + 1),
@@ -297,8 +380,8 @@ func TestTraceCall(t *testing.T) {
297380
t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr)
298381
continue
299382
}
300-
if !reflect.DeepEqual(err, testspec.expectErr) {
301-
t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err)
383+
if !reflect.DeepEqual(err.Error(), testspec.expectErr.Error()) {
384+
t.Errorf("test %d: error mismatch, want '%v', got '%v'", i, testspec.expectErr, err)
302385
}
303386
} else {
304387
if err != nil {
@@ -338,7 +421,14 @@ func TestTraceTransaction(t *testing.T) {
338421
// Transfer from account[0] to account[1]
339422
// value: 1000 wei
340423
// fee: 0 wei
341-
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
424+
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
425+
Nonce: uint64(i),
426+
To: &accounts[1].addr,
427+
Value: big.NewInt(1000),
428+
Gas: params.TxGas,
429+
GasPrice: b.BaseFee(),
430+
Data: nil}),
431+
signer, accounts[0].key)
342432
b.AddTx(tx)
343433
target = tx.Hash()
344434
})
@@ -388,7 +478,14 @@ func TestTraceBlock(t *testing.T) {
388478
// Transfer from account[0] to account[1]
389479
// value: 1000 wei
390480
// fee: 0 wei
391-
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
481+
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
482+
Nonce: uint64(i),
483+
To: &accounts[1].addr,
484+
Value: big.NewInt(1000),
485+
Gas: params.TxGas,
486+
GasPrice: b.BaseFee(),
487+
Data: nil}),
488+
signer, accounts[0].key)
392489
b.AddTx(tx)
393490
txHash = tx.Hash()
394491
})
@@ -478,7 +575,14 @@ func TestTracingWithOverrides(t *testing.T) {
478575
// Transfer from account[0] to account[1]
479576
// value: 1000 wei
480577
// fee: 0 wei
481-
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
578+
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
579+
Nonce: uint64(i),
580+
To: &accounts[1].addr,
581+
Value: big.NewInt(1000),
582+
Gas: params.TxGas,
583+
GasPrice: b.BaseFee(),
584+
Data: nil}),
585+
signer, accounts[0].key)
482586
b.AddTx(tx)
483587
})
484588
defer backend.chain.Stop()

0 commit comments

Comments
 (0)