Upgrade TxStart and TxEnd hooks
This commit is contained in:
parent
a7de17ed21
commit
378781654f
|
@ -183,6 +183,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
)
|
||||
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
|
||||
|
||||
tracer.CaptureTxStart(tx)
|
||||
// (ret []byte, usedGas uint64, failed bool, err error)
|
||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||
if err != nil {
|
||||
|
@ -231,6 +232,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
|||
//receipt.BlockNumber
|
||||
receipt.TransactionIndex = uint(txIndex)
|
||||
receipts = append(receipts, receipt)
|
||||
tracer.CaptureTxEnd(receipt)
|
||||
}
|
||||
|
||||
txIndex++
|
||||
|
|
|
@ -87,7 +87,13 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
|||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
if vmenv.Config.Tracer != nil {
|
||||
vmenv.Config.Tracer.CaptureTxStart(tx)
|
||||
}
|
||||
receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
|
||||
if vmenv.Config.Tracer != nil {
|
||||
vmenv.Config.Tracer.CaptureTxEnd(receipt)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
|
||||
}
|
||||
|
|
|
@ -326,13 +326,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if tracer := st.evm.Config.Tracer; tracer != nil {
|
||||
tracer.CaptureTxStart(st.initialGas)
|
||||
defer func() {
|
||||
tracer.CaptureTxEnd(st.gasRemaining)
|
||||
}()
|
||||
}
|
||||
|
||||
var (
|
||||
msg = st.msg
|
||||
sender = vm.AccountRef(msg.From)
|
||||
|
|
|
@ -20,6 +20,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// EVMLogger is used to collect execution traces from an EVM transaction
|
||||
|
@ -29,8 +30,8 @@ import (
|
|||
// if you need to retain them beyond the current call.
|
||||
type EVMLogger interface {
|
||||
// Transaction level
|
||||
CaptureTxStart(gasLimit uint64)
|
||||
CaptureTxEnd(restGas uint64)
|
||||
CaptureTxStart(tx *types.Transaction)
|
||||
CaptureTxEnd(receipt *types.Receipt)
|
||||
// Top call frame
|
||||
CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int)
|
||||
CaptureEnd(output []byte, gasUsed uint64, err error)
|
||||
|
|
|
@ -414,6 +414,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
|||
return b.eth.StateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
|
||||
}
|
||||
|
||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ func (eth *Ethereum) StateAtBlock(ctx context.Context, block *types.Block, reexe
|
|||
}
|
||||
|
||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
||||
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
// Short circuit if it's genesis block.
|
||||
if block.NumberU64() == 0 {
|
||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||
|
@ -216,7 +216,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
|||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||
if idx == txIndex {
|
||||
return msg, context, statedb, release, nil
|
||||
return tx, context, statedb, release, nil
|
||||
}
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
@ -87,7 +88,7 @@ type Backend interface {
|
|||
Engine() consensus.Engine
|
||||
ChainDb() ethdb.Database
|
||||
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
|
||||
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
||||
StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
|
||||
}
|
||||
|
||||
// API is the collection of tracing APIs exposed over the private debugging endpoint.
|
||||
|
@ -277,7 +278,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
|||
TxIndex: i,
|
||||
TxHash: tx.Hash(),
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
|
||||
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config)
|
||||
if err != nil {
|
||||
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
|
||||
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
|
||||
|
@ -612,7 +613,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
|||
TxIndex: i,
|
||||
TxHash: tx.Hash(),
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config)
|
||||
res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -655,7 +656,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
|
|||
TxIndex: task.index,
|
||||
TxHash: txs[task.index].Hash(),
|
||||
}
|
||||
res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
|
||||
res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config)
|
||||
if err != nil {
|
||||
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
|
||||
continue
|
||||
|
@ -789,7 +790,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
|||
// Execute the transaction and flush any traces to disk
|
||||
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
|
||||
statedb.SetTxContext(tx.Hash(), i)
|
||||
_, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||
vmConf.Tracer.CaptureTxStart(tx)
|
||||
vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||
vmConf.Tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas})
|
||||
if writer != nil {
|
||||
writer.Flush()
|
||||
}
|
||||
|
@ -846,11 +849,15 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
|
||||
tx, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer release()
|
||||
msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
txctx := &Context{
|
||||
BlockHash: blockHash,
|
||||
|
@ -858,7 +865,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
|
|||
TxIndex: int(index),
|
||||
TxHash: hash,
|
||||
}
|
||||
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
|
||||
return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config)
|
||||
}
|
||||
|
||||
// TraceCall lets you trace a given eth_call. It collects the structured logs
|
||||
|
@ -912,18 +919,21 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tx, err := argsToTransaction(api.backend, &args, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var traceConfig *TraceConfig
|
||||
if config != nil {
|
||||
traceConfig = &config.TraceConfig
|
||||
}
|
||||
return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
|
||||
return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
|
||||
}
|
||||
|
||||
// traceTx configures a new tracer according to the provided configuration, and
|
||||
// executes the given message in the provided environment. The return value will
|
||||
// be tracer dependent.
|
||||
func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||
func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
|
||||
var (
|
||||
tracer Tracer
|
||||
err error
|
||||
|
@ -962,9 +972,13 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
|
|||
|
||||
// Call Prepare to clear out the statedb access list
|
||||
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
|
||||
if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
|
||||
tracer.CaptureTxStart(tx)
|
||||
res, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("tracing failed: %w", err)
|
||||
}
|
||||
r := &types.Receipt{GasUsed: res.UsedGas}
|
||||
tracer.CaptureTxEnd(r)
|
||||
return tracer.GetResult()
|
||||
}
|
||||
|
||||
|
@ -1023,3 +1037,54 @@ func overrideConfig(original *params.ChainConfig, override *params.ChainConfig)
|
|||
|
||||
return copy, canon
|
||||
}
|
||||
|
||||
// argsToTransaction produces a Transaction object given call arguments.
|
||||
// The `msg` field must be converted from the same arguments.
|
||||
func argsToTransaction(b Backend, args *ethapi.TransactionArgs, msg *core.Message) (*types.Transaction, error) {
|
||||
chainID := b.ChainConfig().ChainID
|
||||
if args.ChainID != nil {
|
||||
if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 {
|
||||
return nil, fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID)
|
||||
}
|
||||
}
|
||||
var data types.TxData
|
||||
switch {
|
||||
case args.MaxFeePerGas != nil:
|
||||
al := types.AccessList{}
|
||||
if args.AccessList != nil {
|
||||
al = *args.AccessList
|
||||
}
|
||||
data = &types.DynamicFeeTx{
|
||||
To: args.To,
|
||||
ChainID: chainID,
|
||||
Nonce: msg.Nonce,
|
||||
Gas: msg.GasLimit,
|
||||
GasFeeCap: msg.GasFeeCap,
|
||||
GasTipCap: msg.GasTipCap,
|
||||
Value: msg.Value,
|
||||
Data: msg.Data,
|
||||
AccessList: al,
|
||||
}
|
||||
case args.AccessList != nil:
|
||||
data = &types.AccessListTx{
|
||||
To: args.To,
|
||||
ChainID: chainID,
|
||||
Nonce: msg.Nonce,
|
||||
Gas: msg.GasLimit,
|
||||
GasPrice: msg.GasPrice,
|
||||
Value: msg.Value,
|
||||
Data: msg.Data,
|
||||
AccessList: *args.AccessList,
|
||||
}
|
||||
default:
|
||||
data = &types.LegacyTx{
|
||||
To: args.To,
|
||||
Nonce: msg.Nonce,
|
||||
Gas: msg.GasLimit,
|
||||
GasPrice: msg.GasPrice,
|
||||
Value: msg.Value,
|
||||
Data: msg.Data,
|
||||
}
|
||||
}
|
||||
return types.NewTx(data), nil
|
||||
}
|
||||
|
|
|
@ -156,7 +156,7 @@ func (b *testBackend) StateAtBlock(ctx context.Context, block *types.Block, reex
|
|||
return statedb, release, nil
|
||||
}
|
||||
|
||||
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
||||
func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error) {
|
||||
parent := b.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||
if parent == nil {
|
||||
return nil, vm.BlockContext{}, nil, nil, errBlockNotFound
|
||||
|
@ -175,7 +175,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
|||
txContext := core.NewEVMTxContext(msg)
|
||||
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
|
||||
if idx == txIndex {
|
||||
return msg, context, statedb, release, nil
|
||||
return tx, context, statedb, release, nil
|
||||
}
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
|
||||
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||
|
|
|
@ -18,6 +18,7 @@ package tracetest
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -31,6 +32,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
|
@ -148,10 +150,12 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
tracer.CaptureTxStart(tx)
|
||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to execute transaction: %v", err)
|
||||
}
|
||||
tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas})
|
||||
// Retrieve the trace result and compare against the expected.
|
||||
res, err := tracer.GetResult()
|
||||
if err != nil {
|
||||
|
@ -261,8 +265,12 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
|||
|
||||
func TestInternals(t *testing.T) {
|
||||
var (
|
||||
config = params.AllEthashProtocolChanges
|
||||
to = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
|
||||
origin = common.HexToAddress("0x00000000000000000000000000000000feed")
|
||||
originHex = "0x71562b71999873db5b286df957af199ec94617f7"
|
||||
origin = common.HexToAddress(originHex)
|
||||
signer = types.LatestSigner(config)
|
||||
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||
txContext = vm.TxContext{
|
||||
Origin: origin,
|
||||
GasPrice: big.NewInt(1),
|
||||
|
@ -302,13 +310,13 @@ func TestInternals(t *testing.T) {
|
|||
byte(vm.CALL),
|
||||
},
|
||||
tracer: mkTracer("callTracer", nil),
|
||||
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`,
|
||||
want: fmt.Sprintf(`{"from":"%s","gas":"0xc350","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0x6cbf","gasUsed":"0x0","to":"0x00000000000000000000000000000000000000ff","input":"0x","value":"0x0","type":"CALL"}],"value":"0x0","type":"CALL"}`, originHex),
|
||||
},
|
||||
{
|
||||
name: "Stack depletion in LOG0",
|
||||
code: []byte{byte(vm.LOG3)},
|
||||
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
|
||||
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`,
|
||||
want: fmt.Sprintf(`{"from":"%s","gas":"0xc350","gasUsed":"0xc350","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, originHex),
|
||||
},
|
||||
{
|
||||
name: "Mem expansion in LOG0",
|
||||
|
@ -321,7 +329,7 @@ func TestInternals(t *testing.T) {
|
|||
byte(vm.LOG0),
|
||||
},
|
||||
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
|
||||
want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`,
|
||||
want: fmt.Sprintf(`{"from":"%s","gas":"0xc350","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}],"value":"0x0","type":"CALL"}`, originHex),
|
||||
},
|
||||
{
|
||||
// Leads to OOM on the prestate tracer
|
||||
|
@ -340,7 +348,7 @@ func TestInternals(t *testing.T) {
|
|||
byte(vm.LOG0),
|
||||
},
|
||||
tracer: mkTracer("prestateTracer", json.RawMessage(`{ "withLog": true }`)),
|
||||
want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52640350"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`,
|
||||
want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52640350"}}`, originHex),
|
||||
},
|
||||
} {
|
||||
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(),
|
||||
|
@ -353,20 +361,25 @@ func TestInternals(t *testing.T) {
|
|||
},
|
||||
}, false)
|
||||
evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
|
||||
msg := &core.Message{
|
||||
To: &to,
|
||||
From: origin,
|
||||
Value: big.NewInt(0),
|
||||
GasLimit: 50000,
|
||||
GasPrice: big.NewInt(0),
|
||||
GasFeeCap: big.NewInt(0),
|
||||
GasTipCap: big.NewInt(0),
|
||||
SkipAccountChecks: false,
|
||||
tx, err := types.SignNewTx(key, signer, &types.LegacyTx{
|
||||
To: &to,
|
||||
Value: big.NewInt(0),
|
||||
Gas: 50000,
|
||||
GasPrice: big.NewInt(0),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err)
|
||||
}
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||
if _, err := st.TransitionDb(); err != nil {
|
||||
msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0))
|
||||
if err != nil {
|
||||
t.Fatalf("test %v: failed to create message: %v", tc.name, err)
|
||||
}
|
||||
tc.tracer.CaptureTxStart(tx)
|
||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err)
|
||||
}
|
||||
tc.tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas})
|
||||
// Retrieve the trace result and compare against the expected
|
||||
res, err := tc.tracer.GetResult()
|
||||
if err != nil {
|
||||
|
|
|
@ -113,11 +113,12 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
|||
if err != nil {
|
||||
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
|
||||
if _, err = st.TransitionDb(); err != nil {
|
||||
tracer.CaptureTxStart(tx)
|
||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute transaction: %v", err)
|
||||
}
|
||||
tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas})
|
||||
|
||||
// Retrieve the trace result and compare against the etalon
|
||||
res, err := tracer.GetResult()
|
||||
|
|
|
@ -119,10 +119,12 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||
}
|
||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if _, err = st.TransitionDb(); err != nil {
|
||||
tracer.CaptureTxStart(tx)
|
||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||
if err != nil {
|
||||
t.Fatalf("failed to execute transaction: %v", err)
|
||||
}
|
||||
tracer.CaptureTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas})
|
||||
// Retrieve the trace result and compare against the expected
|
||||
res, err := tracer.GetResult()
|
||||
if err != nil {
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
|
@ -214,14 +215,14 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer
|
|||
|
||||
// CaptureTxStart implements the Tracer interface and is invoked at the beginning of
|
||||
// transaction processing.
|
||||
func (t *jsTracer) CaptureTxStart(gasLimit uint64) {
|
||||
t.gasLimit = gasLimit
|
||||
func (t *jsTracer) CaptureTxStart(tx *types.Transaction) {
|
||||
t.gasLimit = tx.Gas()
|
||||
}
|
||||
|
||||
// CaptureTxEnd implements the Tracer interface and is invoked at the end of
|
||||
// transaction processing.
|
||||
func (t *jsTracer) CaptureTxEnd(restGas uint64) {
|
||||
t.ctx["gasUsed"] = t.vm.ToValue(t.gasLimit - restGas)
|
||||
func (t *jsTracer) CaptureTxEnd(receipt *types.Receipt) {
|
||||
t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed)
|
||||
}
|
||||
|
||||
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
||||
|
|
|
@ -26,6 +26,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/state"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
"github.com/ethereum/go-ethereum/params"
|
||||
|
@ -73,12 +74,12 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
|
|||
contract.Code = contractCode
|
||||
}
|
||||
|
||||
tracer.CaptureTxStart(gasLimit)
|
||||
tracer.CaptureTxStart(types.NewTx(&types.LegacyTx{Gas: gasLimit}))
|
||||
tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
|
||||
ret, err := env.Interpreter().Run(contract, []byte{}, false)
|
||||
tracer.CaptureEnd(ret, startGas-contract.Gas, err)
|
||||
// Rest gas assumes no refund
|
||||
tracer.CaptureTxEnd(contract.Gas)
|
||||
tracer.CaptureTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -172,9 +172,9 @@ func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com
|
|||
|
||||
func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {}
|
||||
|
||||
func (*AccessListTracer) CaptureTxStart(gasLimit uint64) {}
|
||||
func (*AccessListTracer) CaptureTxStart(tx *types.Transaction) {}
|
||||
|
||||
func (*AccessListTracer) CaptureTxEnd(restGas uint64) {}
|
||||
func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt) {}
|
||||
|
||||
// AccessList returns the current accesslist maintained by the tracer.
|
||||
func (a *AccessListTracer) AccessList() types.AccessList {
|
||||
|
|
|
@ -109,12 +109,11 @@ type StructLogger struct {
|
|||
cfg Config
|
||||
env *vm.EVM
|
||||
|
||||
storage map[common.Address]Storage
|
||||
logs []StructLog
|
||||
output []byte
|
||||
err error
|
||||
gasLimit uint64
|
||||
usedGas uint64
|
||||
storage map[common.Address]Storage
|
||||
logs []StructLog
|
||||
output []byte
|
||||
err error
|
||||
usedGas uint64
|
||||
|
||||
interrupt atomic.Bool // Atomic flag to signal execution interruption
|
||||
reason error // Textual reason for the interruption
|
||||
|
@ -266,12 +265,10 @@ func (l *StructLogger) Stop(err error) {
|
|||
l.interrupt.Store(true)
|
||||
}
|
||||
|
||||
func (l *StructLogger) CaptureTxStart(gasLimit uint64) {
|
||||
l.gasLimit = gasLimit
|
||||
}
|
||||
func (l *StructLogger) CaptureTxStart(tx *types.Transaction) {}
|
||||
|
||||
func (l *StructLogger) CaptureTxEnd(restGas uint64) {
|
||||
l.usedGas = l.gasLimit - restGas
|
||||
func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt) {
|
||||
l.usedGas = receipt.GasUsed
|
||||
}
|
||||
|
||||
// StructLogs returns the captured log entries.
|
||||
|
@ -403,9 +400,9 @@ func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad
|
|||
|
||||
func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {}
|
||||
|
||||
func (*mdLogger) CaptureTxStart(gasLimit uint64) {}
|
||||
func (*mdLogger) CaptureTxStart(tx *types.Transaction) {}
|
||||
|
||||
func (*mdLogger) CaptureTxEnd(restGas uint64) {}
|
||||
func (*mdLogger) CaptureTxEnd(receipt *types.Receipt) {}
|
||||
|
||||
// ExecutionResult groups all structured logs emitted by the EVM
|
||||
// while replaying a transaction in debug mode as well as transaction
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/math"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
||||
|
@ -102,6 +103,6 @@ func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.
|
|||
|
||||
func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {}
|
||||
|
||||
func (l *JSONLogger) CaptureTxStart(gasLimit uint64) {}
|
||||
func (l *JSONLogger) CaptureTxStart(tx *types.Transaction) {}
|
||||
|
||||
func (l *JSONLogger) CaptureTxEnd(restGas uint64) {}
|
||||
func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt) {}
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
)
|
||||
|
@ -233,12 +234,12 @@ func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
|||
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
|
||||
}
|
||||
|
||||
func (t *callTracer) CaptureTxStart(gasLimit uint64) {
|
||||
t.gasLimit = gasLimit
|
||||
func (t *callTracer) CaptureTxStart(tx *types.Transaction) {
|
||||
t.gasLimit = tx.Gas()
|
||||
}
|
||||
|
||||
func (t *callTracer) CaptureTxEnd(restGas uint64) {
|
||||
t.callstack[0].GasUsed = t.gasLimit - restGas
|
||||
func (t *callTracer) CaptureTxEnd(receipt *types.Receipt) {
|
||||
t.callstack[0].GasUsed = receipt.GasUsed
|
||||
if t.config.WithLog {
|
||||
// Logs are not emitted when the call fails
|
||||
clearFailedLogs(&t.callstack[0], false)
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
)
|
||||
|
@ -202,12 +203,12 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *flatCallTracer) CaptureTxStart(gasLimit uint64) {
|
||||
t.tracer.CaptureTxStart(gasLimit)
|
||||
func (t *flatCallTracer) CaptureTxStart(tx *types.Transaction) {
|
||||
t.tracer.CaptureTxStart(tx)
|
||||
}
|
||||
|
||||
func (t *flatCallTracer) CaptureTxEnd(restGas uint64) {
|
||||
t.tracer.CaptureTxEnd(restGas)
|
||||
func (t *flatCallTracer) CaptureTxEnd(receipt *types.Receipt) {
|
||||
t.tracer.CaptureTxEnd(receipt)
|
||||
}
|
||||
|
||||
// GetResult returns an empty json object.
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
)
|
||||
|
@ -115,15 +116,15 @@ func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *muxTracer) CaptureTxStart(gasLimit uint64) {
|
||||
func (t *muxTracer) CaptureTxStart(tx *types.Transaction) {
|
||||
for _, t := range t.tracers {
|
||||
t.CaptureTxStart(gasLimit)
|
||||
t.CaptureTxStart(tx)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *muxTracer) CaptureTxEnd(restGas uint64) {
|
||||
func (t *muxTracer) CaptureTxEnd(receipt *types.Receipt) {
|
||||
for _, t := range t.tracers {
|
||||
t.CaptureTxEnd(restGas)
|
||||
t.CaptureTxEnd(receipt)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/ethereum/go-ethereum/eth/tracers"
|
||||
|
@ -174,11 +175,11 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
|
|||
}
|
||||
}
|
||||
|
||||
func (t *prestateTracer) CaptureTxStart(gasLimit uint64) {
|
||||
t.gasLimit = gasLimit
|
||||
func (t *prestateTracer) CaptureTxStart(tx *types.Transaction) {
|
||||
t.gasLimit = tx.Gas()
|
||||
}
|
||||
|
||||
func (t *prestateTracer) CaptureTxEnd(restGas uint64) {
|
||||
func (t *prestateTracer) CaptureTxEnd(receipt *types.Receipt) {
|
||||
if !t.config.DiffMode {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ import (
|
|||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/core/vm"
|
||||
)
|
||||
|
||||
|
@ -68,9 +69,9 @@ func (t *NoopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.
|
|||
func (t *NoopTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
||||
}
|
||||
|
||||
func (*NoopTracer) CaptureTxStart(gasLimit uint64) {}
|
||||
func (*NoopTracer) CaptureTxStart(tx *types.Transaction) {}
|
||||
|
||||
func (*NoopTracer) CaptureTxEnd(restGas uint64) {}
|
||||
func (*NoopTracer) CaptureTxEnd(receipt *types.Receipt) {}
|
||||
|
||||
// GetResult returns an empty json object.
|
||||
func (t *NoopTracer) GetResult() (json.RawMessage, error) {
|
||||
|
|
|
@ -49,13 +49,13 @@ func (p *Printer) CaptureExit(output []byte, gasUsed uint64, err error) {
|
|||
fmt.Printf("CaptureExit: output=%v, gasUsed=%v, err=%v\n", output, gasUsed, err)
|
||||
}
|
||||
|
||||
func (p *Printer) CaptureTxStart(gasLimit uint64) {
|
||||
fmt.Printf("CaptureTxStart: gasLimit=%v\n", gasLimit)
|
||||
func (p *Printer) CaptureTxStart(tx *types.Transaction) {
|
||||
fmt.Printf("CaptureTxStart: tx=%v\n", tx)
|
||||
|
||||
}
|
||||
|
||||
func (p *Printer) CaptureTxEnd(restGas uint64) {
|
||||
fmt.Printf("CaptureTxEnd: restGas=%v\n", restGas)
|
||||
func (p *Printer) CaptureTxEnd(receipt *types.Receipt) {
|
||||
fmt.Printf("CaptureTxEnd: receipt=%v\n", receipt)
|
||||
}
|
||||
|
||||
func (p *Printer) CaptureBlockStart(b *types.Block) {
|
||||
|
|
|
@ -333,6 +333,6 @@ func (b *LesApiBackend) StateAtBlock(ctx context.Context, block *types.Block, re
|
|||
return b.eth.stateAtBlock(ctx, block, reexec)
|
||||
}
|
||||
|
||||
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
func (b *LesApiBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ func (leth *LightEthereum) stateAtBlock(ctx context.Context, block *types.Block,
|
|||
}
|
||||
|
||||
// stateAtTransaction returns the execution environment of a certain transaction.
|
||||
func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
|
||||
// Short circuit if it's genesis block.
|
||||
if block.NumberU64() == 0 {
|
||||
return nil, vm.BlockContext{}, nil, nil, errors.New("no transaction in genesis")
|
||||
|
@ -65,7 +65,7 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
|
|||
context := core.NewEVMBlockContext(block.Header(), leth.blockchain, nil)
|
||||
statedb.SetTxContext(tx.Hash(), idx)
|
||||
if idx == txIndex {
|
||||
return msg, context, statedb, release, nil
|
||||
return tx, context, statedb, release, nil
|
||||
}
|
||||
// Not yet the searched for transaction, execute on top of the current state
|
||||
vmenv := vm.NewEVM(context, txContext, statedb, leth.blockchain.Config(), vm.Config{})
|
||||
|
|
Loading…
Reference in New Issue