eth/tracers: fix state hooks in API (#30830)
When a tx/block was being traced through the API the state hooks weren't being called as they should. This is due to #30745 moving the hooked statedb one level up in the state processor. This PR fixes that. --------- Co-authored-by: Martin HS <martin@swende.se> Co-authored-by: Gary Rong <garyrong0905@gmail.com>
This commit is contained in:
parent
a793bc7f5f
commit
ce8cec007c
|
@ -1007,8 +1007,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The actual TxContext will be created as part of ApplyTransactionWithEVM.
|
tracingStateDB := state.NewHookedState(statedb, tracer.Hooks)
|
||||||
evm := vm.NewEVM(vmctx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
|
evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
|
||||||
|
|
||||||
// Define a meaningful timeout of a single transaction trace
|
// Define a meaningful timeout of a single transaction trace
|
||||||
if config.Timeout != nil {
|
if config.Timeout != nil {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
@ -185,6 +186,94 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
|
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stateTracer struct {
|
||||||
|
Balance map[common.Address]*hexutil.Big
|
||||||
|
Nonce map[common.Address]hexutil.Uint64
|
||||||
|
Storage map[common.Address]map[common.Hash]common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStateTracer(ctx *Context, cfg json.RawMessage, chainCfg *params.ChainConfig) (*Tracer, error) {
|
||||||
|
t := &stateTracer{
|
||||||
|
Balance: make(map[common.Address]*hexutil.Big),
|
||||||
|
Nonce: make(map[common.Address]hexutil.Uint64),
|
||||||
|
Storage: make(map[common.Address]map[common.Hash]common.Hash),
|
||||||
|
}
|
||||||
|
return &Tracer{
|
||||||
|
GetResult: func() (json.RawMessage, error) {
|
||||||
|
return json.Marshal(t)
|
||||||
|
},
|
||||||
|
Hooks: &tracing.Hooks{
|
||||||
|
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
|
||||||
|
t.Balance[addr] = (*hexutil.Big)(new)
|
||||||
|
},
|
||||||
|
OnNonceChange: func(addr common.Address, prev, new uint64) {
|
||||||
|
t.Nonce[addr] = hexutil.Uint64(new)
|
||||||
|
},
|
||||||
|
OnStorageChange: func(addr common.Address, slot common.Hash, prev, new common.Hash) {
|
||||||
|
if t.Storage[addr] == nil {
|
||||||
|
t.Storage[addr] = make(map[common.Hash]common.Hash)
|
||||||
|
}
|
||||||
|
t.Storage[addr][slot] = new
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateHooks(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Initialize test accounts
|
||||||
|
var (
|
||||||
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
from = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
to = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
|
||||||
|
genesis = &core.Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: types.GenesisAlloc{
|
||||||
|
from: {Balance: big.NewInt(params.Ether)},
|
||||||
|
to: {
|
||||||
|
Code: []byte{
|
||||||
|
byte(vm.PUSH1), 0x2a, // stack: [42]
|
||||||
|
byte(vm.PUSH1), 0x0, // stack: [0, 42]
|
||||||
|
byte(vm.SSTORE), // stack: []
|
||||||
|
byte(vm.STOP),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
genBlocks = 2
|
||||||
|
signer = types.HomesteadSigner{}
|
||||||
|
nonce = uint64(0)
|
||||||
|
backend = newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
|
||||||
|
// Transfer from account[0] to account[1]
|
||||||
|
// value: 1000 wei
|
||||||
|
// fee: 0 wei
|
||||||
|
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, key)
|
||||||
|
b.AddTx(tx)
|
||||||
|
nonce++
|
||||||
|
})
|
||||||
|
)
|
||||||
|
defer backend.teardown()
|
||||||
|
DefaultDirectory.Register("stateTracer", newStateTracer, false)
|
||||||
|
api := NewAPI(backend)
|
||||||
|
tracer := "stateTracer"
|
||||||
|
res, err := api.TraceCall(context.Background(), ethapi.TransactionArgs{From: &from, To: &to, Value: (*hexutil.Big)(big.NewInt(1000))}, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), &TraceCallConfig{TraceConfig: TraceConfig{Tracer: &tracer}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to trace call: %v", err)
|
||||||
|
}
|
||||||
|
expected := `{"Balance":{"0x00000000000000000000000000000000deadbeef":"0x3e8","0x71562b71999873db5b286df957af199ec94617f7":"0xde0975924ed6f90"},"Nonce":{"0x71562b71999873db5b286df957af199ec94617f7":"0x3"},"Storage":{"0x00000000000000000000000000000000deadbeef":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x000000000000000000000000000000000000000000000000000000000000002a"}}}`
|
||||||
|
if expected != fmt.Sprintf("%s", res) {
|
||||||
|
t.Fatalf("unexpected trace result: have %s want %s", res, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTraceCall(t *testing.T) {
|
func TestTraceCall(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue