eth/tracers: tx-level state in debug_traceCall (#28460)
This commit is contained in:
parent
dd0d0a2522
commit
5fb8ebc9ec
@ -164,6 +164,7 @@ type TraceCallConfig struct {
|
|||||||
TraceConfig
|
TraceConfig
|
||||||
StateOverrides *ethapi.StateOverride
|
StateOverrides *ethapi.StateOverride
|
||||||
BlockOverrides *ethapi.BlockOverrides
|
BlockOverrides *ethapi.BlockOverrides
|
||||||
|
TxIndex *hexutil.Uint
|
||||||
}
|
}
|
||||||
|
|
||||||
// StdTraceConfig holds extra parameters to standard-json trace functions.
|
// StdTraceConfig holds extra parameters to standard-json trace functions.
|
||||||
@ -863,11 +864,17 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||||||
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
||||||
// created during the execution of EVM if the given transaction was added on
|
// created during the execution of EVM if the given transaction was added on
|
||||||
// top of the provided block and returns them as a JSON object.
|
// top of the provided block and returns them as a JSON object.
|
||||||
|
// If no transaction index is specified, the trace will be conducted on the state
|
||||||
|
// after executing the specified block. However, if a transaction index is provided,
|
||||||
|
// the trace will be conducted on the state after executing the specified transaction
|
||||||
|
// within the specified block.
|
||||||
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
|
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
|
||||||
// Try to retrieve the specified block
|
// Try to retrieve the specified block
|
||||||
var (
|
var (
|
||||||
err error
|
err error
|
||||||
block *types.Block
|
block *types.Block
|
||||||
|
statedb *state.StateDB
|
||||||
|
release StateReleaseFunc
|
||||||
)
|
)
|
||||||
if hash, ok := blockNrOrHash.Hash(); ok {
|
if hash, ok := blockNrOrHash.Hash(); ok {
|
||||||
block, err = api.blockByHash(ctx, hash)
|
block, err = api.blockByHash(ctx, hash)
|
||||||
@ -892,7 +899,12 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||||||
if config != nil && config.Reexec != nil {
|
if config != nil && config.Reexec != nil {
|
||||||
reexec = *config.Reexec
|
reexec = *config.Reexec
|
||||||
}
|
}
|
||||||
statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
|
|
||||||
|
if config != nil && config.TxIndex != nil {
|
||||||
|
_, _, statedb, release, err = api.backend.StateAtTransaction(ctx, block, int(*config.TxIndex), reexec)
|
||||||
|
} else {
|
||||||
|
statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -200,13 +200,51 @@ func TestTraceCall(t *testing.T) {
|
|||||||
}
|
}
|
||||||
genBlocks := 10
|
genBlocks := 10
|
||||||
signer := types.HomesteadSigner{}
|
signer := types.HomesteadSigner{}
|
||||||
|
nonce := uint64(0)
|
||||||
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
|
backend := newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
|
||||||
// Transfer from account[0] to account[1]
|
// Transfer from account[0] to account[1]
|
||||||
// value: 1000 wei
|
// value: 1000 wei
|
||||||
// fee: 0 wei
|
// fee: 0 wei
|
||||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &accounts[1].addr,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, accounts[0].key)
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
|
nonce++
|
||||||
|
|
||||||
|
if i == genBlocks-2 {
|
||||||
|
// Transfer from account[0] to account[2]
|
||||||
|
tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &accounts[2].addr,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, accounts[0].key)
|
||||||
|
b.AddTx(tx)
|
||||||
|
nonce++
|
||||||
|
|
||||||
|
// Transfer from account[0] to account[1] again
|
||||||
|
tx, _ = types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &accounts[1].addr,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, accounts[0].key)
|
||||||
|
b.AddTx(tx)
|
||||||
|
nonce++
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
uintPtr := func(i int) *hexutil.Uint { x := hexutil.Uint(i); return &x }
|
||||||
|
|
||||||
defer backend.teardown()
|
defer backend.teardown()
|
||||||
api := NewAPI(backend)
|
api := NewAPI(backend)
|
||||||
var testSuite = []struct {
|
var testSuite = []struct {
|
||||||
@ -240,6 +278,51 @@ func TestTraceCall(t *testing.T) {
|
|||||||
expectErr: nil,
|
expectErr: nil,
|
||||||
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||||
},
|
},
|
||||||
|
// Upon the last state, default to the post block's state
|
||||||
|
{
|
||||||
|
blockNumber: rpc.BlockNumber(genBlocks - 1),
|
||||||
|
call: ethapi.TransactionArgs{
|
||||||
|
From: &accounts[2].addr,
|
||||||
|
To: &accounts[0].addr,
|
||||||
|
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
|
||||||
|
},
|
||||||
|
config: nil,
|
||||||
|
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||||
|
},
|
||||||
|
// Before the first transaction, should be failed
|
||||||
|
{
|
||||||
|
blockNumber: rpc.BlockNumber(genBlocks - 1),
|
||||||
|
call: ethapi.TransactionArgs{
|
||||||
|
From: &accounts[2].addr,
|
||||||
|
To: &accounts[0].addr,
|
||||||
|
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
|
||||||
|
},
|
||||||
|
config: &TraceCallConfig{TxIndex: uintPtr(0)},
|
||||||
|
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
|
||||||
|
},
|
||||||
|
// Before the target transaction, should be failed
|
||||||
|
{
|
||||||
|
blockNumber: rpc.BlockNumber(genBlocks - 1),
|
||||||
|
call: ethapi.TransactionArgs{
|
||||||
|
From: &accounts[2].addr,
|
||||||
|
To: &accounts[0].addr,
|
||||||
|
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
|
||||||
|
},
|
||||||
|
config: &TraceCallConfig{TxIndex: uintPtr(1)},
|
||||||
|
expectErr: fmt.Errorf("tracing failed: insufficient funds for gas * price + value: address %s have 1000000000000000000 want 1000000000000000100", accounts[2].addr),
|
||||||
|
},
|
||||||
|
// After the target transaction, should be succeed
|
||||||
|
{
|
||||||
|
blockNumber: rpc.BlockNumber(genBlocks - 1),
|
||||||
|
call: ethapi.TransactionArgs{
|
||||||
|
From: &accounts[2].addr,
|
||||||
|
To: &accounts[0].addr,
|
||||||
|
Value: (*hexutil.Big)(new(big.Int).Add(big.NewInt(params.Ether), big.NewInt(100))),
|
||||||
|
},
|
||||||
|
config: &TraceCallConfig{TxIndex: uintPtr(2)},
|
||||||
|
expectErr: nil,
|
||||||
|
expect: `{"gas":21000,"failed":false,"returnValue":"","structLogs":[]}`,
|
||||||
|
},
|
||||||
// Standard JSON trace upon the non-existent block, error expects
|
// Standard JSON trace upon the non-existent block, error expects
|
||||||
{
|
{
|
||||||
blockNumber: rpc.BlockNumber(genBlocks + 1),
|
blockNumber: rpc.BlockNumber(genBlocks + 1),
|
||||||
@ -297,8 +380,8 @@ func TestTraceCall(t *testing.T) {
|
|||||||
t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr)
|
t.Errorf("test %d: expect error %v, got nothing", i, testspec.expectErr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(err, testspec.expectErr) {
|
if !reflect.DeepEqual(err.Error(), testspec.expectErr.Error()) {
|
||||||
t.Errorf("test %d: error mismatch, want %v, git %v", i, testspec.expectErr, err)
|
t.Errorf("test %d: error mismatch, want '%v', got '%v'", i, testspec.expectErr, err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -338,7 +421,14 @@ func TestTraceTransaction(t *testing.T) {
|
|||||||
// Transfer from account[0] to account[1]
|
// Transfer from account[0] to account[1]
|
||||||
// value: 1000 wei
|
// value: 1000 wei
|
||||||
// fee: 0 wei
|
// fee: 0 wei
|
||||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: uint64(i),
|
||||||
|
To: &accounts[1].addr,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, accounts[0].key)
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
target = tx.Hash()
|
target = tx.Hash()
|
||||||
})
|
})
|
||||||
@ -388,7 +478,14 @@ func TestTraceBlock(t *testing.T) {
|
|||||||
// Transfer from account[0] to account[1]
|
// Transfer from account[0] to account[1]
|
||||||
// value: 1000 wei
|
// value: 1000 wei
|
||||||
// fee: 0 wei
|
// fee: 0 wei
|
||||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: uint64(i),
|
||||||
|
To: &accounts[1].addr,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, accounts[0].key)
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
txHash = tx.Hash()
|
txHash = tx.Hash()
|
||||||
})
|
})
|
||||||
@ -478,7 +575,14 @@ func TestTracingWithOverrides(t *testing.T) {
|
|||||||
// Transfer from account[0] to account[1]
|
// Transfer from account[0] to account[1]
|
||||||
// value: 1000 wei
|
// value: 1000 wei
|
||||||
// fee: 0 wei
|
// fee: 0 wei
|
||||||
tx, _ := types.SignTx(types.NewTransaction(uint64(i), accounts[1].addr, big.NewInt(1000), params.TxGas, b.BaseFee(), nil), signer, accounts[0].key)
|
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: uint64(i),
|
||||||
|
To: &accounts[1].addr,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, accounts[0].key)
|
||||||
b.AddTx(tx)
|
b.AddTx(tx)
|
||||||
})
|
})
|
||||||
defer backend.chain.Stop()
|
defer backend.chain.Stop()
|
||||||
|
Loading…
Reference in New Issue
Block a user