diff --git a/.github/workflows/evm-tests.yml b/.github/workflows/evm-tests.yml
index 0ab7ae3fe..8c661b553 100644
--- a/.github/workflows/evm-tests.yml
+++ b/.github/workflows/evm-tests.yml
@@ -11,7 +11,7 @@ on:
jobs:
state-test:
- name: Run State Tests
+ name: Run EVM Tests
strategy:
matrix:
go-version: [1.22.x]
diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go
index 224e28021..9b3d69e7b 100644
--- a/accounts/abi/bind/backends/simulated.go
+++ b/accounts/abi/bind/backends/simulated.go
@@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/vm"
"github.com/ethereum/go-ethereum/eth/filters"
@@ -620,9 +621,26 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
}
// Set infinite balance to the fake caller account.
from := stateDB.GetOrNewStateObject(call.From)
- from.SetBalance(math.MaxBig256)
+ from.SetBalance(math.MaxBig256, tracing.BalanceChangeUnspecified)
+
// Execute the call.
- msg := callMsg{call}
+ msg := core.NewMessage(
+ call.From,
+ call.To,
+ 0,
+ call.Value,
+ call.Gas,
+ call.GasPrice,
+ call.GasFeeCap,
+ call.GasTipCap,
+ call.Data,
+ call.AccessList,
+ // Skip nonce check for simulated backend
+ true,
+ nil,
+ nil,
+ nil,
+ )
txContext := core.NewEVMTxContext(msg)
evmContext := core.NewEVMBlockContext(block.Header(), b.blockchain, nil)
@@ -631,7 +649,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
vmEnv := vm.NewEVM(evmContext, txContext, stateDB, b.config, vm.Config{NoBaseFee: true})
gasPool := new(core.GasPool).AddGas(math.MaxUint64)
- return core.NewStateTransition(vmEnv, msg, gasPool).TransitionDb()
+ return core.ApplyMessage(vmEnv, msg, gasPool)
}
// SendTransaction updates the pending block to include the given transaction.
@@ -795,31 +813,6 @@ func (b *SimulatedBackend) Blockchain() *core.BlockChain {
return b.blockchain
}
-// callMsg implements core.Message to allow passing it as a transaction simulator.
-type callMsg struct {
- ethereum.CallMsg
-}
-
-func (m callMsg) From() common.Address { return m.CallMsg.From }
-func (m callMsg) Nonce() uint64 { return 0 }
-func (m callMsg) IsFake() bool { return true }
-func (m callMsg) To() *common.Address { return m.CallMsg.To }
-func (m callMsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
-func (m callMsg) GasFeeCap() *big.Int { return m.CallMsg.GasFeeCap }
-func (m callMsg) GasTipCap() *big.Int { return m.CallMsg.GasTipCap }
-func (m callMsg) Gas() uint64 { return m.CallMsg.Gas }
-func (m callMsg) Value() *big.Int { return m.CallMsg.Value }
-func (m callMsg) Data() []byte { return m.CallMsg.Data }
-func (m callMsg) AccessList() types.AccessList { return m.CallMsg.AccessList }
-func (m callMsg) SetCodeAuthorizations() []types.SetCodeAuthorization { return nil }
-
-// FIXME: support sponsored transaction in callMsg
-func (m callMsg) Payer() common.Address { return m.CallMsg.From }
-func (m callMsg) ExpiredTime() uint64 { return 0 }
-
-func (m callMsg) BlobHashes() []common.Hash { return nil }
-func (m callMsg) BlobGasFeeCap() *big.Int { return nil }
-
// filterBackend implements filters.Backend to support filtering for logs without
// taking bloom-bits acceleration structures into account.
type filterBackend struct {
diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go
index 8583d786c..0c28d2452 100644
--- a/cmd/evm/internal/t8ntool/execution.go
+++ b/cmd/evm/internal/t8ntool/execution.go
@@ -18,6 +18,7 @@ package t8ntool
import (
"fmt"
+ "io"
"math/big"
"os"
@@ -28,9 +29,11 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/vm"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
@@ -97,7 +100,7 @@ type rejectedTx struct {
// Apply applies a set of transactions to a pre-state
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txs types.Transactions, miningReward int64,
- getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error),
+ getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error),
) (*state.StateDB, *ExecutionResult, error) {
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
// required blockhashes
@@ -148,17 +151,19 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
}
for i, tx := range txs {
- msg, err := tx.AsMessage(signer, pre.Env.BaseFee)
+ msg, err := core.TransactionToMessage(tx, signer, pre.Env.BaseFee)
if err != nil {
log.Warn("rejected tx", "index", i, "hash", tx.Hash(), "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
continue
}
- tracer, err := getTracerFn(txIndex, tx.Hash())
+ tracer, _, err := getTracerFn(txIndex, tx.Hash())
if err != nil {
return nil, nil, err
}
- vmConfig.Tracer = tracer
+ if tracer != nil {
+ vmConfig.Tracer = tracer.Hooks
+ }
vmConfig.Debug = (tracer != nil)
statedb.SetTxContext(tx.Hash(), txIndex)
txContext := core.NewEVMTxContext(msg)
@@ -169,7 +174,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
if err != nil {
statedb.RevertToSnapshot(snapshot)
- log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From(), "error", err)
+ log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
continue
}
@@ -200,7 +205,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
receipt.GasUsed = msgResult.UsedGas
// If the transaction created a contract, store the creation address in the receipt.
- if msg.To() == nil {
+ if msg.To == nil {
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
}
@@ -238,9 +243,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
reward.Sub(reward, big.NewInt(0).SetUint64(ommer.Delta))
reward.Mul(reward, blockReward)
reward.Div(reward, big.NewInt(8))
- statedb.AddBalance(ommer.Address, reward)
+ statedb.AddBalance(ommer.Address, reward, tracing.BalanceIncreaseRewardMineUncle)
}
- statedb.AddBalance(pre.Env.Coinbase, minerReward)
+ statedb.AddBalance(pre.Env.Coinbase, minerReward, tracing.BalanceIncreaseRewardMineBlock)
}
// Commit block
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
@@ -274,7 +279,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc) *state.StateDB
for addr, a := range accounts {
statedb.SetCode(addr, a.Code)
statedb.SetNonce(addr, a.Nonce)
- statedb.SetBalance(addr, a.Balance)
+ statedb.SetBalance(addr, a.Balance, tracing.BalanceIncreaseGenesisBalance)
for k, v := range a.Storage {
statedb.SetState(addr, k, v)
}
diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go
index a7f06f337..b30b83acd 100644
--- a/cmd/evm/internal/t8ntool/transition.go
+++ b/cmd/evm/internal/t8ntool/transition.go
@@ -21,12 +21,15 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
"io/ioutil"
"math/big"
"os"
"path"
+ "path/filepath"
"strings"
+ "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/common"
@@ -91,10 +94,9 @@ func Transition(ctx *cli.Context) error {
log.Root().SetHandler(glogger)
var (
- err error
- tracer vm.EVMLogger
+ err error
)
- var getTracer func(txIndex int, txHash common.Hash) (vm.EVMLogger, error)
+ var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil }
baseDir, err := createBasedir(ctx)
if err != nil {
@@ -127,20 +129,19 @@ func Transition(ctx *cli.Context) error {
prevFile.Close()
}
}()
- getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) {
- if prevFile != nil {
- prevFile.Close()
- }
- traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String())))
+ getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
+ traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String())))
if err != nil {
- return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
+ return nil, nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err))
}
- prevFile = traceFile
- return logger.NewJSONLogger(logConfig, traceFile), nil
- }
- } else {
- getTracer = func(txIndex int, txHash common.Hash) (tracer vm.EVMLogger, err error) {
- return nil, nil
+ logger := logger.NewJSONLogger(logConfig, traceFile)
+ tracer := &tracers.Tracer{
+ Hooks: logger,
+ // jsonLogger streams out result to file.
+ GetResult: func() (json.RawMessage, error) { return nil, nil },
+ Stop: func(err error) {},
+ }
+ return tracer, traceFile, nil
}
}
// We need to load three things: alloc, env and transactions. May be either in
@@ -179,10 +180,7 @@ func Transition(ctx *cli.Context) error {
}
prestate.Env = *inputData.Env
- vmConfig := vm.Config{
- Tracer: tracer,
- Debug: (tracer != nil),
- }
+ vmConfig := vm.Config{}
// Construct the chainconfig
var chainConfig *params.ChainConfig
if cConf, extraEips, err := tests.GetChainConfig(ctx.String(ForknameFlag.Name)); err != nil {
diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go
index 4a060f3e1..574193018 100644
--- a/cmd/evm/runner.go
+++ b/cmd/evm/runner.go
@@ -39,6 +39,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/vm"
"github.com/ethereum/go-ethereum/core/vm/runtime"
@@ -122,7 +123,7 @@ func runCmd(ctx *cli.Context) error {
}
var (
- tracer vm.EVMLogger
+ tracer *tracing.Hooks
debugLogger *logger.StructLogger
statedb *state.StateDB
chainConfig *params.ChainConfig
@@ -134,7 +135,7 @@ func runCmd(ctx *cli.Context) error {
tracer = logger.NewJSONLogger(logconfig, os.Stdout)
} else if ctx.Bool(DebugFlag.Name) {
debugLogger = logger.NewStructLogger(logconfig)
- tracer = debugLogger
+ tracer = debugLogger.Hooks()
} else {
debugLogger = logger.NewStructLogger(logconfig)
}
diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go
index 506f789a8..9a9435579 100644
--- a/cmd/evm/staterunner.go
+++ b/cmd/evm/staterunner.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/tests"
@@ -68,7 +69,7 @@ func stateTestCmd(ctx *cli.Context) error {
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
}
var (
- tracer vm.EVMLogger
+ tracer *tracing.Hooks
debugger *logger.StructLogger
)
switch {
@@ -77,7 +78,7 @@ func stateTestCmd(ctx *cli.Context) error {
case ctx.Bool(DebugFlag.Name):
debugger = logger.NewStructLogger(config)
- tracer = debugger
+ tracer = debugger.Hooks()
default:
debugger = logger.NewStructLogger(config)
diff --git a/cmd/ronin/main.go b/cmd/ronin/main.go
index afb7595d0..343a8fd07 100644
--- a/cmd/ronin/main.go
+++ b/cmd/ronin/main.go
@@ -46,6 +46,7 @@ import (
// Force-load the tracer engines to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
+ _ "github.com/ethereum/go-ethereum/eth/tracers/live"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
"github.com/urfave/cli/v2"
@@ -164,6 +165,8 @@ var (
utils.RinkebyFlag,
utils.GoerliFlag,
utils.VMEnableDebugFlag,
+ utils.VMTraceFlag,
+ utils.VMTraceConfigFlag,
utils.NetworkIdFlag,
utils.EthStatsURLFlag,
utils.FakePoWFlag,
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index 02e08403f..75a2729da 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -19,6 +19,7 @@ package utils
import (
"crypto/ecdsa"
+ "encoding/json"
"fmt"
"io/ioutil"
"math"
@@ -641,6 +642,17 @@ var (
Usage: "Record information useful for VM and contract debugging",
Category: flags.VMCategory,
}
+ VMTraceFlag = &cli.StringFlag{
+ Name: "vmtrace",
+ Usage: "Name of tracer which should record internal VM operations (costly)",
+ Category: flags.VMCategory,
+ }
+ VMTraceConfigFlag = &cli.StringFlag{
+ Name: "vmtrace.config",
+ Usage: "Tracer configuration (JSON)",
+ Value: "{}",
+ Category: flags.VMCategory,
+ }
RPCGlobalGasCapFlag = &cli.Uint64Flag{
Name: "rpc.gascap",
Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)",
@@ -1349,7 +1361,6 @@ func setWS(ctx *cli.Context, cfg *node.Config) {
cfg.WSReadBuffer = ctx.Int(WSReadBufferFlag.Name)
cfg.WSWriteBuffer = ctx.Int(WSWriteBufferFlag.Name)
-
}
// setIPC creates an IPC path configuration from the set command line flags,
@@ -2134,6 +2145,13 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
if err := kzg4844.UseCKZG(ctx.String(CryptoKZGFlag.Name) == "ckzg"); err != nil {
Fatalf("Failed to set KZG library implementation to %s: %v", ctx.String(CryptoKZGFlag.Name), err)
}
+ // VM tracing config.
+ if ctx.IsSet(VMTraceFlag.Name) {
+ if name := ctx.String(VMTraceFlag.Name); name != "" {
+ cfg.VMTrace = name
+ cfg.VMTraceConfig = ctx.String(VMTraceConfigFlag.Name)
+ }
+ }
if ctx.IsSet(DisableTxBroadcastFromFlag.Name) {
scheme := enode.V4ID{}
nodeIds := SplitAndTrim(ctx.String(DisableTxBroadcastFromFlag.Name))
@@ -2404,7 +2422,16 @@ func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chai
cache.TrieDirtyLimit = ctx.Int(CacheFlag.Name) * ctx.Int(CacheGCFlag.Name) / 100
}
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
-
+ if ctx.IsSet(VMTraceFlag.Name) {
+ if name := ctx.String(VMTraceFlag.Name); name != "" {
+ config := json.RawMessage(ctx.String(VMTraceConfigFlag.Name))
+ t, err := tracers.LiveDirectory.New(name, config)
+ if err != nil {
+ Fatalf("Failed to create tracer %q: %v", name, err)
+ }
+ vmcfg.Tracer = t
+ }
+ }
// TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only.
// Disable transaction indexing/unindexing by default.
chain, err = core.NewBlockChain(chainDb, cache, gpec, nil, engine, vmcfg, nil, nil)
diff --git a/consensus/consortium/common/contract.go b/consensus/consortium/common/contract.go
index 8405581cd..6dd8a5ce5 100644
--- a/consensus/consortium/common/contract.go
+++ b/consensus/consortium/common/contract.go
@@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/consortium/generated_contracts/staking"
"github.com/ethereum/go-ethereum/core"
"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/vm"
"github.com/ethereum/go-ethereum/crypto"
@@ -194,7 +195,7 @@ func (c *ContractIntegrator) WrapUpEpoch(opts *ApplyTransactOpts) error {
if err != nil {
return err
}
- msg := types.NewMessage(
+ msg := core.NewMessage(
opts.Header.Coinbase,
tx.To(),
opts.State.GetNonce(opts.Header.Coinbase),
@@ -224,8 +225,8 @@ func (c *ContractIntegrator) WrapUpEpoch(opts *ApplyTransactOpts) error {
func (c *ContractIntegrator) SubmitBlockReward(opts *ApplyTransactOpts) error {
coinbase := opts.Header.Coinbase
balance := opts.State.GetBalance(consensus.SystemAddress)
- opts.State.SetBalance(consensus.SystemAddress, big.NewInt(0))
- opts.State.AddBalance(coinbase, balance)
+ opts.State.SetBalance(consensus.SystemAddress, big.NewInt(0), tracing.BalanceDecreaseSystemAddress)
+ opts.State.AddBalance(coinbase, balance, tracing.BalanceIncreaseRewardMineBlock)
nonce := opts.State.GetNonce(c.coinbase)
isVenoki := c.chainConfig.IsVenoki(opts.Header.Number)
@@ -235,7 +236,7 @@ func (c *ContractIntegrator) SubmitBlockReward(opts *ApplyTransactOpts) error {
}
log.Debug("Submitted block reward", "block", opts.Header.Number, "amount", balance.Uint64())
- msg := types.NewMessage(
+ msg := core.NewMessage(
opts.Header.Coinbase,
tx.To(),
opts.State.GetNonce(opts.Header.Coinbase),
@@ -270,7 +271,7 @@ func (c *ContractIntegrator) Slash(opts *ApplyTransactOpts, spoiledValidator com
return err
}
- msg := types.NewMessage(
+ msg := core.NewMessage(
opts.Header.Coinbase,
tx.To(),
opts.State.GetNonce(opts.Header.Coinbase),
@@ -302,7 +303,7 @@ func (c *ContractIntegrator) FinalityReward(opts *ApplyTransactOpts, votedValida
return err
}
- msg := types.NewMessage(
+ msg := core.NewMessage(
opts.Header.Coinbase,
tx.To(),
opts.State.GetNonce(opts.Header.Coinbase),
@@ -473,7 +474,7 @@ type ApplyTransactOpts struct {
// ApplyTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. It returns nil if applied success
// and an error if the transaction failed, indicating the block was invalid.
-func ApplyTransaction(msg types.Message, opts *ApplyTransactOpts) (err error) {
+func ApplyTransaction(msg *core.Message, opts *ApplyTransactOpts) (err error) {
var failed bool
signer := opts.Signer
@@ -486,13 +487,13 @@ func ApplyTransaction(msg types.Message, opts *ApplyTransactOpts) (err error) {
header := opts.Header
receipts := opts.Receipts
usedGas := opts.UsedGas
- nonce := msg.Nonce()
+ nonce := msg.Nonce
// TODO(linh): This function is deprecated. Shall we replace it with NewTx?
- expectedTx := types.NewTransaction(nonce, *msg.To(), msg.Value(), msg.Gas(), msg.GasPrice(), msg.Data())
+ expectedTx := types.NewTransaction(nonce, *msg.To, msg.Amount, msg.GasLimit, msg.GasPrice, msg.Data)
expectedHash := signer.Hash(expectedTx)
- sender := msg.From()
+ sender := msg.From
// An empty/non-existing account's code hash is 0x000...00, while an existing account with no code has code hash
// that is equal to crypto.Keccak256Hash(nil)
if codeHash := opts.State.GetCodeHash(sender); codeHash != crypto.Keccak256Hash(nil) && codeHash != (common.Hash{}) {
@@ -504,7 +505,7 @@ func ApplyTransaction(msg types.Message, opts *ApplyTransactOpts) (err error) {
}
if mining {
- expectedTx, err = signTxFn(accounts.Account{Address: msg.From()}, expectedTx, chainConfig.ChainID)
+ expectedTx, err = signTxFn(accounts.Account{Address: msg.From}, expectedTx, chainConfig.ChainID)
if err != nil {
return err
}
@@ -530,7 +531,7 @@ func ApplyTransaction(msg types.Message, opts *ApplyTransactOpts) (err error) {
*receivedTxs = (*receivedTxs)[1:]
}
opts.State.SetTxContext(expectedTx.Hash(), len(*txs))
- opts.State.SetNonce(msg.From(), nonce+1)
+ opts.State.SetNonce(msg.From, nonce+1)
gasUsed, err := applyMessage(opts.ApplyMessageOpts, expectedTx)
if err != nil {
failed = true
diff --git a/consensus/consortium/common/contract_test.go b/consensus/consortium/common/contract_test.go
index 719dbad59..0185d92dc 100644
--- a/consensus/consortium/common/contract_test.go
+++ b/consensus/consortium/common/contract_test.go
@@ -17,6 +17,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/vm"
"github.com/ethereum/go-ethereum/crypto"
@@ -43,7 +44,7 @@ func TestApplyTransactionSender(t *testing.T) {
t.Fatalf("Failed to create stateDB, err %s", err)
}
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
t.Fatalf("Failed to create message, err %s", err)
}
@@ -64,7 +65,7 @@ func TestApplyTransactionSender(t *testing.T) {
// Sender is not an empty account but still has no code, we must
// not get core.ErrSenderNoEOA
- state.SetBalance(sender, common.Big1)
+ state.SetBalance(sender, common.Big1, tracing.BalanceChangeUnspecified)
err = ApplyTransaction(
msg,
&ApplyTransactOpts{
@@ -312,7 +313,7 @@ func TestApplyTransaction(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- msg := types.NewMessage(minerAddr, tx.To(), tx.Nonce(), tx.Value(), tx.Gas(),
+ msg := core.NewMessage(minerAddr, tx.To(), tx.Nonce(), tx.Value(), tx.Gas(),
tx.GasPrice(), tx.GasFeeCap(), tx.GasTipCap(), tx.Data(), nil, false, nil, nil, nil)
state, err := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
diff --git a/consensus/consortium/main.go b/consensus/consortium/main.go
index 20a3b20de..7e86dc44e 100644
--- a/consensus/consortium/main.go
+++ b/consensus/consortium/main.go
@@ -11,6 +11,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/consortium/v2/finality"
"github.com/ethereum/go-ethereum/core"
"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/ethdb"
"github.com/ethereum/go-ethereum/internal/ethapi"
@@ -115,7 +116,8 @@ func (c *Consortium) Prepare(chain consensus.ChainHeaderReader, header *types.He
// Finalize implements consensus.Engine as a proxy
func (c *Consortium) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction,
- uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, internalTxs *[]*types.InternalTransaction, usedGas *uint64) error {
+ uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, internalTxs *[]*types.InternalTransaction, usedGas *uint64,
+) error {
if c.chainConfig.IsConsortiumV2(header.Number) {
return c.v2.Finalize(chain, header, state, txs, uncles, receipts, systemTxs, internalTxs, usedGas)
}
@@ -125,7 +127,8 @@ func (c *Consortium) Finalize(chain consensus.ChainHeaderReader, header *types.H
// FinalizeAndAssemble implements consensus.Engine as a proxy
func (c *Consortium) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB,
- txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, []*types.Receipt, error) {
+ txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt,
+) (*types.Block, []*types.Receipt, error) {
if c.chainConfig.IsConsortiumV2(header.Number) {
return c.v2.FinalizeAndAssemble(chain, header, state, txs, uncles, receipts)
}
@@ -196,7 +199,7 @@ func (c *Consortium) SetGetFenixValidators(fn func() ([]common.Address, error))
// IsSystemTransaction implements consensus.PoSA. It is only available on v2 since v1 doesn't have system contract
func (c *Consortium) IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) {
- msg, err := tx.AsMessage(types.MakeSigner(c.chainConfig, header.Number), header.BaseFee)
+ msg, err := core.TransactionToMessage(tx, types.MakeSigner(c.chainConfig, header.Number), header.BaseFee)
if err != nil {
return false, err
}
@@ -270,7 +273,7 @@ func (c *Consortium) GetFinalityVoterAt(
// HandleSystemTransaction fixes up the statedb when system transaction
// goes through ApplyMessage when tracing/debugging
-func HandleSystemTransaction(engine consensus.Engine, statedb *state.StateDB, msg core.Message, block *types.Block) bool {
+func HandleSystemTransaction(engine consensus.Engine, statedb *state.StateDB, msg *core.Message, block *types.Block) bool {
consortium, ok := engine.(*Consortium)
if !ok {
return false
@@ -279,10 +282,10 @@ func HandleSystemTransaction(engine consensus.Engine, statedb *state.StateDB, ms
if consortium.chainConfig.IsConsortiumV2(new(big.Int).Add(block.Number(), common.Big1)) {
isSystemMsg := consortium.v2.IsSystemMessage(msg, block.Header())
if isSystemMsg {
- if msg.Value().Cmp(common.Big0) > 0 {
+ if msg.Amount.Cmp(common.Big0) > 0 {
balance := statedb.GetBalance(consensus.SystemAddress)
- statedb.SetBalance(consensus.SystemAddress, big.NewInt(0))
- statedb.AddBalance(block.Coinbase(), balance)
+ statedb.SetBalance(consensus.SystemAddress, big.NewInt(0), tracing.BalanceDecreaseSystemAddress)
+ statedb.AddBalance(block.Coinbase(), balance, tracing.BalanceIncreaseRewardMineBlock)
}
return true
diff --git a/consensus/consortium/v2/consortium.go b/consensus/consortium/v2/consortium.go
index 98e01bf78..195ea943b 100644
--- a/consensus/consortium/v2/consortium.go
+++ b/consensus/consortium/v2/consortium.go
@@ -165,17 +165,17 @@ func New(
// transaction or not.
// A system transaction is a transaction that has the recipient of the contract address
// is defined in params.ConsortiumV2Contracts
-func (c *Consortium) IsSystemMessage(msg core.Message, header *types.Header) bool {
+func (c *Consortium) IsSystemMessage(msg *core.Message, header *types.Header) bool {
// deploy a contract
- if msg.To() == nil {
+ if msg.To == nil {
return false
}
if c.chainConfig.IsBuba(header.Number) {
- if msg.From() == header.Coinbase && c.IsSystemContract(msg.To()) {
+ if msg.From == header.Coinbase && c.IsSystemContract(msg.To) {
return true
}
} else {
- if msg.From() == header.Coinbase && c.IsSystemContract(msg.To()) && msg.GasPrice().Cmp(big.NewInt(0)) == 0 {
+ if msg.From == header.Coinbase && c.IsSystemContract(msg.To) && msg.GasPrice.Cmp(big.NewInt(0)) == 0 {
return true
}
}
@@ -185,7 +185,7 @@ func (c *Consortium) IsSystemMessage(msg core.Message, header *types.Header) boo
// In normal case, IsSystemTransaction in consortium/main.go is used instead of this function. This function
// is only used in testing when we create standalone consortium v2 engine without the v1
func (c *Consortium) IsSystemTransaction(tx *types.Transaction, header *types.Header) (bool, error) {
- msg, err := tx.AsMessage(types.MakeSigner(c.chainConfig, header.Number), header.BaseFee)
+ msg, err := core.TransactionToMessage(tx, types.MakeSigner(c.chainConfig, header.Number), header.BaseFee)
if err != nil {
return false, err
}
@@ -700,9 +700,7 @@ func (c *Consortium) snapshot(chain consensus.ChainHeaderReader, number uint64,
// init snapshot if it is at forkedBlock
if number == c.forkedBlock-1 {
- var (
- err error
- )
+ var err error
snap, err = loadSnapshot(c.config, c.signatures, c.db, hash, c.ethAPI, c.chainConfig)
if err == nil {
log.Trace("Loaded snapshot from disk", "number", number, "hash", hash.Hex())
@@ -1107,8 +1105,8 @@ func (c *Consortium) Prepare(chain consensus.ChainHeaderReader, header *types.He
}
func (c *Consortium) processSystemTransactions(chain consensus.ChainHeaderReader, header *types.Header,
- transactOpts *consortiumCommon.ApplyTransactOpts, isFinalizeAndAssemble bool) error {
-
+ transactOpts *consortiumCommon.ApplyTransactOpts, isFinalizeAndAssemble bool,
+) error {
snap, err := c.snapshot(chain, header.Number.Uint64()-1, header.ParentHash, nil)
if err != nil {
return err
@@ -1257,7 +1255,8 @@ func verifyValidatorExtraDataWithContract(
// - Slash the validator who does not sign if it is in-turn
// - SubmitBlockRewards of the current block
func (c *Consortium) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs *[]*types.Transaction,
- uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, internalTxs *[]*types.InternalTransaction, usedGas *uint64) error {
+ uncles []*types.Header, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction, internalTxs *[]*types.InternalTransaction, usedGas *uint64,
+) error {
_, _, signTxFn, _ := c.readSignerAndContract()
evmContext := core.NewEVMBlockContext(header, consortiumCommon.ChainContext{Chain: chain, Consortium: c}, &header.Coinbase, chain.OpEvents()...)
transactOpts := &consortiumCommon.ApplyTransactOpts{
@@ -1360,7 +1359,8 @@ func (c *Consortium) Finalize(chain consensus.ChainHeaderReader, header *types.H
// - Slash the validator who does not sign if it is in-turn
// - SubmitBlockRewards of the current block
func (c *Consortium) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB,
- txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, []*types.Receipt, error) {
+ txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt,
+) (*types.Block, []*types.Receipt, error) {
// No block rewards in PoA, so the state remains as is and uncles are dropped
if txs == nil {
txs = make([]*types.Transaction, 0)
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index 495ae86ff..0a5d14ec7 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc"
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"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/params"
"github.com/ethereum/go-ethereum/rlp"
@@ -675,10 +676,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
r.Sub(r, header.Number)
r.Mul(r, blockReward)
r.Div(r, big8)
- state.AddBalance(uncle.Coinbase, r)
+ state.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle)
r.Div(blockReward, big32)
reward.Add(reward, r)
}
- state.AddBalance(header.Coinbase, reward)
+ state.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock)
}
diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go
index 36df036f2..20f5524dc 100644
--- a/consensus/misc/dao.go
+++ b/consensus/misc/dao.go
@@ -22,6 +22,7 @@ import (
"math/big"
"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/params"
)
@@ -40,10 +41,11 @@ var (
// ensure it conforms to DAO hard-fork rules.
//
// DAO hard-fork extension to the header validity:
-// a) if the node is no-fork, do not accept blocks in the [fork, fork+10) range
-// with the fork specific extra-data set
-// b) if the node is pro-fork, require blocks in the specific range to have the
-// unique extra-data set.
+//
+// a) if the node is no-fork, do not accept blocks in the [fork, fork+10) range
+// with the fork specific extra-data set
+// b) if the node is pro-fork, require blocks in the specific range to have the
+// unique extra-data set.
func VerifyDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error {
// Short circuit validation if the node doesn't care about the DAO fork
if config.DAOForkBlock == nil {
@@ -79,7 +81,7 @@ func ApplyDAOHardFork(statedb *state.StateDB) {
// Move every DAO account and extra-balance account funds into the refund contract
for _, addr := range params.DAODrainList() {
- statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr))
- statedb.SetBalance(addr, new(big.Int))
+ statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract)
+ statedb.SetBalance(addr, new(big.Int), tracing.BalanceDecreaseDaoAccount)
}
}
diff --git a/core/blockchain.go b/core/blockchain.go
index 19accfeda..54ba06e20 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/ethdb"
@@ -259,6 +260,7 @@ type BlockChain struct {
prefetcher Prefetcher
processor Processor // Block transaction processor interface
vmConfig vm.Config
+ logger *tracing.Hooks
shouldPreserve func(*types.Block) bool // Function used to determine whether should preserve the given block.
shouldStoreInternalTxs bool
@@ -325,6 +327,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
futureBlocks: futureBlocks,
engine: engine,
vmConfig: vmConfig,
+ logger: vmConfig.Tracer,
shouldStoreInternalTxs: rawdb.ReadStoreInternalTransactionsEnabled(db),
blobSidecarsCache: blobSidecarsCache,
@@ -456,6 +459,25 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
}
+ if bc.logger != nil && bc.logger.OnBlockchainInit != nil {
+ bc.logger.OnBlockchainInit(chainConfig)
+ }
+
+ if bc.logger != nil && bc.logger.OnGenesisBlock != nil {
+ if block := bc.CurrentBlock(); block.Number().Uint64() == 0 {
+ alloc, err := getGenesisState(bc.db, block.Hash())
+ if err != nil {
+ return nil, fmt.Errorf("failed to get genesis state: %w", err)
+ }
+
+ if alloc == nil {
+ return nil, fmt.Errorf("live blockchain tracer requires genesis alloc to be set")
+ }
+
+ bc.logger.OnGenesisBlock(bc.genesisBlock, alloc)
+ }
+ }
+
// Load any existing snapshot, regenerating it if loading failed
if bc.cacheConfig.SnapshotLimit > 0 {
// If the chain was rewound past the snapshot persistent layer (causing
@@ -1070,6 +1092,10 @@ func (bc *BlockChain) Stop() {
}
}
}
+ // Allow tracers to clean-up and release resources.
+ if bc.logger != nil && bc.logger.OnClose != nil {
+ bc.logger.OnClose()
+ }
// Flush the collected preimages to disk
if err := bc.triedb.Close(); err != nil {
log.Error("Failed to close trie db", "err", err)
@@ -1971,6 +1997,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
return it.index, err
}
stats.processed++
+ if bc.logger != nil && bc.logger.OnSkippedBlock != nil {
+ bc.logger.OnSkippedBlock(tracing.BlockEvent{
+ Block: block,
+ TD: bc.GetTd(block.ParentHash(), block.NumberU64()-1),
+ Finalized: bc.CurrentFinalBlock(),
+ })
+ }
// We can assume that logs are empty here, since the only way for consecutive
// Clique blocks to have the same state is if there are no transactions.
@@ -1988,6 +2021,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
if err != nil {
return it.index, err
}
+ statedb.SetLogger(bc.logger)
// Enable prefetching to pull in trie node paths while processing transactions
statedb.StartPrefetcher("chain")
@@ -2001,7 +2035,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) {
- bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt)
+ // Disable tracing for prefetcher executions.
+ vmCfg := bc.vmConfig
+ vmCfg.Tracer = nil
+ bc.prefetcher.Prefetch(followup, throwaway, vmCfg, &followupInterrupt)
blockPrefetchExecuteTimer.Update(time.Since(start))
if atomic.LoadUint32(interrupt) == 1 {
@@ -2011,73 +2048,19 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
}
}
- // Process block using the parent state as reference point
- substart := time.Now()
- receipts, logs, internalTxs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig, bc.OpEvents()...)
- if err != nil {
- bc.reportBlock(block, receipts, err)
- atomic.StoreUint32(&followupInterrupt, 1)
- return it.index, err
- }
-
- // store internal txs to db and send them to internalTxFeed
- if bc.enableAdditionalChainEvent && len(internalTxs) > 0 {
- bc.WriteInternalTransactions(block.Hash(), internalTxs)
- bc.internalTxFeed.Send(internalTxs)
- }
-
- // Update the metrics touched during block processing
- accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them
- storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them
- accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete, we can mark them
- storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete, we can mark them
- snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete, we can mark them
- snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete, we can mark them
- triehash := statedb.AccountHashes + statedb.StorageHashes // Save to not double count in validation
- trieproc := statedb.SnapshotAccountReads + statedb.AccountReads + statedb.AccountUpdates
- trieproc += statedb.SnapshotStorageReads + statedb.StorageReads + statedb.StorageUpdates
-
- blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash)
-
- // Validate the state using the default validator
- substart = time.Now()
- if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
- bc.reportBlock(block, receipts, err)
- atomic.StoreUint32(&followupInterrupt, 1)
- return it.index, err
- }
- proctime := time.Since(start)
-
- // Update the metrics touched during block validation
- accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete, we can mark them
- storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete, we can mark them
-
- blockValidationTimer.Update(time.Since(substart) - (statedb.AccountHashes + statedb.StorageHashes - triehash))
-
- // Write the block to the chain and get the status.
- substart = time.Now()
var blockSidecars []*types.BlobTxSidecar
if len(sidecars) > 0 {
blockSidecars = sidecars[it.index]
}
- status, err := bc.writeBlockWithState(block, receipts, logs, internalTxs, statedb, false, blockSidecars)
+
+ // The traced section of block import.
+ res, err := bc.processBlock(block, statedb, start, blockSidecars)
atomic.StoreUint32(&followupInterrupt, 1)
if err != nil {
return it.index, err
}
- // Update the metrics touched during block commit
- accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them
- storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them
- snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
- triedbCommitTimer.Update(statedb.TrieDBCommits) // Triedb commits are complete, we can mark them
-
- blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
- blockInsertTimer.UpdateSince(start)
- blockTxsGauge.Update(int64(len(block.Transactions())))
- blockGasUsedGauge.Update(int64(block.GasUsed()))
-
- switch status {
+ switch res.status {
case CanonStatTy:
log.Debug("Inserted new block", "number", block.Number(), "hash", block.Hash(),
"uncles", len(block.Uncles()), "txs", len(block.Transactions()), "gas", block.GasUsed(),
@@ -2087,7 +2070,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
lastCanon = block
// Only count canonical blocks for GC processing time
- bc.gcproc += proctime
+ bc.gcproc += res.procTime
case SideStatTy:
log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(),
@@ -2104,7 +2087,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
"root", block.Root())
}
stats.processed++
- stats.usedGas += usedGas
+ stats.usedGas += res.usedGas
dirty, _ := bc.triedb.Size()
stats.report(chain, it.index, dirty)
@@ -2137,6 +2120,94 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool, sidecars
return it.index, err
}
+// blockProcessingResult is a summary of block processing
+// used for updating the stats.
+type blockProcessingResult struct {
+ usedGas uint64
+ procTime time.Duration
+ status WriteStatus
+}
+
+// processBlock executes and validates the given block. If there was no error
+// it writes the block and associated state to database.
+func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, start time.Time, blockSidecars []*types.BlobTxSidecar) (_ *blockProcessingResult, blockEndErr error) {
+ if bc.logger != nil && bc.logger.OnBlockStart != nil {
+ td := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
+ bc.logger.OnBlockStart(tracing.BlockEvent{
+ Block: block,
+ TD: td,
+ Finalized: bc.CurrentFinalBlock(),
+ })
+ }
+ if bc.logger != nil && bc.logger.OnBlockEnd != nil {
+ defer func() {
+ bc.logger.OnBlockEnd(blockEndErr)
+ }()
+ }
+
+ // Process block using the parent state as reference point
+ substart := time.Now()
+ receipts, logs, internalTxs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig, bc.OpEvents()...)
+ if err != nil {
+ bc.reportBlock(block, receipts, err)
+ return nil, err
+ }
+
+ // store internal txs to db and send them to internalTxFeed
+ if bc.enableAdditionalChainEvent && len(internalTxs) > 0 {
+ bc.WriteInternalTransactions(block.Hash(), internalTxs)
+ bc.internalTxFeed.Send(internalTxs)
+ }
+
+ // Update the metrics touched during block processing
+ accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them
+ storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them
+ accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete, we can mark them
+ storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete, we can mark them
+ snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete, we can mark them
+ snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete, we can mark them
+ triehash := statedb.AccountHashes + statedb.StorageHashes // Save to not double count in validation
+ trieproc := statedb.SnapshotAccountReads + statedb.AccountReads + statedb.AccountUpdates
+ trieproc += statedb.SnapshotStorageReads + statedb.StorageReads + statedb.StorageUpdates
+
+ blockExecutionTimer.Update(time.Since(substart) - trieproc - triehash)
+
+ // Validate the state using the default validator
+ substart = time.Now()
+ if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
+ bc.reportBlock(block, receipts, err)
+ return nil, err
+ }
+ proctime := time.Since(start)
+
+ // Update the metrics touched during block validation
+ accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete, we can mark them
+ storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete, we can mark them
+
+ blockValidationTimer.Update(time.Since(substart) - (statedb.AccountHashes + statedb.StorageHashes - triehash))
+
+ // Write the block to the chain and get the status.
+ substart = time.Now()
+ status, err := bc.writeBlockWithState(block, receipts, logs, internalTxs, statedb, false, blockSidecars)
+ if err != nil {
+ bc.reportBlock(block, receipts, err)
+ return nil, err
+ }
+
+ // Update the metrics touched during block commit
+ accountCommitTimer.Update(statedb.AccountCommits) // Account commits are complete, we can mark them
+ storageCommitTimer.Update(statedb.StorageCommits) // Storage commits are complete, we can mark them
+ snapshotCommitTimer.Update(statedb.SnapshotCommits) // Snapshot commits are complete, we can mark them
+ triedbCommitTimer.Update(statedb.TrieDBCommits) // Triedb commits are complete, we can mark them
+
+ blockWriteTimer.Update(time.Since(substart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
+ blockInsertTimer.UpdateSince(start)
+ blockTxsGauge.Update(int64(len(block.Transactions())))
+ blockGasUsedGauge.Update(int64(block.GasUsed()))
+
+ return &blockProcessingResult{usedGas: usedGas, procTime: proctime, status: status}, nil
+}
+
// insertSideChain is called when an import batch hits upon a pruned ancestor
// error, which happens when a sidechain with a sufficiently old fork-block is
// found.
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 5854edb15..9c2861c1c 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -4130,7 +4130,7 @@ func testEIP3651(t *testing.T, scheme string) {
b.AddTx(tx)
})
- chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, nil, nil)
+ chain, err := NewBlockChain(db, DefaultCacheConfigWithScheme(scheme), gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr).Hooks()}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
diff --git a/core/chain_makers.go b/core/chain_makers.go
index 2c58f6393..04ab4b2d5 100644
--- a/core/chain_makers.go
+++ b/core/chain_makers.go
@@ -83,6 +83,12 @@ func (b *BlockGen) SetDifficulty(diff *big.Int) {
b.header.Difficulty = diff
}
+// SetBaseFee sets the base fee field of the generated block. This method is
+// used only for EIP-1559 tests.
+func (b *BlockGen) SetBaseFee(baseFee *big.Int) {
+ b.header.BaseFee = baseFee
+}
+
// Difficulty returns the currently calculated difficulty of the block.
func (b *BlockGen) Difficulty() *big.Int {
return new(big.Int).Set(b.header.Difficulty)
@@ -100,7 +106,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
b.SetCoinbase(common.Address{})
}
b.statedb.SetTxContext(tx.Hash(), len(b.txs))
- receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig, &ReceiptBloomGenerator{})
+ receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vmConfig)
if err != nil {
panic(err)
}
diff --git a/core/evm.go b/core/evm.go
index 787dc5eb1..74e145fbd 100644
--- a/core/evm.go
+++ b/core/evm.go
@@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
)
@@ -84,11 +85,11 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
}
// NewEVMTxContext creates a new transaction context for a single transaction.
-func NewEVMTxContext(msg Message) vm.TxContext {
+func NewEVMTxContext(msg *Message) vm.TxContext {
return vm.TxContext{
- Origin: msg.From(),
- GasPrice: new(big.Int).Set(msg.GasPrice()),
- BlobHashes: msg.BlobHashes(),
+ Origin: msg.From,
+ GasPrice: new(big.Int).Set(msg.GasPrice),
+ BlobHashes: msg.BlobHashes,
}
}
@@ -134,6 +135,6 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *big.Int) bool {
// Transfer subtracts amount from sender and adds amount to recipient using the given Db
func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int) {
- db.SubBalance(sender, amount)
- db.AddBalance(recipient, amount)
+ db.SubBalance(sender, amount, tracing.BalanceChangeTransfer)
+ db.AddBalance(recipient, amount, tracing.BalanceChangeTransfer)
}
diff --git a/core/genesis.go b/core/genesis.go
index 024438843..e1c09d27d 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@@ -80,7 +81,9 @@ func hashAlloc(ga *types.GenesisAlloc) (common.Hash, error) {
return common.Hash{}, err
}
for addr, account := range *ga {
- statedb.AddBalance(addr, account.Balance)
+ if account.Balance != nil {
+ statedb.AddBalance(addr, account.Balance, tracing.BalanceIncreaseGenesisBalance)
+ }
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
for key, value := range account.Storage {
@@ -100,7 +103,7 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *trie.Database
}
for addr, account := range *ga {
if account.Balance != nil {
- statedb.AddBalance(addr, account.Balance)
+ statedb.AddBalance(addr, account.Balance, tracing.BalanceIncreaseGenesisBalance)
}
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
@@ -127,6 +130,37 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *trie.Database
return nil
}
+func getGenesisState(db ethdb.Database, blockhash common.Hash) (alloc types.GenesisAlloc, err error) {
+ blob := rawdb.ReadGenesisStateSpec(db, blockhash)
+ if len(blob) != 0 {
+ if err := alloc.UnmarshalJSON(blob); err != nil {
+ return nil, err
+ }
+
+ return alloc, nil
+ }
+
+ // Genesis allocation is missing and there are several possibilities:
+ // the node is legacy which doesn't persist the genesis allocation or
+ // the persisted allocation is just lost.
+ // - supported networks(mainnet, testnets), recover with defined allocations
+ // - private network, can't recover
+ var genesis *Genesis
+ switch blockhash {
+ case params.MainnetGenesisHash:
+ genesis = DefaultGenesisBlock()
+ case params.GoerliGenesisHash:
+ genesis = DefaultGoerliGenesisBlock()
+ case params.SepoliaGenesisHash:
+ genesis = DefaultSepoliaGenesisBlock()
+ }
+ if genesis != nil {
+ return genesis.Alloc, nil
+ }
+
+ return nil, nil
+}
+
// field type overrides for gencodec
type genesisSpecMarshaling struct {
Nonce math.HexOrDecimal64
diff --git a/core/receipt_processor.go b/core/receipt_processor.go
deleted file mode 100644
index 3b4c2579c..000000000
--- a/core/receipt_processor.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package core
-
-import (
- "bytes"
- "sync"
-
- "github.com/ethereum/go-ethereum/core/types"
-)
-
-type ReceiptProcessor interface {
- Apply(receipt *types.Receipt)
-}
-
-var (
- _ ReceiptProcessor = (*ReceiptBloomGenerator)(nil)
- _ ReceiptProcessor = (*AsyncReceiptBloomGenerator)(nil)
-)
-
-func NewReceiptBloomGenerator() *ReceiptBloomGenerator {
- return &ReceiptBloomGenerator{}
-}
-
-type ReceiptBloomGenerator struct {
-}
-
-func (p *ReceiptBloomGenerator) Apply(receipt *types.Receipt) {
- receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
-}
-
-func NewAsyncReceiptBloomGenerator(txNums int) *AsyncReceiptBloomGenerator {
- generator := &AsyncReceiptBloomGenerator{
- receipts: make(chan *types.Receipt, txNums),
- }
- generator.startWorker()
- return generator
-}
-
-type AsyncReceiptBloomGenerator struct {
- receipts chan *types.Receipt
- wg sync.WaitGroup
- isClosed bool
-}
-
-func (p *AsyncReceiptBloomGenerator) startWorker() {
- p.wg.Add(1)
- go func() {
- defer p.wg.Done()
- for receipt := range p.receipts {
- if receipt != nil && bytes.Equal(receipt.Bloom[:], types.EmptyBloom[:]) {
- receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
- }
- }
- }()
-}
-
-func (p *AsyncReceiptBloomGenerator) Apply(receipt *types.Receipt) {
- if !p.isClosed {
- p.receipts <- receipt
- }
-}
-
-func (p *AsyncReceiptBloomGenerator) Close() {
- close(p.receipts)
- p.isClosed = true
- p.wg.Wait()
-}
diff --git a/core/state/state_object.go b/core/state/state_object.go
index e97468512..279fc0af0 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -24,6 +24,7 @@ import (
"time"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
@@ -276,6 +277,9 @@ func (s *stateObject) SetState(key, value common.Hash) {
key: key,
prevalue: prev,
})
+ if s.db.logger != nil && s.db.logger.OnStorageChange != nil {
+ s.db.logger.OnStorageChange(s.address, key, prev, value)
+ }
s.setState(key, value)
}
@@ -444,7 +448,7 @@ func (s *stateObject) commit() (*trienode.NodeSet, error) {
// AddBalance adds amount to s's balance.
// It is used to add funds to the destination account of a transfer.
-func (s *stateObject) AddBalance(amount *big.Int) {
+func (s *stateObject) AddBalance(amount *big.Int, reason tracing.BalanceChangeReason) {
// EIP161: We must check emptiness for the objects such that the account
// clearing (0,0,0 objects) can take effect.
if amount.Sign() == 0 {
@@ -453,23 +457,26 @@ func (s *stateObject) AddBalance(amount *big.Int) {
}
return
}
- s.SetBalance(new(big.Int).Add(s.Balance(), amount))
+ s.SetBalance(new(big.Int).Add(s.Balance(), amount), reason)
}
// SubBalance removes amount from s's balance.
// It is used to remove funds from the origin account of a transfer.
-func (s *stateObject) SubBalance(amount *big.Int) {
+func (s *stateObject) SubBalance(amount *big.Int, reason tracing.BalanceChangeReason) {
if amount.Sign() == 0 {
return
}
- s.SetBalance(new(big.Int).Sub(s.Balance(), amount))
+ s.SetBalance(new(big.Int).Sub(s.Balance(), amount), reason)
}
-func (s *stateObject) SetBalance(amount *big.Int) {
+func (s *stateObject) SetBalance(amount *big.Int, reason tracing.BalanceChangeReason) {
s.db.journal.append(balanceChange{
account: &s.address,
prev: new(big.Int).Set(s.data.Balance),
})
+ if s.db.logger != nil && s.db.logger.OnBalanceChange != nil {
+ s.db.logger.OnBalanceChange(s.address, s.Balance(), amount, reason)
+ }
s.setBalance(amount)
}
@@ -547,6 +554,9 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []byte) []byte {
prevhash: s.CodeHash(),
prevcode: prevcode,
})
+ if s.db.logger != nil && s.db.logger.OnCodeChange != nil {
+ s.db.logger.OnCodeChange(s.address, common.BytesToHash(s.CodeHash()), prevcode, codeHash, code)
+ }
s.setCode(codeHash, code)
return prevcode
}
@@ -562,6 +572,9 @@ func (s *stateObject) SetNonce(nonce uint64) {
account: &s.address,
prev: s.data.Nonce,
})
+ if s.db.logger != nil && s.db.logger.OnNonceChange != nil {
+ s.db.logger.OnNonceChange(s.address, s.data.Nonce, nonce)
+ }
s.setNonce(nonce)
}
diff --git a/core/state/state_test.go b/core/state/state_test.go
index 9b011eb95..618aa7269 100644
--- a/core/state/state_test.go
+++ b/core/state/state_test.go
@@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@@ -47,11 +48,11 @@ func TestDump(t *testing.T) {
// generate a few entries
obj1 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01}))
- obj1.AddBalance(big.NewInt(22))
+ obj1.AddBalance(big.NewInt(22), tracing.BalanceChangeUnspecified)
obj2 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x01, 0x02}))
obj2.SetCode(crypto.Keccak256Hash([]byte{3, 3, 3, 3, 3, 3, 3}), []byte{3, 3, 3, 3, 3, 3, 3})
obj3 := s.state.GetOrNewStateObject(common.BytesToAddress([]byte{0x02}))
- obj3.SetBalance(big.NewInt(44))
+ obj3.SetBalance(big.NewInt(44), tracing.BalanceChangeUnspecified)
// write some of them to the trie
s.state.updateStateObject(obj1)
@@ -98,7 +99,7 @@ func TestNull(t *testing.T) {
s := newStateEnv()
address := common.HexToAddress("0x823140710bf13990e4500136726d8b55")
s.state.CreateAccount(address)
- //value := common.FromHex("0x823140710bf13990e4500136726d8b55")
+ // value := common.FromHex("0x823140710bf13990e4500136726d8b55")
var value common.Hash
s.state.SetState(address, common.Hash{}, value)
@@ -159,7 +160,7 @@ func TestCreateObjectRevert(t *testing.T) {
state.CreateAccount(addr)
so0 := state.getStateObject(addr)
- so0.SetBalance(big.NewInt(42))
+ so0.SetBalance(big.NewInt(42), tracing.BalanceChangeUnspecified)
so0.SetNonce(43)
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
state.setStateObject(so0)
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 2907274a4..33f856603 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -29,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state/snapshot"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
@@ -45,10 +46,8 @@ type revision struct {
journalIndex int
}
-var (
- // emptyRoot is the known root hash of an empty trie.
- emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
-)
+// emptyRoot is the known root hash of an empty trie.
+var emptyRoot = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
type proofList [][]byte
@@ -96,6 +95,7 @@ type StateDB struct {
prefetcher *triePrefetcher
trie Trie
hasher crypto.KeccakState
+ logger *tracing.Hooks
// originalRoot is the pre-state root, before any changes were made.
// It will be updated when the Commit is called.
@@ -208,6 +208,11 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
return sdb, nil
}
+// SetLogger sets the logger for account update hooks.
+func (s *StateDB) SetLogger(l *tracing.Hooks) {
+ s.logger = l
+}
+
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot.
@@ -247,8 +252,13 @@ func (s *StateDB) AddLog(log *types.Log) {
log.TxHash = s.thash
log.TxIndex = uint(s.txIndex)
log.Index = s.logSize
+
s.logs[s.thash] = append(s.logs[s.thash], log)
s.logSize++
+
+ if s.logger != nil && s.logger.OnLog != nil {
+ s.logger.OnLog(log)
+ }
}
// GetLogs returns the logs matching the specified transaction hash, and annotates
@@ -452,25 +462,25 @@ func (s *StateDB) HasSelfDestructed(addr common.Address) bool {
*/
// AddBalance adds amount to the account associated with addr.
-func (s *StateDB) AddBalance(addr common.Address, amount *big.Int) {
+func (s *StateDB) AddBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
- stateObject.AddBalance(amount)
+ stateObject.AddBalance(amount, reason)
}
}
// SubBalance subtracts amount from the account associated with addr.
-func (s *StateDB) SubBalance(addr common.Address, amount *big.Int) {
+func (s *StateDB) SubBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
- stateObject.SubBalance(amount)
+ stateObject.SubBalance(amount, reason)
}
}
-func (s *StateDB) SetBalance(addr common.Address, amount *big.Int) {
+func (s *StateDB) SetBalance(addr common.Address, amount *big.Int, reason tracing.BalanceChangeReason) {
stateObject := s.GetOrNewStateObject(addr)
if stateObject != nil {
- stateObject.SetBalance(amount)
+ stateObject.SetBalance(amount, reason)
}
}
@@ -519,7 +529,7 @@ func (s *StateDB) SetStorage(addr common.Address, storage map[common.Hash]common
if obj != nil {
newObj.SetCode(common.BytesToHash(obj.CodeHash()), obj.code)
newObj.SetNonce(obj.Nonce())
- newObj.SetBalance(obj.Balance())
+ newObj.SetBalance(obj.Balance(), tracing.BalanceChangeUnspecified)
}
}
@@ -533,13 +543,20 @@ func (s *StateDB) SelfDestruct(addr common.Address) bool {
if stateObject == nil {
return false
}
+ var (
+ prev = new(big.Int).Set(stateObject.Balance())
+ n = new(big.Int)
+ )
s.journal.append(selfDestructChange{
account: &addr,
prev: stateObject.selfDestructed,
- prevbalance: new(big.Int).Set(stateObject.Balance()),
+ prevbalance: prev,
})
+ if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 {
+ s.logger.OnBalanceChange(addr, prev, n, tracing.BalanceDecreaseSelfdestruct)
+ }
stateObject.markSelfdestructed()
- stateObject.data.Balance = new(big.Int)
+ stateObject.data.Balance = n
return true
}
@@ -815,8 +832,9 @@ func (s *StateDB) Copy() *StateDB {
// to the snapshot tree, we need to copy that as well. Otherwise, any
// block mined by ourselves will cause gaps in the tree, and force the
// miner to operate trie-backed only.
- snaps: s.snaps,
- snap: s.snap,
+ snaps: s.snaps,
+ snap: s.snap,
+ logger: s.logger,
}
// Deep copy cached state objects.
for addr, obj := range s.stateObjects {
@@ -905,6 +923,10 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
delete(s.stateObjects, obj.address)
s.markDelete(addr)
+ // If ether was sent to account post-selfdestruct it is burnt.
+ if bal := obj.Balance(); s.logger != nil && s.logger.OnBalanceChange != nil && obj.selfDestructed && bal.Sign() != 0 {
+ s.logger.OnBalanceChange(obj.address, bal, new(big.Int), tracing.BalanceDecreaseSelfdestructBurn)
+ }
// We need to maintain account deletions explicitly (will remain
// set indefinitely). Note only the first occurred self-destruct
// event is tracked.
diff --git a/core/state/statedb_fuzz_test.go b/core/state/statedb_fuzz_test.go
index e88684552..fd74f6b0f 100644
--- a/core/state/statedb_fuzz_test.go
+++ b/core/state/statedb_fuzz_test.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
@@ -58,7 +59,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction
{
name: "SetBalance",
fn: func(a testAction, s *StateDB) {
- s.SetBalance(addr, big.NewInt(a.args[0]))
+ s.SetBalance(addr, big.NewInt(a.args[0]), tracing.BalanceChangeUnspecified)
},
args: make([]int64, 1),
},
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 39670772d..952c9aaa8 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/trie"
)
@@ -48,7 +49,7 @@ func TestUpdateLeaks(t *testing.T) {
// Update it with some accounts
for i := byte(0); i < 255; i++ {
addr := common.BytesToAddress([]byte{i})
- state.AddBalance(addr, big.NewInt(int64(11*i)))
+ state.AddBalance(addr, big.NewInt(int64(11*i)), tracing.BalanceChangeUnspecified)
state.SetNonce(addr, uint64(42*i))
if i%2 == 0 {
state.SetState(addr, common.BytesToHash([]byte{i, i, i}), common.BytesToHash([]byte{i, i, i, i}))
@@ -81,7 +82,7 @@ func TestIntermediateLeaks(t *testing.T) {
finalState, _ := New(common.Hash{}, NewDatabase(finalDb), nil)
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
- state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)))
+ state.SetBalance(addr, big.NewInt(int64(11*i)+int64(tweak)), tracing.BalanceChangeUnspecified)
state.SetNonce(addr, uint64(42*i+tweak))
if i%2 == 0 {
state.SetState(addr, common.Hash{i, i, i, 0}, common.Hash{})
@@ -157,7 +158,7 @@ func TestCopy(t *testing.T) {
for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
- obj.AddBalance(big.NewInt(int64(i)))
+ obj.AddBalance(big.NewInt(int64(i)), tracing.BalanceChangeUnspecified)
orig.updateStateObject(obj)
}
orig.Finalise(false)
@@ -174,9 +175,9 @@ func TestCopy(t *testing.T) {
copyObj := copy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
- origObj.AddBalance(big.NewInt(2 * int64(i)))
- copyObj.AddBalance(big.NewInt(3 * int64(i)))
- ccopyObj.AddBalance(big.NewInt(4 * int64(i)))
+ origObj.AddBalance(big.NewInt(2*int64(i)), tracing.BalanceChangeUnspecified)
+ copyObj.AddBalance(big.NewInt(3*int64(i)), tracing.BalanceChangeUnspecified)
+ ccopyObj.AddBalance(big.NewInt(4*int64(i)), tracing.BalanceChangeUnspecified)
orig.updateStateObject(origObj)
copy.updateStateObject(copyObj)
@@ -223,7 +224,7 @@ func TestCopyWithDirtyJournal(t *testing.T) {
// Fill up the initial states
for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
- obj.AddBalance(big.NewInt(int64(i)))
+ obj.AddBalance(big.NewInt(int64(i)), tracing.BalanceChangeUnspecified)
obj.data.Root = common.HexToHash("0xdeadbeef")
orig.updateStateObject(obj)
}
@@ -233,7 +234,7 @@ func TestCopyWithDirtyJournal(t *testing.T) {
// modify all in memory without finalizing
for i := byte(0); i < 255; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
- obj.SubBalance(big.NewInt(int64(i)))
+ obj.SubBalance(big.NewInt(int64(i)), tracing.BalanceChangeUnspecified)
orig.updateStateObject(obj)
}
cpy := orig.Copy()
@@ -267,7 +268,7 @@ func TestCopyObjectState(t *testing.T) {
// Fill up the initial states
for i := byte(0); i < 5; i++ {
obj := orig.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
- obj.AddBalance(big.NewInt(int64(i)))
+ obj.AddBalance(big.NewInt(int64(i)), tracing.BalanceChangeUnspecified)
obj.data.Root = common.HexToHash("0xdeadbeef")
orig.updateStateObject(obj)
}
@@ -328,14 +329,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
{
name: "SetBalance",
fn: func(a testAction, s *StateDB) {
- s.SetBalance(addr, big.NewInt(a.args[0]))
+ s.SetBalance(addr, big.NewInt(a.args[0]), tracing.BalanceChangeUnspecified)
},
args: make([]int64, 1),
},
{
name: "AddBalance",
fn: func(a testAction, s *StateDB) {
- s.AddBalance(addr, big.NewInt(a.args[0]))
+ s.AddBalance(addr, big.NewInt(a.args[0]), tracing.BalanceChangeUnspecified)
},
args: make([]int64, 1),
},
@@ -605,7 +606,7 @@ func TestTouchDelete(t *testing.T) {
s.state, _ = New(root, s.state.db, s.state.snaps)
snapshot := s.state.Snapshot()
- s.state.AddBalance(common.Address{}, new(big.Int))
+ s.state.AddBalance(common.Address{}, new(big.Int), tracing.BalanceChangeUnspecified)
if len(s.state.journal.dirties) != 1 {
t.Fatal("expected one dirty state object")
@@ -621,7 +622,7 @@ func TestTouchDelete(t *testing.T) {
func TestCopyOfCopy(t *testing.T) {
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
addr := common.HexToAddress("aaaa")
- state.SetBalance(addr, big.NewInt(42))
+ state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified)
if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
t.Fatalf("1st copy fail, expected 42, got %v", got)
@@ -644,9 +645,9 @@ func TestCopyCommitCopy(t *testing.T) {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, big.NewInt(42)) // Change the account trie
- state.SetCode(addr, []byte("hello")) // Change an external metadata
- state.SetState(addr, skey, sval) // Change the storage trie
+ state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie
+ state.SetCode(addr, []byte("hello")) // Change an external metadata
+ state.SetState(addr, skey, sval) // Change the storage trie
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
@@ -718,9 +719,9 @@ func TestCopyCopyCommitCopy(t *testing.T) {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, big.NewInt(42)) // Change the account trie
- state.SetCode(addr, []byte("hello")) // Change an external metadata
- state.SetState(addr, skey, sval) // Change the storage trie
+ state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie
+ state.SetCode(addr, []byte("hello")) // Change an external metadata
+ state.SetState(addr, skey, sval) // Change the storage trie
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
@@ -789,9 +790,9 @@ func TestCommitCopy(t *testing.T) {
skey1, skey2 := common.HexToHash("a1"), common.HexToHash("a2")
sval1, sval2 := common.HexToHash("b1"), common.HexToHash("b2")
- state.SetBalance(addr, big.NewInt(42)) // Change the account trie
- state.SetCode(addr, []byte("hello")) // Change an external metadata
- state.SetState(addr, skey1, sval1) // Change the storage trie
+ state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie
+ state.SetCode(addr, []byte("hello")) // Change an external metadata
+ state.SetState(addr, skey1, sval1) // Change the storage trie
if balance := state.GetBalance(addr); balance.Cmp(big.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
@@ -855,7 +856,7 @@ func TestDeleteCreateRevert(t *testing.T) {
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
addr := common.BytesToAddress([]byte("so"))
- state.SetBalance(addr, big.NewInt(1))
+ state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified)
root, _ := state.Commit(0, false)
state, _ = New(root, state.db, state.snaps)
@@ -865,7 +866,7 @@ func TestDeleteCreateRevert(t *testing.T) {
state.Finalise(true)
id := state.Snapshot()
- state.SetBalance(addr, big.NewInt(2))
+ state.SetBalance(addr, big.NewInt(2), tracing.BalanceChangeUnspecified)
state.RevertToSnapshot(id)
// Commit the entire state and make sure we don't crash and have the correct state
@@ -881,7 +882,7 @@ func TestDeleteResetBalance(t *testing.T) {
state, _ := New(common.Hash{}, NewDatabase(rawdb.NewMemoryDatabase()), nil)
addr := common.BytesToAddress([]byte("so"))
- state.SetBalance(addr, big.NewInt(1))
+ state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified)
state.SetNonce(addr, 10)
root, _ := state.Commit(0, false)
@@ -916,7 +917,6 @@ func TestDeleteResetBalance(t *testing.T) {
// the Commit operation fails with an error
// If we are missing trie nodes, we should not continue writing to the trie
func TestMissingTrieNodes(t *testing.T) {
-
// Create an initial state with a few accounts
memDb := rawdb.NewMemoryDatabase()
db := NewDatabase(memDb)
@@ -924,10 +924,10 @@ func TestMissingTrieNodes(t *testing.T) {
state, _ := New(common.Hash{}, db, nil)
addr := common.BytesToAddress([]byte("so"))
{
- state.SetBalance(addr, big.NewInt(1))
+ state.SetBalance(addr, big.NewInt(1), tracing.BalanceChangeUnspecified)
state.SetCode(addr, []byte{1, 2, 3})
a2 := common.BytesToAddress([]byte("another"))
- state.SetBalance(a2, big.NewInt(100))
+ state.SetBalance(a2, big.NewInt(100), tracing.BalanceChangeUnspecified)
state.SetCode(a2, []byte{1, 2, 4})
root, _ = state.Commit(0, false)
t.Logf("root: %x", root)
@@ -952,7 +952,7 @@ func TestMissingTrieNodes(t *testing.T) {
t.Errorf("expected %d, got %d", exp, got)
}
// Modify the state
- state.SetBalance(addr, big.NewInt(2))
+ state.SetBalance(addr, big.NewInt(2), tracing.BalanceChangeUnspecified)
root, err := state.Commit(0, false)
if err == nil {
t.Fatalf("expected error, got root :%x", root)
@@ -977,7 +977,7 @@ func TestStateDBAccessList(t *testing.T) {
t.Helper()
// convert to common.Address form
var addresses []common.Address
- var addressMap = make(map[common.Address]struct{})
+ addressMap := make(map[common.Address]struct{})
for _, astring := range astrings {
address := addr(astring)
addresses = append(addresses, address)
@@ -1000,10 +1000,10 @@ func TestStateDBAccessList(t *testing.T) {
if !state.AddressInAccessList(addr(addrString)) {
t.Fatalf("scope missing address/slots %v", addrString)
}
- var address = addr(addrString)
+ address := addr(addrString)
// convert to common.Hash form
var slots []common.Hash
- var slotMap = make(map[common.Hash]struct{})
+ slotMap := make(map[common.Hash]struct{})
for _, slotString := range slotStrings {
s := slot(slotString)
slots = append(slots, s)
diff --git a/core/state/sync_test.go b/core/state/sync_test.go
index 559f37044..3b8347341 100644
--- a/core/state/sync_test.go
+++ b/core/state/sync_test.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb"
@@ -60,7 +61,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *trie.Database, com
for i := byte(0); i < 96; i++ {
obj := state.GetOrNewStateObject(common.BytesToAddress([]byte{i}))
acc := &testAccount{address: common.BytesToAddress([]byte{i})}
- obj.AddBalance(big.NewInt(int64(11 * i)))
+ obj.AddBalance(big.NewInt(int64(11*i)), tracing.BalanceChangeUnspecified)
acc.balance = big.NewInt(int64(11 * i))
obj.SetNonce(uint64(42 * i))
acc.nonce = uint64(42 * i)
diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go
index cb0b67d7e..98f6bb092 100644
--- a/core/state/trie_prefetcher_test.go
+++ b/core/state/trie_prefetcher_test.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/tracing"
)
func filledStateDB() *StateDB {
@@ -33,9 +34,9 @@ func filledStateDB() *StateDB {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, big.NewInt(42)) // Change the account trie
- state.SetCode(addr, []byte("hello")) // Change an external metadata
- state.SetState(addr, skey, sval) // Change the storage trie
+ state.SetBalance(addr, big.NewInt(42), tracing.BalanceChangeUnspecified) // Change the account trie
+ state.SetCode(addr, []byte("hello")) // Change an external metadata
+ state.SetState(addr, skey, sval) // Change the storage trie
for i := 0; i < 100; i++ {
sk := common.BigToHash(big.NewInt(int64(i)))
state.SetState(addr, sk, sk) // Change the storage trie
diff --git a/core/state_prefetcher.go b/core/state_prefetcher.go
index 867b47db5..c258eee4f 100644
--- a/core/state_prefetcher.go
+++ b/core/state_prefetcher.go
@@ -63,7 +63,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
return
}
// Convert the transaction into an executable message and pre-cache its sender
- msg, err := tx.AsMessage(signer, header.BaseFee)
+ msg, err := TransactionToMessage(tx, signer, header.BaseFee)
if err != nil {
return // Also invalid block, bail out
}
@@ -85,7 +85,7 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
// precacheTransaction attempts to apply a transaction to the given state database
// and uses the input parameters for its environment. The goal is not to execute
// the transaction successfully, rather to warm up touched data slots.
-func precacheTransaction(msg types.Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
+func precacheTransaction(msg *Message, config *params.ChainConfig, gaspool *GasPool, statedb *state.StateDB, header *types.Header, evm *vm.EVM) error {
// Update the evm with the new transaction context.
evm.Reset(NewEVMTxContext(msg), statedb)
// Add addresses to access list if applicable
diff --git a/core/state_processor.go b/core/state_processor.go
index ef5a7441d..c8744e482 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/misc"
"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/vm"
"github.com/ethereum/go-ethereum/crypto"
@@ -67,7 +68,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
gp = new(GasPool).AddGas(block.GasLimit())
)
- var receipts = make([]*types.Receipt, 0)
+ receipts := make([]*types.Receipt, 0)
// Mutate the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
@@ -90,9 +91,6 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
posa, isPoSA := p.engine.(consensus.PoSA)
- bloomProcessors := NewAsyncReceiptBloomGenerator(txNum)
- defer bloomProcessors.Close()
-
// Iterate over and process the individual transactions
// System transactions should be placed at the end of a block
isMiko := p.config.IsMiko(blockNumber)
@@ -123,12 +121,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
vmenv.Context.CurrentTransaction = tx
// reset counter to start counting opcodes in new transaction
vmenv.Context.Counter = 0
- msg, err := tx.AsMessage(signer, header.BaseFee)
+ msg, err := TransactionToMessage(tx, signer, header.BaseFee)
if err != nil {
return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
statedb.SetTxContext(tx.Hash(), i)
- receipt, _, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv, bloomProcessors)
+ receipt, _, err := ApplyMessageWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
if err != nil {
return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
@@ -151,48 +149,63 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
// ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935.
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM) {
- msg := types.NewMessage(consensus.SystemAddress, ¶ms.HistoryStorageAddress, 0, common.Big0, 30_000_000, common.Big0, common.Big0, common.Big0, prevHash.Bytes(), nil, false, nil, nil, nil)
+ if tracer := vmenv.Config.Tracer; tracer != nil {
+ if tracer.OnSystemCallStart != nil {
+ tracer.OnSystemCallStart()
+ }
+ onSystemCallStart(tracer, vmenv.GetVMContext())
+ if tracer.OnSystemCallEnd != nil {
+ defer tracer.OnSystemCallEnd()
+ }
+ }
+
+ msg := NewMessage(consensus.SystemAddress, ¶ms.HistoryStorageAddress, 0, common.Big0, 30_000_000, common.Big0, common.Big0, common.Big0, prevHash.Bytes(), nil, false, nil, nil, nil)
vmenv.Reset(NewEVMTxContext(msg), vmenv.StateDB)
vmenv.StateDB.AddAddressToAccessList(params.HistoryStorageAddress)
- _, _, err := vmenv.Call(vm.AccountRef(msg.From()), *msg.To(), msg.Data(), 30_000_000, common.Big0)
+ _, _, err := vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.Big0)
if err != nil {
log.Error("Failed to store parent block hash in history storage contract", "err", err)
}
vmenv.StateDB.Finalise(true)
}
-func applyTransaction(
- msg types.Message,
+func ApplyMessageWithEVM(
+ msg *Message,
config *params.ChainConfig,
- bc ChainContext,
- author *common.Address,
gp *GasPool,
statedb *state.StateDB,
blockNumber *big.Int,
blockHash common.Hash,
tx *types.Transaction,
usedGas *uint64, evm *vm.EVM,
- receiptProcessor ReceiptProcessor,
-) (*types.Receipt, *ExecutionResult, error) {
+) (receipt *types.Receipt, result *ExecutionResult, err error) {
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil {
+ evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
+ if evm.Config.Tracer.OnTxEnd != nil {
+ defer func() {
+ evm.Config.Tracer.OnTxEnd(receipt, err)
+ }()
+ }
+ }
// Create a new context to be used in the EVM environment.
txContext := NewEVMTxContext(msg)
evm.Reset(txContext, statedb)
- from := msg.From()
+ from := msg.From
// Check if sender and recipient are blacklisted
- payer := msg.Payer()
+ payer := msg.Payer
// After the Venoki hardfork, all addresses now can submit transaction
if config.Consortium != nil && config.IsOdysseus(blockNumber) && !config.IsVenoki(blockNumber) {
contractAddr := config.BlacklistContractAddress
if state.IsAddressBlacklisted(statedb, contractAddr, &from) ||
- state.IsAddressBlacklisted(statedb, contractAddr, msg.To()) ||
+ state.IsAddressBlacklisted(statedb, contractAddr, msg.To) ||
state.IsAddressBlacklisted(statedb, contractAddr, &payer) {
return nil, nil, ErrAddressBlacklisted
}
}
// Apply the transaction to the current state (included in the env).
- result, err := ApplyMessage(evm, msg, gp)
+ result, err = ApplyMessage(evm, msg, gp)
if err != nil {
return nil, nil, err
}
@@ -208,7 +221,16 @@ func applyTransaction(
// Create a new receipt for the transaction, storing the intermediate root and gas used
// by the tx.
- receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
+ receipt = MakeReceipt(evm, result, statedb, blockNumber, blockHash, tx, *usedGas, root)
+
+ return receipt, result, err
+}
+
+// MakeReceipt generates the receipt object for a transaction given its execution result.
+func MakeReceipt(evm *vm.EVM, result *ExecutionResult, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas uint64, root []byte) *types.Receipt {
+ // Create a new receipt for the transaction, storing the intermediate root and gas used
+ // by the tx.
+ receipt := &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: usedGas}
if result.Failed() {
receipt.Status = types.ReceiptStatusFailed
} else {
@@ -223,19 +245,17 @@ func applyTransaction(
}
// If the transaction created a contract, store the creation address in the receipt.
- if msg.To() == nil {
+ if tx.To() == nil {
receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce())
}
// Set the receipt logs and create the bloom filter.
receipt.Logs = statedb.GetLogs(tx.Hash(), blockNumber.Uint64(), blockHash, evm.Context.Time)
+ receipt.Bloom = types.CreateReceiptBloom(receipt)
receipt.BlockHash = blockHash
receipt.BlockNumber = blockNumber
receipt.TransactionIndex = uint(statedb.TxIndex())
- // create the bloom filter
- receiptProcessor.Apply(receipt)
-
- return receipt, result, err
+ return receipt
}
// ApplyTransaction attempts to apply a transaction to the given state database
@@ -252,15 +272,22 @@ func ApplyTransaction(
tx *types.Transaction,
usedGas *uint64,
cfg vm.Config,
- receiptProcessors ReceiptProcessor,
publishEvents ...*vm.PublishEvent,
) (*types.Receipt, *ExecutionResult, error) {
- msg, err := tx.AsMessage(types.MakeSigner(config, header.Number), header.BaseFee)
+ msg, err := TransactionToMessage(tx, types.MakeSigner(config, header.Number), header.BaseFee)
if err != nil {
return nil, nil, err
}
// Create a new context to be used in the EVM environment
blockContext := NewEVMBlockContext(header, bc, author, publishEvents...)
vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg)
- return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv, receiptProcessors)
+ return ApplyMessageWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
+}
+
+func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) {
+ if tracer.OnSystemCallStartV2 != nil {
+ tracer.OnSystemCallStartV2(ctx)
+ } else if tracer.OnSystemCallStart != nil {
+ tracer.OnSystemCallStart()
+ }
}
diff --git a/core/state_transition.go b/core/state_transition.go
index c43bc37cf..1b25a8804 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -22,14 +22,14 @@ import (
"math"
"math/big"
- "github.com/ethereum/go-ethereum/consensus"
- "github.com/ethereum/go-ethereum/crypto/kzg4844"
-
"github.com/ethereum/go-ethereum/common"
cmath "github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/consensus"
+ "github.com/ethereum/go-ethereum/core/tracing"
"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/crypto/kzg4844"
"github.com/ethereum/go-ethereum/params"
)
@@ -56,7 +56,7 @@ The state transitioning model does all the necessary work to work out a valid ne
*/
type StateTransition struct {
gp *GasPool
- msg Message
+ msg *Message
gas uint64
gasPrice *big.Int
gasFeeCap *big.Int
@@ -68,31 +68,108 @@ type StateTransition struct {
evm *vm.EVM
}
-// Message represents a message sent to a contract.
-type Message interface {
- From() common.Address
- To() *common.Address
-
- GasPrice() *big.Int
- GasFeeCap() *big.Int
- GasTipCap() *big.Int
- Gas() uint64
- Value() *big.Int
-
- Nonce() uint64
- IsFake() bool
- Data() []byte
- AccessList() types.AccessList
- SetCodeAuthorizations() []types.SetCodeAuthorization
-
- // In legacy transaction, this is the same as From.
- // In sponsored transaction, this is the payer's
- // address recovered from the payer's signature.
- Payer() common.Address
- ExpiredTime() uint64
-
- BlobGasFeeCap() *big.Int
- BlobHashes() []common.Hash
+type Message struct {
+ To *common.Address
+ From common.Address
+ Nonce uint64
+ Amount *big.Int
+ GasLimit uint64
+ GasPrice *big.Int
+ GasFeeCap *big.Int
+ GasTipCap *big.Int
+ Data []byte
+ AccessList types.AccessList
+ AuthList []types.SetCodeAuthorization
+ SkipAccountChecks bool
+ Payer common.Address
+ ExpiredTime uint64
+ BlobGasFeeCap *big.Int
+ BlobHashes []common.Hash
+}
+
+// Create a new message with payer is the same as from, expired time = 0
+func NewMessage(
+ from common.Address,
+ to *common.Address,
+ nonce uint64,
+ amount *big.Int,
+ gasLimit uint64,
+ gasPrice, gasFeeCap, gasTipCap *big.Int,
+ data []byte,
+ accessList types.AccessList,
+ skipAccountChecks bool,
+ blobFeeCap *big.Int,
+ blobHashes []common.Hash,
+ authList []types.SetCodeAuthorization,
+) *Message {
+ return &Message{
+ From: from,
+ To: to,
+ Nonce: nonce,
+ Amount: amount,
+ GasLimit: gasLimit,
+ GasPrice: gasPrice,
+ GasFeeCap: gasFeeCap,
+ GasTipCap: gasTipCap,
+ Data: data,
+ AccessList: accessList,
+ AuthList: authList,
+ SkipAccountChecks: skipAccountChecks,
+ Payer: from,
+ ExpiredTime: 0,
+ BlobGasFeeCap: blobFeeCap,
+ BlobHashes: blobHashes,
+ }
+}
+
+// TransactionToMessage converts a transaction into a Message.
+func TransactionToMessage(tx *types.Transaction, signer types.Signer, baseFee *big.Int) (*Message, error) {
+ from, err := types.Sender(signer, tx)
+ if err != nil {
+ return nil, err
+ }
+ msg := NewMessage(
+ from,
+ tx.To(),
+ tx.Nonce(),
+ tx.Value(),
+ tx.Gas(),
+ new(big.Int).Set(tx.GasPrice()),
+ new(big.Int).Set(tx.GasFeeCap()),
+ new(big.Int).Set(tx.GasTipCap()),
+ tx.Data(),
+ tx.AccessList(),
+ false,
+ tx.BlobGasFeeCap(),
+ tx.BlobHashes(),
+ tx.SetCodeAuthorizations(),
+ )
+
+ // If expired time is set, set it to the message
+ if tx.ExpiredTime() != 0 {
+ msg.ExpiredTime = tx.ExpiredTime()
+ }
+
+ // If baseFee provided, set gasPrice to effectiveGasPrice.
+ if baseFee != nil {
+ msg.GasPrice = cmath.BigMin(msg.GasPrice.Add(msg.GasTipCap, baseFee), msg.GasFeeCap)
+ }
+
+ if tx.Type() == types.SponsoredTxType {
+ msg.Payer, err = types.Payer(signer, tx)
+ if err != nil {
+ return nil, err
+ }
+
+ if msg.Payer == msg.From {
+ // Reject sponsored transaction with identical payer and sender
+ return nil, types.ErrSamePayerSenderSponsoredTx
+ }
+ return msg, nil
+ } else {
+ msg.Payer = msg.From
+ return msg, nil
+ }
}
// ExecutionResult includes all output after executing given evm
@@ -204,16 +281,16 @@ func toWordSize(size uint64) uint64 {
}
// NewStateTransition initialises and returns a new state transition object.
-func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition {
+func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
return &StateTransition{
gp: gp,
evm: evm,
msg: msg,
- gasPrice: msg.GasPrice(),
- gasFeeCap: msg.GasFeeCap(),
- gasTipCap: msg.GasTipCap(),
- value: msg.Value(),
- data: msg.Data(),
+ gasPrice: msg.GasPrice,
+ gasFeeCap: msg.GasFeeCap,
+ gasTipCap: msg.GasTipCap,
+ value: msg.Amount,
+ data: msg.Data,
state: evm.StateDB,
}
}
@@ -225,21 +302,21 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
// the gas used (which includes gas refunds) and an error if it failed. An error always
// indicates a core error meaning that the message would always fail for that particular
// state and would never be accepted within a block.
-func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) (*ExecutionResult, error) {
+func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
return NewStateTransition(evm, msg, gp).TransitionDb()
}
// to returns the recipient of the message.
func (st *StateTransition) to() common.Address {
- if st.msg == nil || st.msg.To() == nil /* contract creation */ {
+ if st.msg == nil || st.msg.To == nil /* contract creation */ {
return common.Address{}
}
- return *st.msg.To()
+ return *st.msg.To
}
func (st *StateTransition) buyGas() error {
msg := st.msg
- gas := new(big.Int).SetUint64(msg.Gas())
+ gas := new(big.Int).SetUint64(msg.GasLimit)
// In transaction types other than dynamic fee transaction,
// effectiveGasFee is the same as maxGasFee. In dynamic fee
// transaction, st.gasPrice is the already calculated gas
@@ -258,22 +335,22 @@ func (st *StateTransition) buyGas() error {
balanceCheck = new(big.Int).Mul(gas, st.gasPrice)
}
- if msg.Payer() != msg.From() {
+ if msg.Payer != msg.From {
// This is sponsored transaction, check gas fee with payer's balance and msg.value with sender's balance
- if have, want := st.state.GetBalance(msg.Payer()), balanceCheck; have.Cmp(want) < 0 {
- return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientPayerFunds, msg.Payer().Hex(), have, want)
+ if have, want := st.state.GetBalance(msg.Payer), balanceCheck; have.Cmp(want) < 0 {
+ return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientPayerFunds, msg.Payer.Hex(), have, want)
}
- if have, want := st.state.GetBalance(msg.From()), st.value; have.Cmp(want) < 0 {
- return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientSenderFunds, msg.From().Hex(), have, want)
+ if have, want := st.state.GetBalance(msg.From), st.value; have.Cmp(want) < 0 {
+ return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientSenderFunds, msg.From.Hex(), have, want)
}
} else {
// include the logic for blob here
- if msg.BlobHashes() != nil {
+ if msg.BlobHashes != nil {
if blobGas := st.blobGasUsed(); blobGas > 0 {
// Check that the user has enough funds to cover blobGasUsed * tx.BlobGasFeeCap
blobBalanceCheck := new(big.Int).SetUint64(blobGas)
- blobBalanceCheck.Mul(blobBalanceCheck, msg.BlobGasFeeCap())
+ blobBalanceCheck.Mul(blobBalanceCheck, msg.BlobGasFeeCap)
balanceCheck.Add(balanceCheck, blobBalanceCheck)
// Pay for blobGasUsed * actual blob fee
@@ -283,53 +360,57 @@ func (st *StateTransition) buyGas() error {
}
}
balanceCheck.Add(balanceCheck, st.value)
- if have, want := st.state.GetBalance(msg.From()), balanceCheck; have.Cmp(want) < 0 {
- return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, msg.From().Hex(), have, want)
+ if have, want := st.state.GetBalance(msg.From), balanceCheck; have.Cmp(want) < 0 {
+ return fmt.Errorf("%w: address %v have %v want %v", ErrInsufficientFunds, msg.From.Hex(), have, want)
}
}
- if err := st.gp.SubGas(msg.Gas()); err != nil {
+ if err := st.gp.SubGas(msg.GasLimit); err != nil {
return err
}
- st.gas += msg.Gas()
- st.initialGas = msg.Gas()
+ if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil {
+ st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
+ }
+ st.gas += msg.GasLimit
+
+ st.initialGas = msg.GasLimit
// Transfer blob gas fee to Ronin treasury address. If the blob tx fails,
// the fee will not be refund.
//
// Unless the Ronin treasury address is specified, the blob fee amount will be burned.
if st.evm.ChainConfig().RoninTreasuryAddress != nil && blobFee != nil && blobFee.Cmp(common.Big0) == 1 {
- st.state.AddBalance(*st.evm.ChainConfig().RoninTreasuryAddress, blobFee)
+ st.state.AddBalance(*st.evm.ChainConfig().RoninTreasuryAddress, blobFee, tracing.BalanceIncreaseGasReturn)
}
// Subtract the gas fee from balance of the fee payer,
// the msg.value is transfered to the recipient in later step.
- st.state.SubBalance(msg.Payer(), effectiveGasFee)
+ st.state.SubBalance(msg.Payer, effectiveGasFee, tracing.BalanceDecreaseGasBuy)
return nil
}
func (st *StateTransition) preCheck() error {
msg := st.msg
// Only check transactions that are not fake
- if !msg.IsFake() {
+ if !msg.SkipAccountChecks {
// Make sure this transaction's nonce is correct.
- stNonce := st.state.GetNonce(msg.From())
- if msgNonce := msg.Nonce(); stNonce < msgNonce {
+ stNonce := st.state.GetNonce(msg.From)
+ if msgNonce := msg.Nonce; stNonce < msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooHigh,
- msg.From().Hex(), msgNonce, stNonce)
+ msg.From.Hex(), msgNonce, stNonce)
} else if stNonce > msgNonce {
return fmt.Errorf("%w: address %v, tx: %d state: %d", ErrNonceTooLow,
- msg.From().Hex(), msgNonce, stNonce)
+ msg.From.Hex(), msgNonce, stNonce)
} else if stNonce+1 < stNonce {
return fmt.Errorf("%w: address %v, nonce: %d", ErrNonceMax,
- msg.From().Hex(), stNonce)
+ msg.From.Hex(), stNonce)
}
// Make sure the sender is an EOA
- code := st.state.GetCode(msg.From())
+ code := st.state.GetCode(msg.From)
_, delegated := types.ParseDelegation(code)
if len(code) > 0 && !delegated {
- return fmt.Errorf("%w: address %v, len(code): %d", ErrSenderNoEOA, msg.From().Hex(), len(code))
+ return fmt.Errorf("%w: address %v, len(code): %d", ErrSenderNoEOA, msg.From.Hex(), len(code))
}
}
// Make sure that transaction gasFeeCap is greater than the baseFee (post london)
@@ -338,47 +419,47 @@ func (st *StateTransition) preCheck() error {
if !st.evm.Config.NoBaseFee || st.gasFeeCap.BitLen() > 0 || st.gasTipCap.BitLen() > 0 {
if l := st.gasFeeCap.BitLen(); l > 256 {
return fmt.Errorf("%w: address %v, maxFeePerGas bit length: %d", ErrFeeCapVeryHigh,
- msg.From().Hex(), l)
+ msg.From.Hex(), l)
}
if l := st.gasTipCap.BitLen(); l > 256 {
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas bit length: %d", ErrTipVeryHigh,
- msg.From().Hex(), l)
+ msg.From.Hex(), l)
}
if st.gasFeeCap.Cmp(st.gasTipCap) < 0 {
return fmt.Errorf("%w: address %v, maxPriorityFeePerGas: %s, maxFeePerGas: %s", ErrTipAboveFeeCap,
- msg.From().Hex(), st.gasTipCap, st.gasFeeCap)
+ msg.From.Hex(), st.gasTipCap, st.gasFeeCap)
}
// This will panic if baseFee is nil, but basefee presence is verified
// as part of header validation.
if st.gasFeeCap.Cmp(st.evm.Context.BaseFee) < 0 {
return fmt.Errorf("%w: address %v, maxFeePerGas: %s baseFee: %s", ErrFeeCapTooLow,
- msg.From().Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
+ msg.From.Hex(), st.gasFeeCap, st.evm.Context.BaseFee)
}
}
}
// Check expired time, gas fee cap and tip cap in sponsored transaction
- if msg.Payer() != msg.From() {
- expiredTime := msg.ExpiredTime()
+ if msg.Payer != msg.From {
+ expiredTime := msg.ExpiredTime
if expiredTime != 0 && expiredTime <= st.evm.Context.Time {
return fmt.Errorf("%w: expiredTime: %d, blockTime: %d", ErrExpiredSponsoredTx,
- msg.ExpiredTime(), st.evm.Context.Time)
+ msg.ExpiredTime, st.evm.Context.Time)
}
// Before Venoki (base fee is 0), we have the rule that these 2 fields must be the same
if !st.evm.ChainConfig().IsVenoki(st.evm.Context.BlockNumber) {
- if msg.GasTipCap().Cmp(msg.GasFeeCap()) != 0 {
+ if msg.GasTipCap.Cmp(msg.GasFeeCap) != 0 {
return ErrDifferentFeeCapTipCap
}
}
}
- blobHashes := msg.BlobHashes()
+ blobHashes := msg.BlobHashes
if blobHashes != nil {
// The to field of a blob tx type is mandatory, and a `BlobTx` transaction internally
// has it as a non-nillable value, so any msg derived from blob transaction has it non-nil.
// However, messages created through RPC (eth_call) don't have this restriction.
- if msg.To() == nil {
+ if msg.To == nil {
return ErrBlobTxCreate
}
if len(blobHashes) == 0 {
@@ -395,25 +476,25 @@ func (st *StateTransition) preCheck() error {
if st.evm.ChainConfig().IsCancun(st.evm.Context.BlockNumber) {
if st.blobGasUsed() > 0 {
// Skip the checks if gas fields are zero and blobBaseFee was explicitly disabled (eth_call)
- skipCheck := st.evm.Config.NoBaseFee && msg.BlobGasFeeCap().BitLen() == 0
+ skipCheck := st.evm.Config.NoBaseFee && msg.BlobGasFeeCap.BitLen() == 0
if !skipCheck {
// This will panic if blobBaseFee is nil, but blobBaseFee presence
// is verified as part of header validation.
- if msg.BlobGasFeeCap().Cmp(st.evm.Context.BlobBaseFee) < 0 {
+ if msg.BlobGasFeeCap.Cmp(st.evm.Context.BlobBaseFee) < 0 {
return fmt.Errorf("%w: address %v blobGasFeeCap: %v, blobBaseFee: %v", ErrBlobFeeCapTooLow,
- msg.From().Hex(), msg.BlobGasFeeCap(), st.evm.Context.BlobBaseFee)
+ msg.From.Hex(), msg.BlobGasFeeCap, st.evm.Context.BlobBaseFee)
}
}
}
}
// Check that EIP-7702 authorization list signatures are well formed.
- if msg.SetCodeAuthorizations() != nil {
- if msg.To() == nil {
- return fmt.Errorf("%w (sender %v)", ErrSetCodeTxCreate, msg.From())
+ if msg.AuthList != nil {
+ if msg.To == nil {
+ return fmt.Errorf("%w (sender %v)", ErrSetCodeTxCreate, msg.From)
}
- if len(msg.SetCodeAuthorizations()) == 0 {
- return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From())
+ if len(msg.AuthList) == 0 {
+ return fmt.Errorf("%w (sender %v)", ErrEmptyAuthList, msg.From)
}
}
@@ -450,27 +531,15 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, err
}
- if tracer := st.evm.Config.Tracer; tracer != nil {
- var payer *common.Address
- if st.msg.From() != st.msg.Payer() {
- payerAddr := st.msg.Payer()
- payer = &payerAddr
- }
- tracer.CaptureTxStart(st.initialGas, payer)
- defer func() {
- tracer.CaptureTxEnd(st.gas)
- }()
- }
-
msg := st.msg
- sender := vm.AccountRef(msg.From())
+ sender := vm.AccountRef(msg.From)
rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber)
- contractCreation := msg.To() == nil
+ contractCreation := msg.To == nil
floorDataGas := uint64(0)
// Check clauses 4-5, subtract intrinsic gas if everything is correct
if !st.evm.Config.IsSystemTransaction {
- gas, err := IntrinsicGas(st.data, st.msg.AccessList(), st.msg.SetCodeAuthorizations(), contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
+ gas, err := IntrinsicGas(st.data, st.msg.AccessList, st.msg.AuthList, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai)
if err != nil {
return nil, err
}
@@ -479,20 +548,23 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}
// Gas limit suffices for the floor data cost (EIP-7623)
if rules.IsKotaro {
- floorDataGas, err = FloorDataGas(msg.Data())
+ floorDataGas, err = FloorDataGas(msg.Data)
if err != nil {
return nil, err
}
- if msg.Gas() < floorDataGas {
- return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.Gas(), floorDataGas)
+ if msg.GasLimit < floorDataGas {
+ return nil, fmt.Errorf("%w: have %d, want %d", ErrFloorDataGas, msg.GasLimit, floorDataGas)
}
}
+ if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
+ t.OnGasChange(st.gas, st.gas-gas, tracing.GasChangeTxIntrinsicGas)
+ }
st.gas -= gas
}
// Check clause 6
- if msg.Value().Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From(), msg.Value()) {
- return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From().Hex())
+ if msg.Amount.Sign() > 0 && !st.evm.Context.CanTransfer(st.state, msg.From, msg.Amount) {
+ return nil, fmt.Errorf("%w: address %v", ErrInsufficientFundsForTransfer, msg.From.Hex())
}
// Check whether the init code size has been exceeded.
@@ -503,7 +575,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
- st.state.Prepare(rules, msg.From(), st.evm.Context.Coinbase, msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
+ st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList)
var (
ret []byte
@@ -513,11 +585,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
ret, _, st.gas, vmerr = st.evm.Create(sender, st.data, st.gas, st.value)
} else {
// Increment the nonce for the next transaction.
- st.state.SetNonce(msg.From(), st.state.GetNonce(msg.From())+1)
+ st.state.SetNonce(msg.From, st.state.GetNonce(msg.From)+1)
// Apply EIP-7702 authorizations.
- if msg.SetCodeAuthorizations() != nil {
- for _, auth := range msg.SetCodeAuthorizations() {
+ if msg.AuthList != nil {
+ for _, auth := range msg.AuthList {
// Note errors are ignored, we simply skip invalid authorizations here.
_ = st.applyAuthorization(&auth)
}
@@ -528,7 +600,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// the account was deployed during this transaction. To handle correctly,
// simply wait until the final state of delegations is determined before
// performing the resolution and warming.
- if addr, ok := types.ParseDelegation(st.state.GetCode(*msg.To())); ok {
+ if addr, ok := types.ParseDelegation(st.state.GetCode(*msg.To)); ok {
st.state.AddAddressToAccessList(addr)
}
@@ -546,7 +618,11 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
if rules.IsKotaro {
// After EIP-7623: Data-heavy transactions pay the floor gas.
if st.gasUsed() < floorDataGas {
+ prev := st.gas
st.gas = st.initialGas - floorDataGas
+ if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
+ t.OnGasChange(prev, st.gas, tracing.GasChangeTxDataFloor)
+ }
}
if peakGasUsed < floorDataGas {
peakGasUsed = floorDataGas
@@ -562,9 +638,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
// if currentBlock is ConsortiumV2 then add balance to system address
newEffectiveTip := new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), effectiveTip)
if st.evm.ChainConfig().IsConsortiumV2(st.evm.Context.BlockNumber) {
- st.state.AddBalance(consensus.SystemAddress, newEffectiveTip)
+ st.state.AddBalance(consensus.SystemAddress, newEffectiveTip, tracing.BalanceIncreaseRewardTransactionFee)
} else {
- st.state.AddBalance(st.evm.Context.Coinbase, newEffectiveTip)
+ st.state.AddBalance(st.evm.Context.Coinbase, newEffectiveTip, tracing.BalanceIncreaseRewardTransactionFee)
}
// After Venoki the base fee is non-zero and the fee is transferred to treasury
@@ -572,7 +648,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
treasuryAddress := st.evm.ChainConfig().RoninTreasuryAddress
if treasuryAddress != nil {
fee := new(big.Int).Mul(big.NewInt(int64(st.gasUsed())), st.evm.Context.BaseFee)
- st.state.AddBalance(*treasuryAddress, fee)
+ st.state.AddBalance(*treasuryAddress, fee, tracing.BalanceIncreaseRewardTransactionFee)
}
}
}
@@ -656,6 +732,10 @@ func (st *StateTransition) calcRefund() uint64 {
if refund > st.state.GetRefund() {
refund = st.state.GetRefund()
}
+
+ if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 {
+ st.evm.Config.Tracer.OnGasChange(st.gas, st.gas+refund, tracing.GasChangeTxRefunds)
+ }
return refund
}
@@ -664,7 +744,11 @@ func (st *StateTransition) calcRefund() uint64 {
func (st *StateTransition) returnGas() {
// Return ETH for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
- st.state.AddBalance(st.msg.Payer(), remaining)
+ st.state.AddBalance(st.msg.Payer, remaining, tracing.BalanceIncreaseGasReturn)
+
+ if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gas > 0 {
+ st.evm.Config.Tracer.OnGasChange(st.gas, 0, tracing.GasChangeTxLeftOverReturned)
+ }
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
@@ -678,5 +762,5 @@ func (st *StateTransition) gasUsed() uint64 {
// blobGasUsed returns the amount of blob gas used by the message.
func (st *StateTransition) blobGasUsed() uint64 {
- return uint64(len(st.msg.BlobHashes()) * params.BlobTxBlobGasPerBlob)
+ return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob)
}
diff --git a/core/tracing/gen_balance_change_reason_stringer.go b/core/tracing/gen_balance_change_reason_stringer.go
new file mode 100644
index 000000000..8445f230d
--- /dev/null
+++ b/core/tracing/gen_balance_change_reason_stringer.go
@@ -0,0 +1,39 @@
+// Code generated by "stringer -type=BalanceChangeReason -trimprefix=BalanceChange -output gen_balance_change_reason_stringer.go"; DO NOT EDIT.
+
+package tracing
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[BalanceChangeUnspecified-0]
+ _ = x[BalanceIncreaseRewardMineUncle-1]
+ _ = x[BalanceIncreaseRewardMineBlock-2]
+ _ = x[BalanceIncreaseWithdrawal-3]
+ _ = x[BalanceIncreaseGenesisBalance-4]
+ _ = x[BalanceIncreaseRewardTransactionFee-5]
+ _ = x[BalanceDecreaseGasBuy-6]
+ _ = x[BalanceIncreaseGasReturn-7]
+ _ = x[BalanceIncreaseDaoContract-8]
+ _ = x[BalanceDecreaseDaoAccount-9]
+ _ = x[BalanceChangeTransfer-10]
+ _ = x[BalanceChangeTouchAccount-11]
+ _ = x[BalanceIncreaseSelfdestruct-12]
+ _ = x[BalanceDecreaseSelfdestruct-13]
+ _ = x[BalanceDecreaseSelfdestructBurn-14]
+ _ = x[BalanceChangeRevert-15]
+ _ = x[BalanceDecreaseSystemAddress-16]
+}
+
+const _BalanceChangeReason_name = "UnspecifiedBalanceIncreaseRewardMineUncleBalanceIncreaseRewardMineBlockBalanceIncreaseWithdrawalBalanceIncreaseGenesisBalanceBalanceIncreaseRewardTransactionFeeBalanceDecreaseGasBuyBalanceIncreaseGasReturnBalanceIncreaseDaoContractBalanceDecreaseDaoAccountTransferTouchAccountBalanceIncreaseSelfdestructBalanceDecreaseSelfdestructBalanceDecreaseSelfdestructBurnRevertBalanceDecreaseSystemAddress"
+
+var _BalanceChangeReason_index = [...]uint16{0, 11, 41, 71, 96, 125, 160, 181, 205, 231, 256, 264, 276, 303, 330, 361, 367, 395}
+
+func (i BalanceChangeReason) String() string {
+ if i >= BalanceChangeReason(len(_BalanceChangeReason_index)-1) {
+ return "BalanceChangeReason(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _BalanceChangeReason_name[_BalanceChangeReason_index[i]:_BalanceChangeReason_index[i+1]]
+}
diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go
new file mode 100644
index 000000000..555619727
--- /dev/null
+++ b/core/tracing/hooks.go
@@ -0,0 +1,379 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+// Package tracing defines hooks for 'live tracing' of block processing and transaction
+// execution. Here we define the low-level [Hooks] object that carries hooks which are
+// invoked by the go-ethereum core at various points in the state transition.
+//
+// To create a tracer that can be invoked with Geth, you need to register it using
+// [github.com/ethereum/go-ethereum/eth/tracers.LiveDirectory.Register].
+//
+// See https://geth.ethereum.org/docs/developers/evm-tracing/live-tracing for a tutorial.
+package tracing
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
+)
+
+// OpContext provides the context at which the opcode is being
+// executed in, including the memory, stack and various contract-level information.
+type OpContext interface {
+ MemoryData() []byte
+ StackData() []uint256.Int
+ Caller() common.Address
+ Address() common.Address
+ CallValue() *uint256.Int
+ CallInput() []byte
+}
+
+// StateDB gives tracers access to the whole state.
+type StateDB interface {
+ GetBalance(common.Address) *big.Int
+ GetNonce(common.Address) uint64
+ GetCode(common.Address) []byte
+ GetCodeHash(common.Address) common.Hash
+ GetState(common.Address, common.Hash) common.Hash
+ GetTransientState(common.Address, common.Hash) common.Hash
+ Exist(common.Address) bool
+ GetRefund() uint64
+}
+
+// VMContext provides the context for the EVM execution.
+type VMContext struct {
+ Coinbase common.Address
+ BlockNumber *big.Int
+ Time uint64
+ // Effective tx gas price
+ GasPrice *big.Int
+ ChainConfig *params.ChainConfig
+ StateDB StateDB
+}
+
+// BlockEvent is emitted upon tracing an incoming block.
+// It contains the block as well as consensus related information.
+type BlockEvent struct {
+ Block *types.Block
+ TD *big.Int
+ Finalized *types.Header
+}
+
+type (
+ /*
+ - VM events -
+ */
+
+ // TxStartHook is called before the execution of a transaction starts.
+ // Call simulations don't come with a valid signature. `from` field
+ // to be used for address of the caller.
+ TxStartHook = func(vm *VMContext, tx *types.Transaction, from common.Address)
+
+ // TxEndHook is called after the execution of a transaction ends.
+ TxEndHook = func(receipt *types.Receipt, err error)
+
+ // EnterHook is invoked when the processing of a message starts.
+ //
+ // Take note that EnterHook, when in the context of a live tracer, can be invoked
+ // outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
+ // see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
+ EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64)
+
+ // ExitHook is invoked when the processing of a message ends.
+ // `revert` is true when there was an error during the execution.
+ // Exceptionally, before the homestead hardfork a contract creation that
+ // ran out of gas when attempting to persist the code to database did not
+ // count as a call failure and did not cause a revert of the call. This will
+ // be indicated by `reverted == false` and `err == ErrCodeStoreOutOfGas`.
+ //
+ // Take note that ExitHook, when in the context of a live tracer, can be invoked
+ // outside of the `OnTxStart` and `OnTxEnd` hooks when dealing with system calls,
+ // see [OnSystemCallStartHook] and [OnSystemCallEndHook] for more information.
+ ExitHook = func(depth int, output []byte, gasUsed uint64, err error, reverted bool)
+
+ // OpcodeHook is invoked just prior to the execution of an opcode.
+ OpcodeHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, rData []byte, depth int, err error)
+
+ // FaultHook is invoked when an error occurs during the execution of an opcode.
+ FaultHook = func(pc uint64, op byte, gas, cost uint64, scope OpContext, depth int, err error)
+
+ // GasChangeHook is invoked when the gas changes.
+ GasChangeHook = func(old, new uint64, reason GasChangeReason)
+
+ /*
+ - Chain events -
+ */
+
+ // BlockchainInitHook is called when the blockchain is initialized.
+ BlockchainInitHook = func(chainConfig *params.ChainConfig)
+
+ // CloseHook is called when the blockchain closes.
+ CloseHook = func()
+
+ // BlockStartHook is called before executing `block`.
+ // `td` is the total difficulty prior to `block`.
+ BlockStartHook = func(event BlockEvent)
+
+ // BlockEndHook is called after executing a block.
+ BlockEndHook = func(err error)
+
+ // SkippedBlockHook indicates a block was skipped during processing
+ // due to it being known previously. This can happen e.g. when recovering
+ // from a crash.
+ SkippedBlockHook = func(event BlockEvent)
+
+ // GenesisBlockHook is called when the genesis block is being processed.
+ GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc)
+
+ // OnSystemCallStartHook is called when a system call is about to be executed. Today,
+ // this hook is invoked when the EIP-4788 system call is about to be executed to set the
+ // beacon block root.
+ //
+ // After this hook, the EVM call tracing will happened as usual so you will receive a `OnEnter/OnExit`
+ // as well as state hooks between this hook and the `OnSystemCallEndHook`.
+ //
+ // Note that system call happens outside normal transaction execution, so the `OnTxStart/OnTxEnd` hooks
+ // will not be invoked.
+ OnSystemCallStartHook = func()
+
+ // OnSystemCallStartHookV2 is called when a system call is about to be executed. Refer
+ // to `OnSystemCallStartHook` for more information.
+ OnSystemCallStartHookV2 = func(vm *VMContext)
+
+ // OnSystemCallEndHook is called when a system call has finished executing. Today,
+ // this hook is invoked when the EIP-4788 system call is about to be executed to set the
+ // beacon block root.
+ OnSystemCallEndHook = func()
+
+ /*
+ - State events -
+ */
+
+ // BalanceChangeHook is called when the balance of an account changes.
+ BalanceChangeHook = func(addr common.Address, prev, new *big.Int, reason BalanceChangeReason)
+
+ // NonceChangeHook is called when the nonce of an account changes.
+ NonceChangeHook = func(addr common.Address, prev, new uint64)
+
+ // NonceChangeHookV2 is called when the nonce of an account changes.
+ NonceChangeHookV2 = func(addr common.Address, prev, new uint64, reason NonceChangeReason)
+
+ // CodeChangeHook is called when the code of an account changes.
+ CodeChangeHook = func(addr common.Address, prevCodeHash common.Hash, prevCode []byte, codeHash common.Hash, code []byte)
+
+ // StorageChangeHook is called when the storage of an account changes.
+ StorageChangeHook = func(addr common.Address, slot common.Hash, prev, new common.Hash)
+
+ // LogHook is called when a log is emitted.
+ LogHook = func(log *types.Log)
+
+ // BlockHashReadHook is called when EVM reads the blockhash of a block.
+ BlockHashReadHook = func(blockNumber uint64, hash common.Hash)
+)
+
+type Hooks struct {
+ // VM events
+ OnTxStart TxStartHook
+ OnTxEnd TxEndHook
+ OnEnter EnterHook
+ OnExit ExitHook
+ OnOpcode OpcodeHook
+ OnFault FaultHook
+ OnGasChange GasChangeHook
+ // Chain events
+ OnBlockchainInit BlockchainInitHook
+ OnClose CloseHook
+ OnBlockStart BlockStartHook
+ OnBlockEnd BlockEndHook
+ OnSkippedBlock SkippedBlockHook
+ OnGenesisBlock GenesisBlockHook
+ OnSystemCallStart OnSystemCallStartHook
+ OnSystemCallStartV2 OnSystemCallStartHookV2
+ OnSystemCallEnd OnSystemCallEndHook
+ // State events
+ OnBalanceChange BalanceChangeHook
+ OnNonceChange NonceChangeHook
+ OnNonceChangeV2 NonceChangeHookV2
+ OnCodeChange CodeChangeHook
+ OnStorageChange StorageChangeHook
+ OnLog LogHook
+ // Block hash read
+ OnBlockHashRead BlockHashReadHook
+}
+
+// BalanceChangeReason is used to indicate the reason for a balance change, useful
+// for tracing and reporting.
+type BalanceChangeReason byte
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=BalanceChangeReason -trimprefix=BalanceChange -output gen_balance_change_reason_stringer.go
+
+const (
+ BalanceChangeUnspecified BalanceChangeReason = 0
+
+ // Issuance
+ // BalanceIncreaseRewardMineUncle is a reward for mining an uncle block.
+ BalanceIncreaseRewardMineUncle BalanceChangeReason = 1
+ // BalanceIncreaseRewardMineBlock is a reward for mining a block.
+ BalanceIncreaseRewardMineBlock BalanceChangeReason = 2
+ // BalanceIncreaseWithdrawal is ether withdrawn from the beacon chain.
+ BalanceIncreaseWithdrawal BalanceChangeReason = 3
+ // BalanceIncreaseGenesisBalance is ether allocated at the genesis block.
+ BalanceIncreaseGenesisBalance BalanceChangeReason = 4
+
+ // Transaction fees
+ // BalanceIncreaseRewardTransactionFee is the transaction tip increasing block builder's balance.
+ BalanceIncreaseRewardTransactionFee BalanceChangeReason = 5
+ // BalanceDecreaseGasBuy is spent to purchase gas for execution a transaction.
+ // Part of this gas will be burnt as per EIP-1559 rules.
+ BalanceDecreaseGasBuy BalanceChangeReason = 6
+ // BalanceIncreaseGasReturn is ether returned for unused gas at the end of execution.
+ BalanceIncreaseGasReturn BalanceChangeReason = 7
+
+ // DAO fork
+ // BalanceIncreaseDaoContract is ether sent to the DAO refund contract.
+ BalanceIncreaseDaoContract BalanceChangeReason = 8
+ // BalanceDecreaseDaoAccount is ether taken from a DAO account to be moved to the refund contract.
+ BalanceDecreaseDaoAccount BalanceChangeReason = 9
+
+ // BalanceChangeTransfer is ether transferred via a call.
+ // it is a decrease for the sender and an increase for the recipient.
+ BalanceChangeTransfer BalanceChangeReason = 10
+ // BalanceChangeTouchAccount is a transfer of zero value. It is only there to
+ // touch-create an account.
+ BalanceChangeTouchAccount BalanceChangeReason = 11
+
+ // BalanceIncreaseSelfdestruct is added to the recipient as indicated by a selfdestructing account.
+ BalanceIncreaseSelfdestruct BalanceChangeReason = 12
+ // BalanceDecreaseSelfdestruct is deducted from a contract due to self-destruct.
+ BalanceDecreaseSelfdestruct BalanceChangeReason = 13
+ // BalanceDecreaseSelfdestructBurn is ether that is sent to an already self-destructed
+ // account within the same tx (captured at end of tx).
+ // Note it doesn't account for a self-destruct which appoints itself as recipient.
+ BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14
+
+ // BalanceChangeRevert is emitted when the balance is reverted back to a previous value due to call failure.
+ // It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
+ BalanceChangeRevert BalanceChangeReason = 15
+
+ // Consortium consensus
+ // BalanceDecreaseSystemAddress is emitted when the balance of a system address is transferred to the
+ // coinbase and then set to 0.
+ BalanceDecreaseSystemAddress BalanceChangeReason = 16
+)
+
+// GasChangeReason is used to indicate the reason for a gas change, useful
+// for tracing and reporting.
+//
+// There is essentially two types of gas changes, those that can be emitted once per transaction
+// and those that can be emitted on a call basis, so possibly multiple times per transaction.
+//
+// They can be recognized easily by their name, those that start with `GasChangeTx` are emitted
+// once per transaction, while those that start with `GasChangeCall` are emitted on a call basis.
+type GasChangeReason byte
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=GasChangeReason -trimprefix=GasChange -output gen_gas_change_reason_stringer.go
+
+const (
+ GasChangeUnspecified GasChangeReason = 0
+
+ // GasChangeTxInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only
+ // one such gas change per transaction.
+ GasChangeTxInitialBalance GasChangeReason = 1
+ // GasChangeTxIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is
+ // always exactly one of those per transaction.
+ GasChangeTxIntrinsicGas GasChangeReason = 2
+ // GasChangeTxRefunds is the sum of all refunds which happened during the tx execution (e.g. storage slot being cleared)
+ // this generates an increase in gas. There is at most one of such gas change per transaction.
+ GasChangeTxRefunds GasChangeReason = 3
+ // GasChangeTxLeftOverReturned is the amount of gas left over at the end of transaction's execution that will be returned
+ // to the chain. This change will always be a negative change as we "drain" left over gas towards 0. If there was no gas
+ // left at the end of execution, no such even will be emitted. The returned gas's value in Wei is returned to caller.
+ // There is at most one of such gas change per transaction.
+ GasChangeTxLeftOverReturned GasChangeReason = 4
+
+ // GasChangeCallInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call. There is only
+ // one such gas change per call.
+ GasChangeCallInitialBalance GasChangeReason = 5
+ // GasChangeCallLeftOverReturned is the amount of gas left over that will be returned to the caller, this change will always
+ // be a negative change as we "drain" left over gas towards 0. If there was no gas left at the end of execution, no such even
+ // will be emitted.
+ GasChangeCallLeftOverReturned GasChangeReason = 6
+ // GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the call after the child call execution it
+ // executed completed. This value is always positive as we are giving gas back to the you, the left over gas of the child.
+ // If there was no gas left to be refunded, no such even will be emitted.
+ GasChangeCallLeftOverRefunded GasChangeReason = 7
+ // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE.
+ GasChangeCallContractCreation GasChangeReason = 8
+ // GasChangeCallContractCreation2 is the amount of gas that will be burned for a CREATE2.
+ GasChangeCallContractCreation2 GasChangeReason = 9
+ // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage.
+ GasChangeCallCodeStorage GasChangeReason = 10
+ // GasChangeCallOpCode is the amount of gas that will be charged for an opcode executed by the EVM, exact opcode that was
+ // performed can be check by `OnOpcode` handling.
+ GasChangeCallOpCode GasChangeReason = 11
+ // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution.
+ GasChangeCallPrecompiledContract GasChangeReason = 12
+ // GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules.
+ GasChangeCallStorageColdAccess GasChangeReason = 13
+ // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
+ GasChangeCallFailedExecution GasChangeReason = 14
+ // GasChangeWitnessContractInit flags the event of adding to the witness during the contract creation initialization step.
+ GasChangeWitnessContractInit GasChangeReason = 15
+ // GasChangeWitnessContractCreation flags the event of adding to the witness during the contract creation finalization step.
+ GasChangeWitnessContractCreation GasChangeReason = 16
+ // GasChangeWitnessCodeChunk flags the event of adding one or more contract code chunks to the witness.
+ GasChangeWitnessCodeChunk GasChangeReason = 17
+ // GasChangeWitnessContractCollisionCheck flags the event of adding to the witness when checking for contract address collision.
+ GasChangeWitnessContractCollisionCheck GasChangeReason = 18
+ // GasChangeTxDataFloor is the amount of extra gas the transaction has to pay to reach the minimum gas requirement for the
+ // transaction data. This change will always be a negative change.
+ GasChangeTxDataFloor GasChangeReason = 19
+
+ // GasChangeIgnored is a special value that can be used to indicate that the gas change should be ignored as
+ // it will be "manually" tracked by a direct emit of the gas change event.
+ GasChangeIgnored GasChangeReason = 0xFF
+)
+
+// NonceChangeReason is used to indicate the reason for a nonce change.
+type NonceChangeReason byte
+
+//go:generate go run golang.org/x/tools/cmd/stringer -type=NonceChangeReason -trimprefix NonceChange -output gen_nonce_change_reason_stringer.go
+
+const (
+ NonceChangeUnspecified NonceChangeReason = 0
+
+ // NonceChangeGenesis is the nonce allocated to accounts at genesis.
+ NonceChangeGenesis NonceChangeReason = 1
+
+ // NonceChangeEoACall is the nonce change due to an EoA call.
+ NonceChangeEoACall NonceChangeReason = 2
+
+ // NonceChangeContractCreator is the nonce change of an account creating a contract.
+ NonceChangeContractCreator NonceChangeReason = 3
+
+ // NonceChangeNewContract is the nonce change of a newly created contract.
+ NonceChangeNewContract NonceChangeReason = 4
+
+ // NonceChangeTransaction is the nonce change due to a EIP-7702 authorization.
+ NonceChangeAuthorization NonceChangeReason = 5
+
+ // NonceChangeRevert is emitted when the nonce is reverted back to a previous value due to call failure.
+ // It is only emitted when the tracer has opted in to use the journaling wrapper (WrapWithJournal).
+ NonceChangeRevert NonceChangeReason = 6
+)
diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go
index 145f4ad30..7fdf65d93 100644
--- a/core/txpool/blobpool/blobpool_test.go
+++ b/core/txpool/blobpool/blobpool_test.go
@@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
@@ -650,19 +651,19 @@ func TestOpenDrops(t *testing.T) {
// Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
- statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3)
- statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2)
- statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000))
- statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), big.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), big.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), big.NewInt(10000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -758,7 +759,7 @@ func TestOpenDropsFeeCapUnderpriced(t *testing.T) {
chainConfig := *testChainConfig
chainConfig.VenokiBlock = common.Big0
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
- statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), big.NewInt(1000000), tracing.BalanceChangeUnspecified)
chain := &testBlockChain{
config: &chainConfig,
basefee: uint256.NewInt(params.InitialBaseFee),
@@ -822,7 +823,7 @@ func TestOpenIndex(t *testing.T) {
// Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
- statedb.AddBalance(addr, big.NewInt(1_000_000_000))
+ statedb.AddBalance(addr, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -921,9 +922,9 @@ func TestOpenHeap(t *testing.T) {
// Create a blob pool out of the pre-seeded data
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
- statedb.AddBalance(addr1, big.NewInt(1_000_000_000))
- statedb.AddBalance(addr2, big.NewInt(1_000_000_000))
- statedb.AddBalance(addr3, big.NewInt(1_000_000_000))
+ statedb.AddBalance(addr1, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr2, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr3, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -1000,9 +1001,9 @@ func TestOpenCap(t *testing.T) {
for _, datacap := range []uint64{2 * (txAvgSize + blobSize), 100 * (txAvgSize + blobSize)} {
// Create a blob pool out of the pre-seeded data, but cap it to 2 blob transaction
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
- statedb.AddBalance(addr1, big.NewInt(1_000_000_000))
- statedb.AddBalance(addr2, big.NewInt(1_000_000_000))
- statedb.AddBalance(addr3, big.NewInt(1_000_000_000))
+ statedb.AddBalance(addr1, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr2, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr3, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -1415,7 +1416,7 @@ func TestAdd(t *testing.T) {
addrs[acc] = crypto.PubkeyToAddress(keys[acc].PublicKey)
// Seed the state database with this account
- statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance))
+ statedb.AddBalance(addrs[acc], new(big.Int).SetUint64(seed.balance), tracing.BalanceChangeUnspecified)
statedb.SetNonce(addrs[acc], seed.nonce)
// Sign the seed transactions and store them in the data store
@@ -1495,7 +1496,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
if err != nil {
b.Fatal(err)
}
- statedb.AddBalance(addr, big.NewInt(1_000_000_000))
+ statedb.AddBalance(addr, big.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
pool.add(tx)
}
statedb.Commit(0, true)
@@ -1548,8 +1549,8 @@ func TestSponsoredTxRejection(t *testing.T) {
}
recipient := common.HexToAddress("1000000000000000000000000000000000000001")
- statedb.SetBalance(crypto.PubkeyToAddress(payerKey.PublicKey), new(big.Int).Mul(big.NewInt(100000), big.NewInt(22000)))
- statedb.SetBalance(crypto.PubkeyToAddress(senderKey.PublicKey), big.NewInt(10))
+ statedb.SetBalance(crypto.PubkeyToAddress(payerKey.PublicKey), new(big.Int).Mul(big.NewInt(100000), big.NewInt(22000)), tracing.BalanceChangeUnspecified)
+ statedb.SetBalance(crypto.PubkeyToAddress(senderKey.PublicKey), big.NewInt(10), tracing.BalanceChangeUnspecified)
innerTx := types.SponsoredTx{
ChainID: big.NewInt(2020),
diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go
index b045ae138..24883ed3a 100644
--- a/core/txpool/legacypool/legacypool2_test.go
+++ b/core/txpool/legacypool/legacypool2_test.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/crypto"
"github.com/ethereum/go-ethereum/event"
@@ -49,7 +50,7 @@ func fillPool(t *testing.T, pool *LegacyPool) {
nonExecutableTxs := types.Transactions{}
for i := 0; i < 384; i++ {
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(10000000000), tracing.BalanceChangeUnspecified)
// Add executable ones
for j := 0; j < int(pool.config.AccountSlots); j++ {
executableTxs = append(executableTxs, pricedTransaction(uint64(j), 100000, big.NewInt(300), key))
@@ -95,7 +96,7 @@ func TestTransactionFutureAttack(t *testing.T) {
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
{
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified)
futureTxs := types.Transactions{}
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 100000, big.NewInt(500), key))
@@ -129,7 +130,7 @@ func TestTransactionFuture1559(t *testing.T) {
// Now, future transaction attack starts, let's add a bunch of expensive non-executables, and see if the pending-count drops
{
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified)
futureTxs := types.Transactions{}
for j := 0; j < int(pool.config.GlobalSlots+pool.config.GlobalQueue); j++ {
futureTxs = append(futureTxs, dynamicFeeTx(1000+uint64(j), 100000, big.NewInt(200), big.NewInt(101), key))
@@ -201,7 +202,7 @@ func TestTransactionZAttack(t *testing.T) {
for j := 0; j < int(pool.config.GlobalQueue); j++ {
futureTxs := types.Transactions{}
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified)
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
pool.AddRemotesSync(futureTxs)
}
@@ -209,7 +210,7 @@ func TestTransactionZAttack(t *testing.T) {
overDraftTxs := types.Transactions{}
{
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified)
for j := 0; j < int(pool.config.GlobalSlots); j++ {
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 60000000000, 21000, big.NewInt(500), key))
}
@@ -234,11 +235,11 @@ func TestTransactionZAttack(t *testing.T) {
payerKey, _ := crypto.GenerateKey()
payerAccount := crypto.PubkeyToAddress(payerKey.PublicKey)
- pool.currentState.SetBalance(payerAccount, new(big.Int).SetUint64(1000*21000*pool.config.GlobalSlots))
+ pool.currentState.SetBalance(payerAccount, new(big.Int).SetUint64(1000*21000*pool.config.GlobalSlots), tracing.BalanceChangeUnspecified)
overDraftSenderSponsoredTxs := types.Transactions{}
{
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), big.NewInt(100000000000), tracing.BalanceChangeUnspecified)
for j := 0; j < int(pool.config.GlobalSlots); j++ {
innerTx := types.SponsoredTx{
@@ -285,7 +286,7 @@ func TestTransactionZAttack(t *testing.T) {
payerKey2, _ := crypto.GenerateKey()
payerAccount2 := crypto.PubkeyToAddress(payerKey2.PublicKey)
- pool.currentState.SetBalance(payerAccount2, new(big.Int).SetUint64(21000*600))
+ pool.currentState.SetBalance(payerAccount2, new(big.Int).SetUint64(21000*600), tracing.BalanceChangeUnspecified)
overDraftPayerSponsoredTxs := types.Transactions{}
{
key, _ := crypto.GenerateKey()
diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go
index 6637c38a4..5f0653916 100644
--- a/core/txpool/legacypool/legacypool_test.go
+++ b/core/txpool/legacypool/legacypool_test.go
@@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -328,7 +329,7 @@ func (c *testChain) State() (*state.StateDB, error) {
c.statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
// simulate that the new head block included tx0 and tx1
c.statedb.SetNonce(c.address, 2)
- c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether))
+ c.statedb.SetBalance(c.address, new(big.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified)
*c.trigger = false
}
return stdb, nil
@@ -348,7 +349,7 @@ func TestStateChangeDuringReset(t *testing.T) {
)
// setup pool with 2 transaction in it
- statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether))
+ statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified)
blockchain := &testChain{&testBlockChain{1000000000, statedb, new(event.Feed), 0}, address, &trigger}
tx0 := transaction(0, 100000, key)
@@ -386,7 +387,7 @@ func TestStateChangeDuringReset(t *testing.T) {
func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) {
pool.mu.Lock()
- pool.currentState.AddBalance(addr, amount)
+ pool.currentState.AddBalance(addr, amount, tracing.BalanceChangeUnspecified)
pool.mu.Unlock()
}
@@ -547,7 +548,7 @@ func TestChainFork(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- statedb.AddBalance(addr, big.NewInt(100000000000000))
+ statedb.AddBalance(addr, big.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
pool.chain = &testBlockChain{1000000, statedb, new(event.Feed), 0}
<-pool.requestReset(nil, nil)
@@ -576,7 +577,7 @@ func TestDoubleNonce(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- statedb.AddBalance(addr, big.NewInt(100000000000000))
+ statedb.AddBalance(addr, big.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
pool.chain = &testBlockChain{1000000, statedb, new(event.Feed), 0}
<-pool.requestReset(nil, nil)
@@ -3244,7 +3245,7 @@ func BenchmarkMultiAccountBatchInsert(b *testing.B) {
for i := 0; i < b.N; i++ {
key, _ := crypto.GenerateKey()
account := crypto.PubkeyToAddress(key.PublicKey)
- pool.currentState.AddBalance(account, big.NewInt(1000000))
+ pool.currentState.AddBalance(account, big.NewInt(1000000), tracing.BalanceChangeUnspecified)
tx := transaction(uint64(0), 100000, key)
batches[i] = tx
}
@@ -3436,14 +3437,14 @@ func TestExpiredTimeAndGasCheckSponsoredTx(t *testing.T) {
}
// 5. Failed when sender does not have sufficient fund for msg.value
- statedb.SetBalance(crypto.PubkeyToAddress(payerKey.PublicKey), new(big.Int).Mul(big.NewInt(100000), big.NewInt(22000)))
+ statedb.SetBalance(crypto.PubkeyToAddress(payerKey.PublicKey), new(big.Int).Mul(big.NewInt(100000), big.NewInt(22000)), tracing.BalanceChangeUnspecified)
err = txpool.addRemoteSync(tx)
if err == nil || !errors.Is(err, core.ErrInsufficientSenderFunds) {
t.Fatalf("Expect error %s, get %s", core.ErrInsufficientSenderFunds, err)
}
// 6. Successfully add tx
- statedb.SetBalance(crypto.PubkeyToAddress(senderKey.PublicKey), big.NewInt(10))
+ statedb.SetBalance(crypto.PubkeyToAddress(senderKey.PublicKey), big.NewInt(10), tracing.BalanceChangeUnspecified)
err = txpool.addRemoteSync(tx)
if err != nil {
t.Fatalf("Expect successfully add tx, get %s", err)
@@ -3477,7 +3478,7 @@ func TestExpiredTimeAndGasCheckSponsoredTx(t *testing.T) {
innerTx.Nonce = 3
innerTx.GasFeeCap = big.NewInt(params.MinimumBaseFee + 1)
innerTx.Value = common.Big0
- statedb.SetBalance(crypto.PubkeyToAddress(payerKey.PublicKey), new(big.Int).Mul(innerTx.GasFeeCap, big.NewInt(22000)))
+ statedb.SetBalance(crypto.PubkeyToAddress(payerKey.PublicKey), new(big.Int).Mul(innerTx.GasFeeCap, big.NewInt(22000)), tracing.BalanceChangeUnspecified)
innerTx.PayerR, innerTx.PayerS, innerTx.PayerV, err = types.PayerSign(
payerKey,
mikoSigner,
@@ -3554,8 +3555,8 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
ExpiredTime: 100,
}
gasFee := new(big.Int).Mul(sponsoredTx1.GasFeeCap, new(big.Int).SetUint64(sponsoredTx1.Gas))
- statedb.SetBalance(payerAddr, gasFee)
- statedb.SetBalance(senderAddr, sponsoredTx1.Value)
+ statedb.SetBalance(payerAddr, gasFee, tracing.BalanceChangeUnspecified)
+ statedb.SetBalance(senderAddr, sponsoredTx1.Value, tracing.BalanceChangeUnspecified)
mikoSigner := types.NewMikoSigner(big.NewInt(2020))
sponsoredTx1.PayerR, sponsoredTx1.PayerS, sponsoredTx1.PayerV, err = types.PayerSign(
@@ -3604,7 +3605,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
}
// 1. Payer fund is insufficient, 2 txs are removed from pending and queued
- statedb.SubBalance(payerAddr, common.Big1)
+ statedb.SubBalance(payerAddr, common.Big1, tracing.BalanceChangeUnspecified)
<-txpool.requestReset(nil, nil)
pending, queued = txpool.Stats()
if pending != 0 {
@@ -3615,7 +3616,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
}
// 2. Sender fund is insufficient, 2 txs are removed from pending and queued
- statedb.AddBalance(payerAddr, common.Big1)
+ statedb.AddBalance(payerAddr, common.Big1, tracing.BalanceChangeUnspecified)
errs = txpool.AddRemotesSync([]*types.Transaction{tx1, tx2})
for _, err := range errs {
if err != nil {
@@ -3631,7 +3632,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
t.Fatalf("Queued txpool, expect %d get %d", 1, queued)
}
- statedb.SubBalance(senderAddr, common.Big1)
+ statedb.SubBalance(senderAddr, common.Big1, tracing.BalanceChangeUnspecified)
<-txpool.requestReset(nil, nil)
pending, queued = txpool.Stats()
if pending != 0 {
@@ -3642,7 +3643,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
}
// 3. Payer fund is insufficient, 2 txs with the same payer in a queue
- statedb.AddBalance(senderAddr, common.Big1)
+ statedb.AddBalance(senderAddr, common.Big1, tracing.BalanceChangeUnspecified)
sponsoredTx3 := types.SponsoredTx{
ChainID: big.NewInt(2020),
Nonce: 3,
@@ -3682,7 +3683,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
}
gasFee = new(big.Int).Mul(sponsoredTx3.GasFeeCap, new(big.Int).SetUint64(sponsoredTx3.Gas))
- statedb.SetBalance(payerAddr, gasFee)
+ statedb.SetBalance(payerAddr, gasFee, tracing.BalanceChangeUnspecified)
<-txpool.requestReset(nil, nil)
// tx2 must be removed from queue but not tx3
@@ -3691,7 +3692,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
t.Fatalf("Queued txpool, expect %d get %d", 1, queued)
}
- statedb.SubBalance(payerAddr, common.Big1)
+ statedb.SubBalance(payerAddr, common.Big1, tracing.BalanceChangeUnspecified)
<-txpool.requestReset(nil, nil)
// tx3 must be removed now
_, queued = txpool.Stats()
@@ -3701,7 +3702,7 @@ func TestSponsoredTxInTxPoolQueue(t *testing.T) {
// 4. Expired txs are removed from pending and queued
gasFee = new(big.Int).Mul(sponsoredTx1.GasFeeCap, new(big.Int).SetUint64(sponsoredTx1.Gas))
- statedb.SetBalance(payerAddr, gasFee)
+ statedb.SetBalance(payerAddr, gasFee, tracing.BalanceChangeUnspecified)
errs = txpool.AddRemotesSync([]*types.Transaction{tx1, tx2})
for _, err := range errs {
if err != nil {
@@ -3780,7 +3781,7 @@ func TestFeeCapCheckVenoki(t *testing.T) {
senderAddr := crypto.PubkeyToAddress(senderKey.PublicKey)
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- statedb.AddBalance(senderAddr, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil))
+ statedb.AddBalance(senderAddr, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil), tracing.BalanceChangeUnspecified)
blockchain := &testBlockChain{10000000, statedb, new(event.Feed), 0}
diff --git a/core/types/block.go b/core/types/block.go
index 59b65da3d..35ccfb816 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -34,11 +34,6 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
-var (
- EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
- EmptyUncleHash = rlpHash([]*Header(nil))
-)
-
// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a sufficient amount of computation has been carried
// out on a block.
diff --git a/core/types/bloom9.go b/core/types/bloom9.go
index 848da9fa7..bfcc35f0b 100644
--- a/core/types/bloom9.go
+++ b/core/types/bloom9.go
@@ -117,6 +117,21 @@ func CreateBloom(receipts Receipts) Bloom {
return bin
}
+// CreateReceiptBloom creates a bloom filter for a receipt
+func CreateReceiptBloom(receipt *Receipt) Bloom {
+ var (
+ bin Bloom
+ buf = make([]byte, 6)
+ )
+ for _, log := range receipt.Logs {
+ bin.add(log.Address.Bytes(), buf)
+ for _, b := range log.Topics {
+ bin.add(b[:], buf)
+ }
+ }
+ return bin
+}
+
// MergeBloom assumes all receipts contain calculated bloom filters and
// merge them to create the final bloom filter instead of recalculating
// like CreateBloom
diff --git a/core/types/hashes.go b/core/types/hashes.go
index 6f26e909d..1e26d9319 100644
--- a/core/types/hashes.go
+++ b/core/types/hashes.go
@@ -22,11 +22,6 @@ import (
"github.com/ethereum/go-ethereum/log"
)
-var (
- // EmptyCodeHash is the known hash of the empty EVM bytecode.
- EmptyCodeHash = crypto.Keccak256Hash(nil) // c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
-)
-
// TrieRootHash returns the hash itself if it's non-empty or the predefined
// emptyHash one instead.
func TrieRootHash(hash common.Hash) common.Hash {
@@ -36,3 +31,23 @@ func TrieRootHash(hash common.Hash) common.Hash {
}
return hash
}
+
+var (
+ // EmptyRootHash is the known root hash of an empty merkle trie.
+ EmptyRootHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyUncleHash is the known hash of the empty uncle set.
+ EmptyUncleHash = rlpHash([]*Header(nil)) // 1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347
+
+ // EmptyCodeHash is the known hash of the empty EVM bytecode.
+ EmptyCodeHash = crypto.Keccak256Hash(nil) // c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
+
+ // EmptyTxsHash is the known hash of the empty transaction set.
+ EmptyTxsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyReceiptsHash is the known hash of the empty receipt set.
+ EmptyReceiptsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
+
+ // EmptyVerkleHash is the known hash of an empty verkle trie.
+ EmptyVerkleHash = common.Hash{}
+)
diff --git a/core/types/transaction.go b/core/types/transaction.go
index c2a7b817e..fc01c5bcb 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -625,127 +625,6 @@ func (s TxByNonce) Len() int { return len(s) }
func (s TxByNonce) Less(i, j int) bool { return s[i].Nonce() < s[j].Nonce() }
func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-// Message is a fully derived transaction and implements core.Message
-//
-// NOTE: In a future PR this will be removed.
-type Message struct {
- to *common.Address
- from common.Address
- nonce uint64
- amount *big.Int
- gasLimit uint64
- gasPrice *big.Int
- gasFeeCap *big.Int
- gasTipCap *big.Int
- data []byte
- accessList AccessList
- isFake bool
- payer common.Address
- expiredTime uint64
- blobGasFeeCap *big.Int
- blobHashes []common.Hash
- authList []SetCodeAuthorization
-}
-
-// Create a new message with payer is the same as from, expired time = 0
-func NewMessage(
- from common.Address,
- to *common.Address,
- nonce uint64,
- amount *big.Int,
- gasLimit uint64,
- gasPrice, gasFeeCap, gasTipCap *big.Int,
- data []byte,
- accessList AccessList,
- isFake bool,
- blobFeeCap *big.Int,
- blobHashes []common.Hash,
- authList []SetCodeAuthorization,
-) Message {
- return Message{
- from: from,
- to: to,
- nonce: nonce,
- amount: amount,
- gasLimit: gasLimit,
- gasPrice: gasPrice,
- gasFeeCap: gasFeeCap,
- gasTipCap: gasTipCap,
- data: data,
- accessList: accessList,
- isFake: isFake,
- payer: from,
- expiredTime: 0,
- blobGasFeeCap: blobFeeCap,
- blobHashes: blobHashes,
- authList: authList,
- }
-}
-
-// AsMessage returns the transaction as a core.Message.
-func (tx *Transaction) AsMessage(s Signer, baseFee *big.Int) (Message, error) {
- msg := Message{
- nonce: tx.Nonce(),
- gasLimit: tx.Gas(),
- gasPrice: new(big.Int).Set(tx.GasPrice()),
- gasFeeCap: new(big.Int).Set(tx.GasFeeCap()),
- gasTipCap: new(big.Int).Set(tx.GasTipCap()),
- to: tx.To(),
- amount: tx.Value(),
- data: tx.Data(),
- accessList: tx.AccessList(),
- isFake: false,
- expiredTime: tx.ExpiredTime(),
- blobGasFeeCap: tx.BlobGasFeeCap(),
- blobHashes: tx.BlobHashes(),
- authList: tx.SetCodeAuthorizations(),
- }
- // If baseFee provided, set gasPrice to effectiveGasPrice.
- if baseFee != nil {
- msg.gasPrice = math.BigMin(msg.gasPrice.Add(msg.gasTipCap, baseFee), msg.gasFeeCap)
- }
- var err error
- msg.from, err = Sender(s, tx)
- if err != nil {
- return Message{}, err
- }
-
- if tx.Type() == SponsoredTxType {
- msg.payer, err = Payer(s, tx)
- if err != nil {
- return Message{}, err
- }
-
- if msg.payer == msg.from {
- // Reject sponsored transaction with identical payer and sender
- return Message{}, ErrSamePayerSenderSponsoredTx
- }
- return msg, nil
- } else {
- msg.payer = msg.from
- return msg, nil
- }
-}
-
-func (m Message) From() common.Address { return m.from }
-func (m Message) To() *common.Address { return m.to }
-func (m Message) GasPrice() *big.Int { return m.gasPrice }
-func (m Message) GasFeeCap() *big.Int { return m.gasFeeCap }
-func (m Message) GasTipCap() *big.Int { return m.gasTipCap }
-func (m Message) Value() *big.Int { return m.amount }
-func (m Message) Gas() uint64 { return m.gasLimit }
-func (m Message) Nonce() uint64 { return m.nonce }
-func (m Message) Data() []byte { return m.data }
-func (m Message) AccessList() AccessList { return m.accessList }
-func (m Message) IsFake() bool { return m.isFake }
-func (m Message) Payer() common.Address { return m.payer }
-func (m Message) ExpiredTime() uint64 { return m.expiredTime }
-
-func (m Message) BlobHashes() []common.Hash { return m.blobHashes }
-func (m Message) BlobGasFeeCap() *big.Int { return m.blobGasFeeCap }
-func (m Message) SetCodeAuthorizations() []SetCodeAuthorization { return m.authList }
-
-// copyAddressPtr copies an address.
func copyAddressPtr(a *common.Address) *common.Address {
if a == nil {
return nil
diff --git a/core/vm/consortium_precompiled_contracts_test.go b/core/vm/consortium_precompiled_contracts_test.go
index 6fdbb6e88..d6d4b7391 100644
--- a/core/vm/consortium_precompiled_contracts_test.go
+++ b/core/vm/consortium_precompiled_contracts_test.go
@@ -589,14 +589,11 @@ func TestSort(t *testing.T) {
// TestConsortiumValidatorSorting_Run sorts 21 validators successfully
func TestConsortiumValidatorSorting_Run(t *testing.T) {
- var (
- statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- )
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
smcAbi := *unmarshalledABIs[SortValidator]
input, err := smcAbi.Pack(sortValidatorsMethod, addressesTest, weightsTest)
-
if err != nil {
t.Fatal(err)
}
@@ -610,7 +607,7 @@ func TestConsortiumValidatorSorting_Run(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- //println(common.Bytes2Hex(output))
+ // println(common.Bytes2Hex(output))
res, err := smcAbi.Methods[sortValidatorsMethod].Outputs.Unpack(output)
if err != nil {
@@ -621,7 +618,7 @@ func TestConsortiumValidatorSorting_Run(t *testing.T) {
t.Fatal(fmt.Sprintf("expected len %d, got %v", 21, len(sortedValidators)))
}
for i, addr := range sortedValidators {
- //println(addr.Hex())
+ // println(addr.Hex())
if expectedValidators[i].Hex() != addr.Hex() {
t.Fatal(fmt.Sprintf("mismatched addr at %d, expected:%s got:%s", i, expectedValidators[i].Hex(), addr.Hex()))
}
@@ -630,9 +627,7 @@ func TestConsortiumValidatorSorting_Run(t *testing.T) {
// TestConsortiumValidatorSorting_Run2 simulates a call from a user who trigger system contract to call `sort` precompiled contract
func TestConsortiumValidatorSorting_Run2(t *testing.T) {
- var (
- statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- )
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
smcAbi, err := abi.JSON(strings.NewReader(wrapupAbi))
if err != nil {
t.Fatal(err)
@@ -748,6 +743,7 @@ func TestConsortiumVerifyHeaders_verify(t *testing.T) {
},
test: true,
}
+ c.evm.SetPrecompiles(activePrecompiledContracts(c.evm.chainRules))
if !c.verify(header1.Coinbase, types.FromHeader(header1, big1, false), types.FromHeader(header2, big1, false)) {
t.Fatal("expected true, got false")
}
@@ -963,6 +959,7 @@ func TestConsortiumVerifyHeaders_malleability(t *testing.T) {
}
c := &consortiumVerifyHeaders{evm: &EVM{chainConfig: ¶ms.ChainConfig{ChainID: big1}}, test: true}
+ c.evm.SetPrecompiles(activePrecompiledContracts(c.evm.chainRules))
if c.verify(header1.Coinbase, types.FromHeader(header1, big1, false), types.FromHeader(header2, big1, false)) {
t.Fatal("expected false, got true")
}
@@ -970,9 +967,7 @@ func TestConsortiumVerifyHeaders_malleability(t *testing.T) {
// TestConsortiumVerifyHeaders_Run2 deploys smart contract and call precompiled contracts via this contract
func TestConsortiumVerifyHeaders_Run2(t *testing.T) {
- var (
- statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- )
+ statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
smcAbi, err := abi.JSON(strings.NewReader(verifyHeadersTestAbi))
if err != nil {
t.Fatal(err)
@@ -1422,7 +1417,6 @@ func TestConsortiumPickValidatorSet_Run(t *testing.T) {
}
input, err := smcAbi.Pack(pickValidatorSetMethod, candidates, weights, isTrustedOrganizations, maxValidatorNumber, maxPrioritizedValidatorNumber)
-
if err != nil {
t.Fatal(err)
}
@@ -1487,7 +1481,6 @@ func TestConsortiumPickValidatorSet_Run2(t *testing.T) {
}
input, err := smcAbi.Pack(pickValidatorSetMethod, candidates, weights, isTrustedOrganizations, maxValidatorNumber, maxPrioritizedValidatorNumber)
-
if err != nil {
t.Fatal(err)
}
@@ -1583,7 +1576,6 @@ func TestConsortiumPickValidatorSet_Run3(t *testing.T) {
}
input, err := smcAbi.Pack(pickValidatorSetMethod, candidates, weights, isTrustedOrganizations, maxValidatorNumber, maxPrioritizedValidatorNumber)
-
if err != nil {
t.Fatal(err)
}
@@ -1680,7 +1672,6 @@ func TestConsortiumPickValidatorSet_Run4(t *testing.T) {
}
input, err := smcAbi.Pack(pickValidatorSetMethod, candidates, weights, isTrustedOrganizations, maxValidatorNumber, maxPrioritizedValidatorNumber)
-
if err != nil {
t.Fatal(err)
}
@@ -1938,6 +1929,8 @@ func newEVM(caller common.Address, statedb StateDB) (*EVM, error) {
chainRules: params.Rules{IsIstanbul: true, IsEIP150: true, IsConsortiumV2: true},
}
evm.chainConfig.ConsortiumV2Block = common.Big1
+ evm.SetPrecompiles(activePrecompiledContracts(evm.chainRules))
+
evm.interpreter = NewEVMInterpreter(evm, Config{NoBaseFee: true})
_, contract, _, err := evm.Create(AccountRef(caller), common.FromHex(testSortCode), math.MaxUint64/2, big0)
if err != nil {
@@ -2348,6 +2341,7 @@ func Test_consortiumVerifyHeaders_getSigner(t *testing.T) {
},
test: true,
}
+ c.evm.SetPrecompiles(activePrecompiledContracts(c.evm.chainRules))
copy(tt.args.blockHeader.Extra[:], extraData)
blockHeader := types.FromHeader(tt.args.blockHeader, tt.args.chainId, tt.args.isVenoki)
header := blockHeader.ToHeader()
diff --git a/core/vm/contract.go b/core/vm/contract.go
index 61dbd5007..5da1b40fa 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -20,6 +20,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/holiman/uint256"
)
@@ -164,14 +165,28 @@ func (c *Contract) Caller() common.Address {
}
// UseGas attempts the use gas and subtracts it and returns true on success
-func (c *Contract) UseGas(gas uint64) (ok bool) {
+func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) {
if c.Gas < gas {
return false
}
+ if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
+ logger.OnGasChange(c.Gas, c.Gas-gas, reason)
+ }
c.Gas -= gas
return true
}
+// RefundGas refunds gas to the contract
+func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) {
+ if gas == 0 {
+ return
+ }
+ if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored {
+ logger.OnGasChange(c.Gas, c.Gas+gas, reason)
+ }
+ c.Gas += gas
+}
+
// Address returns the contracts address
func (c *Contract) Address() common.Address {
return c.self.Address()
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 26ca7f21e..fee008bcf 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -21,6 +21,7 @@ import (
"encoding/binary"
"errors"
"fmt"
+ "maps"
"math/big"
"github.com/consensys/gnark-crypto/ecc"
@@ -29,6 +30,7 @@ import (
"github.com/consensys/gnark-crypto/ecc/bls12-381/fr"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bn256"
@@ -47,6 +49,9 @@ type PrecompiledContract interface {
Run(input []byte) ([]byte, error) // Run runs the precompiled contract
}
+// PrecompiledContracts contains the precompiled contracts supported at the given fork.
+type PrecompiledContracts map[common.Address]PrecompiledContract
+
var (
PrecompiledAddressesPrague []common.Address
PrecompiledAddressesCancun []common.Address
@@ -59,39 +64,39 @@ var (
// PrecompiledContractsHomestead contains the default set of pre-compiled Ethereum
// contracts used in the Frontier and Homestead releases.
- PrecompiledContractsHomestead map[common.Address]PrecompiledContract
+ PrecompiledContractsHomestead PrecompiledContracts
// PrecompiledContractsByzantium contains the default set of pre-compiled Ethereum
// contracts used in the Byzantium release.
- PrecompiledContractsByzantium map[common.Address]PrecompiledContract
+ PrecompiledContractsByzantium PrecompiledContracts
// PrecompiledContractsIstanbul contains the default set of pre-compiled Ethereum
// contracts used in the Istanbul release.
- PrecompiledContractsIstanbul map[common.Address]PrecompiledContract
+ PrecompiledContractsIstanbul PrecompiledContracts
// PrecompiledContractsConsortium contains additional Consortium precompiled contract
// beside PrecompiledContractsIstanbul
- PrecompiledContractsConsortium map[common.Address]PrecompiledContract
+ PrecompiledContractsConsortium PrecompiledContracts
// PrecompiledContractsConsortium contains proof of possession precompiled contract
// beside PrecompiledContractsConsortium
- PrecompiledContractsConsortiumMiko map[common.Address]PrecompiledContract
+ PrecompiledContractsConsortiumMiko PrecompiledContracts
// PrecompiledContractsBerlin contains the default set of pre-compiled Ethereum
// contracts used in the Berlin release.
- PrecompiledContractsBerlin map[common.Address]PrecompiledContract
+ PrecompiledContractsBerlin PrecompiledContracts
// PrecompiledContractsCancun contains the default set of pre-compiled Ethereum
// contracts used in the Cancun release.
- PrecompiledContractsCancun map[common.Address]PrecompiledContract
+ PrecompiledContractsCancun PrecompiledContracts
// PrecompiledContractsPrague contains the default set of pre-compiled Ethereum
// contracts used in the Prague release.
- PrecompiledContractsPrague map[common.Address]PrecompiledContract
+ PrecompiledContractsPrague PrecompiledContracts
)
-func copyPrecompiledContract(contracts map[common.Address]PrecompiledContract) map[common.Address]PrecompiledContract {
- cpy := make(map[common.Address]PrecompiledContract)
+func copyPrecompiledContract(contracts PrecompiledContracts) PrecompiledContracts {
+ cpy := make(PrecompiledContracts)
for address, contract := range contracts {
cpy[address] = contract
@@ -101,7 +106,7 @@ func copyPrecompiledContract(contracts map[common.Address]PrecompiledContract) m
}
func init() {
- PrecompiledContractsHomestead = map[common.Address]PrecompiledContract{
+ PrecompiledContractsHomestead = PrecompiledContracts{
common.BytesToAddress([]byte{1}): &ecrecover{},
common.BytesToAddress([]byte{2}): &sha256hash{},
common.BytesToAddress([]byte{3}): &ripemd160hash{},
@@ -210,24 +215,49 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
}
}
+func activePrecompiledContracts(rules params.Rules) PrecompiledContracts {
+ switch {
+ case rules.IsCancun:
+ return PrecompiledContractsCancun
+ case rules.IsBerlin:
+ return PrecompiledContractsBerlin
+ case rules.IsMiko:
+ return PrecompiledContractsConsortiumMiko
+ case rules.IsLastConsortiumV1Block, rules.IsConsortiumV2:
+ return PrecompiledContractsConsortium
+ case rules.IsIstanbul:
+ return PrecompiledContractsIstanbul
+ case rules.IsByzantium:
+ return PrecompiledContractsByzantium
+ default:
+ return PrecompiledContractsHomestead
+ }
+}
+
+// ActivePrecompiledContracts returns a copy of precompiled contracts enabled with the current configuration.
+func ActivePrecompiledContracts(rules params.Rules) PrecompiledContracts {
+ return maps.Clone(activePrecompiledContracts(rules))
+}
+
// RunPrecompiledContract runs and evaluates the output of a precompiled contract.
// It returns
// - the returned bytes,
// - the _remaining_ gas,
// - any error that occurred
-func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
+func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uint64, logger *tracing.Hooks) (ret []byte, remainingGas uint64, err error) {
gasCost := p.RequiredGas(input)
if suppliedGas < gasCost {
return nil, 0, ErrOutOfGas
}
+ if logger != nil && logger.OnGasChange != nil {
+ logger.OnGasChange(suppliedGas, suppliedGas-gasCost, tracing.GasChangeCallPrecompiledContract)
+ }
suppliedGas -= gasCost
output, err := p.Run(input)
return output, suppliedGas, err
}
-var (
- errBlacklistedAddress = errors.New("address is blacklisted")
-)
+var errBlacklistedAddress = errors.New("address is blacklisted")
type blacklistedAddress struct{}
@@ -287,6 +317,7 @@ type sha256hash struct{}
func (c *sha256hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Sha256PerWordGas + params.Sha256BaseGas
}
+
func (c *sha256hash) Run(input []byte) ([]byte, error) {
h := sha256.Sum256(input)
return h[:], nil
@@ -302,6 +333,7 @@ type ripemd160hash struct{}
func (c *ripemd160hash) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.Ripemd160PerWordGas + params.Ripemd160BaseGas
}
+
func (c *ripemd160hash) Run(input []byte) ([]byte, error) {
ripemd := ripemd160.New()
ripemd.Write(input)
@@ -318,6 +350,7 @@ type dataCopy struct{}
func (c *dataCopy) RequiredGas(input []byte) uint64 {
return uint64(len(input)+31)/32*params.IdentityPerWordGas + params.IdentityBaseGas
}
+
func (c *dataCopy) Run(in []byte) ([]byte, error) {
return common.CopyBytes(in), nil
}
diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go
index a086d9f1a..86feffe58 100644
--- a/core/vm/contracts_test.go
+++ b/core/vm/contracts_test.go
@@ -28,12 +28,11 @@ import (
"time"
"github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
-
- "github.com/ethereum/go-ethereum/common"
)
// precompiledTest defines the input/output pairs for precompiled contract tests.
@@ -128,7 +127,7 @@ func testPrecompiled(addr string, test precompiledTest, t *testing.T) {
in := common.Hex2Bytes(test.Input)
gas := p.RequiredGas(in)
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
- if res, _, err := RunPrecompiledContract(p, in, gas); err != nil {
+ if res, _, err := RunPrecompiledContract(p, in, gas, nil); err != nil {
t.Error(err)
} else if common.Bytes2Hex(res) != test.Expected {
t.Errorf("Expected %v, got %v", test.Expected, common.Bytes2Hex(res))
@@ -150,7 +149,7 @@ func testPrecompiledOOG(addr string, test precompiledTest, t *testing.T) {
gas := p.RequiredGas(in) - 1
t.Run(fmt.Sprintf("%s-Gas=%d", test.Name, gas), func(t *testing.T) {
- _, _, err := RunPrecompiledContract(p, in, gas)
+ _, _, err := RunPrecompiledContract(p, in, gas, nil)
if err.Error() != "out of gas" {
t.Errorf("Expected error [out of gas], got [%v]", err)
}
@@ -167,7 +166,7 @@ func testPrecompiledFailure(addr string, test precompiledFailureTest, t *testing
in := common.Hex2Bytes(test.Input)
gas := p.RequiredGas(in)
t.Run(test.Name, func(t *testing.T) {
- _, _, err := RunPrecompiledContract(p, in, gas)
+ _, _, err := RunPrecompiledContract(p, in, gas, nil)
if err.Error() != test.ExpectedError {
t.Errorf("Expected error [%v], got [%v]", test.ExpectedError, err)
}
@@ -199,7 +198,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
bench.ResetTimer()
for i := 0; i < bench.N; i++ {
copy(data, in)
- res, _, err = RunPrecompiledContract(p, data, reqGas)
+ res, _, err = RunPrecompiledContract(p, data, reqGas, nil)
}
bench.StopTimer()
elapsed := uint64(time.Since(start))
@@ -211,7 +210,7 @@ func benchmarkPrecompiled(addr string, test precompiledTest, bench *testing.B) {
// Keep it as uint64, multiply 100 to get two digit float later
mgasps := (100 * 1000 * gasUsed) / elapsed
bench.ReportMetric(float64(mgasps)/100, "mgas/s")
- //Check if it is correct
+ // Check if it is correct
if err != nil {
bench.Error(err)
return
@@ -343,33 +342,43 @@ func benchJson(name, addr string, b *testing.B) {
func TestPrecompiledBLS12381G1Add(t *testing.T) {
testJson("blsG1Add", common.Bytes2Hex([]byte{11}), t)
}
+
func TestPrecompiledBLS12381G1Mul(t *testing.T) {
testJson("blsG1Mul", common.Bytes2Hex([]byte{12}), t)
}
+
func TestPrecompiledBLS12381G1MultiExp(t *testing.T) {
testJson("blsG1MultiExp", common.Bytes2Hex([]byte{12}), t)
}
+
func TestPrecompiledBLS12381G2Add(t *testing.T) {
testJson("blsG2Add", common.Bytes2Hex([]byte{13}), t)
}
+
func TestPrecompiledBLS12381G2Mul(t *testing.T) {
testJson("blsG2Mul", common.Bytes2Hex([]byte{14}), t)
}
+
func TestPrecompiledBLS12381G2MultiExp(t *testing.T) {
testJson("blsG2MultiExp", common.Bytes2Hex([]byte{14}), t)
}
+
func TestPrecompiledBLS12381Pairing(t *testing.T) {
testJson("blsPairing", common.Bytes2Hex([]byte{15}), t)
}
+
func TestPrecompiledBLS12381MapG1(t *testing.T) {
testJson("blsMapG1", common.Bytes2Hex([]byte{16}), t)
}
+
func TestPrecompiledBLS12381MapG2(t *testing.T) {
testJson("blsMapG2", common.Bytes2Hex([]byte{17}), t)
}
+
func TestPrecompiledPointEvaluation(t *testing.T) {
testJson("pointEvaluation", common.Bytes2Hex([]byte{10}), t)
}
+
func TestPrecompiledConsortiumLog(t *testing.T) {
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.LvlInfo)
@@ -399,21 +408,35 @@ func TestPrecompiledConsortiumLog(t *testing.T) {
func BenchmarkPrecompiledBLS12381G1Add(b *testing.B) {
benchJson("blsG1Add", common.Bytes2Hex([]byte{11}), b)
}
+
+func BenchmarkPrecompiledBLS12381G1Mul(b *testing.B) {
+ benchJson("blsG1Mul", common.Bytes2Hex([]byte{12}), b)
+}
+
func BenchmarkPrecompiledBLS12381G1MultiExp(b *testing.B) {
benchJson("blsG1MultiExp", common.Bytes2Hex([]byte{12}), b)
}
+
func BenchmarkPrecompiledBLS12381G2Add(b *testing.B) {
- benchJson("blsG2Add", common.Bytes2Hex([]byte{13}), b)
+ benchJson("blsG2Add", common.Bytes2Hex([]byte{14}), b)
+}
+
+func BenchmarkPrecompiledBLS12381G2Mul(b *testing.B) {
+ benchJson("blsG2Mul", common.Bytes2Hex([]byte{15}), b)
}
+
func BenchmarkPrecompiledBLS12381G2MultiExp(b *testing.B) {
benchJson("blsG2MultiExp", common.Bytes2Hex([]byte{14}), b)
}
+
func BenchmarkPrecompiledBLS12381Pairing(b *testing.B) {
benchJson("blsPairing", common.Bytes2Hex([]byte{15}), b)
}
+
func BenchmarkPrecompiledBLS12381MapG1(b *testing.B) {
benchJson("blsMapG1", common.Bytes2Hex([]byte{16}), b)
}
+
func BenchmarkPrecompiledBLS12381MapG2(b *testing.B) {
benchJson("blsMapG2", common.Bytes2Hex([]byte{17}), b)
}
@@ -422,27 +445,35 @@ func BenchmarkPrecompiledBLS12381MapG2(b *testing.B) {
func TestPrecompiledBLS12381G1AddFail(t *testing.T) {
testJsonFail("blsG1Add", common.Bytes2Hex([]byte{11}), t)
}
+
func TestPrecompiledBLS12381G1MulFail(t *testing.T) {
testJsonFail("blsG1Mul", common.Bytes2Hex([]byte{12}), t)
}
+
func TestPrecompiledBLS12381G1MultiExpFail(t *testing.T) {
testJsonFail("blsG1MultiExp", common.Bytes2Hex([]byte{12}), t)
}
+
func TestPrecompiledBLS12381G2AddFail(t *testing.T) {
testJsonFail("blsG2Add", common.Bytes2Hex([]byte{13}), t)
}
+
func TestPrecompiledBLS12381G2MulFail(t *testing.T) {
testJsonFail("blsG2Mul", common.Bytes2Hex([]byte{14}), t)
}
+
func TestPrecompiledBLS12381G2MultiExpFail(t *testing.T) {
testJsonFail("blsG2MultiExp", common.Bytes2Hex([]byte{14}), t)
}
+
func TestPrecompiledBLS12381PairingFail(t *testing.T) {
testJsonFail("blsPairing", common.Bytes2Hex([]byte{15}), t)
}
+
func TestPrecompiledBLS12381MapG1Fail(t *testing.T) {
testJsonFail("blsMapG1", common.Bytes2Hex([]byte{16}), t)
}
+
func TestPrecompiledBLS12381MapG2Fail(t *testing.T) {
testJsonFail("blsMapG2", common.Bytes2Hex([]byte{17}), t)
}
@@ -513,6 +544,7 @@ func TestIstanbulPrecompile(t *testing.T) {
IsIstanbul: true,
},
}
+ evm.SetPrecompiles(activePrecompiledContracts(evm.chainRules))
caller := AccountRef(common.Address{0x1})
precompiledContract, ok := evm.precompile(caller, common.BytesToAddress([]byte{6}))
if !ok {
@@ -552,6 +584,7 @@ func TestConsortiumPrecompileQuery(t *testing.T) {
IsMiko: true,
},
}
+ evm.SetPrecompiles(activePrecompiledContracts(evm.chainRules))
caller := AccountRef(common.Address{0x1})
precompiledContract, ok := evm.precompile(caller, common.BytesToAddress([]byte{106}))
if !ok {
@@ -605,6 +638,7 @@ func TestConsortiumPrecompileQuery(t *testing.T) {
}
evm.chainRules.IsCancun = true
+ evm.precompiles = activePrecompiledContracts(evm.chainRules)
precompiledContract, ok = evm.precompile(caller, common.BytesToAddress([]byte{10}))
if !ok {
t.Fatal("Failed to get point evaluation contract after Cancun")
@@ -638,6 +672,7 @@ func BenchmarkConsortiumPrecompileQuery(b *testing.B) {
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
+ evm.SetPrecompiles(activePrecompiledContracts(evm.chainRules))
evm.precompile(nil, common.BytesToAddress([]byte{106}))
}
}
diff --git a/core/vm/errors.go b/core/vm/errors.go
index 500acb71a..f0014fc48 100644
--- a/core/vm/errors.go
+++ b/core/vm/errors.go
@@ -19,6 +19,7 @@ package vm
import (
"errors"
"fmt"
+ "math"
)
// List evm execution errors
@@ -67,3 +68,111 @@ type ErrInvalidOpCode struct {
}
func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) }
+
+// VMError wraps a VM error with an additional stable error code. The error
+// field is the original error that caused the VM error and must be one of the
+// VM error defined at the top of this file.
+//
+// If the error is not one of the known error above, the error code will be
+// set to VMErrorCodeUnknown.
+type VMError struct {
+ error
+ code int
+}
+
+func VMErrorFromErr(err error) error {
+ if err == nil {
+ return nil
+ }
+
+ return &VMError{
+ error: err,
+ code: vmErrorCodeFromErr(err),
+ }
+}
+
+func (e *VMError) Error() string {
+ return e.error.Error()
+}
+
+func (e *VMError) Unwrap() error {
+ return e.error
+}
+
+func (e *VMError) ErrorCode() int {
+ return e.code
+}
+
+const (
+ // We start the error code at 1 so that we can use 0 later for some possible extension. There
+ // is no unspecified value for the code today because it should always be set to a valid value
+ // that could be VMErrorCodeUnknown if the error is not mapped to a known error code.
+
+ VMErrorCodeOutOfGas = 1 + iota
+ VMErrorCodeCodeStoreOutOfGas
+ VMErrorCodeDepth
+ VMErrorCodeInsufficientBalance
+ VMErrorCodeContractAddressCollision
+ VMErrorCodeExecutionReverted
+ VMErrorCodeMaxCodeSizeExceeded
+ VMErrorCodeInvalidJump
+ VMErrorCodeWriteProtection
+ VMErrorCodeReturnDataOutOfBounds
+ VMErrorCodeGasUintOverflow
+ VMErrorCodeInvalidCode
+ VMErrorCodeNonceUintOverflow
+ VMErrorCodeStackUnderflow
+ VMErrorCodeStackOverflow
+ VMErrorCodeInvalidOpCode
+
+ // VMErrorCodeUnknown explicitly marks an error as unknown, this is useful when error is converted
+ // from an actual `error` in which case if the mapping is not known, we can use this value to indicate that.
+ VMErrorCodeUnknown = math.MaxInt - 1
+)
+
+func vmErrorCodeFromErr(err error) int {
+ switch {
+ case errors.Is(err, ErrOutOfGas):
+ return VMErrorCodeOutOfGas
+ case errors.Is(err, ErrCodeStoreOutOfGas):
+ return VMErrorCodeCodeStoreOutOfGas
+ case errors.Is(err, ErrDepth):
+ return VMErrorCodeDepth
+ case errors.Is(err, ErrInsufficientBalance):
+ return VMErrorCodeInsufficientBalance
+ case errors.Is(err, ErrContractAddressCollision):
+ return VMErrorCodeContractAddressCollision
+ case errors.Is(err, ErrExecutionReverted):
+ return VMErrorCodeExecutionReverted
+ case errors.Is(err, ErrMaxCodeSizeExceeded):
+ return VMErrorCodeMaxCodeSizeExceeded
+ case errors.Is(err, ErrInvalidJump):
+ return VMErrorCodeInvalidJump
+ case errors.Is(err, ErrWriteProtection):
+ return VMErrorCodeWriteProtection
+ case errors.Is(err, ErrReturnDataOutOfBounds):
+ return VMErrorCodeReturnDataOutOfBounds
+ case errors.Is(err, ErrGasUintOverflow):
+ return VMErrorCodeGasUintOverflow
+ case errors.Is(err, ErrInvalidCode):
+ return VMErrorCodeInvalidCode
+ case errors.Is(err, ErrNonceUintOverflow):
+ return VMErrorCodeNonceUintOverflow
+
+ default:
+ // Dynamic errors
+ if v := (*ErrStackUnderflow)(nil); errors.As(err, &v) {
+ return VMErrorCodeStackUnderflow
+ }
+
+ if v := (*ErrStackOverflow)(nil); errors.As(err, &v) {
+ return VMErrorCodeStackOverflow
+ }
+
+ if v := (*ErrInvalidOpCode)(nil); errors.As(err, &v) {
+ return VMErrorCodeInvalidOpCode
+ }
+
+ return VMErrorCodeUnknown
+ }
+}
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 37c42b418..7f7e9cca1 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -17,10 +17,11 @@
package vm
import (
+ "errors"
"math/big"
"sync/atomic"
- "time"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
@@ -70,33 +71,12 @@ func (evm *EVM) precompile(caller ContractRef, addr common.Address) (Precompiled
}
}
- var precompiles map[common.Address]PrecompiledContract
- switch {
- case evm.chainRules.IsKotaro:
- precompiles = PrecompiledContractsPrague
- case evm.chainRules.IsCancun:
- precompiles = PrecompiledContractsCancun
- case evm.chainRules.IsBerlin:
- precompiles = PrecompiledContractsBerlin
- case evm.chainRules.IsMiko:
- precompiles = PrecompiledContractsConsortiumMiko
- case evm.chainRules.IsLastConsortiumV1Block, evm.chainRules.IsConsortiumV2:
- precompiles = PrecompiledContractsConsortium
- case evm.chainRules.IsIstanbul:
- precompiles = PrecompiledContractsIstanbul
- case evm.chainRules.IsByzantium:
- precompiles = PrecompiledContractsByzantium
- default:
- precompiles = PrecompiledContractsHomestead
- }
-
- p, ok := precompiles[addr]
+ p, ok := evm.precompiles[addr]
if ok {
if pWithInit, hasInit := p.(PrecompiledContractWithInit); hasInit {
pWithInit.Init(caller, evm)
}
}
-
return p, ok
}
@@ -177,6 +157,8 @@ type EVM struct {
// applied in opCall*.
callGasTemp uint64
+ precompiles PrecompiledContracts
+
evmHook EVMHook
}
@@ -196,6 +178,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
}
+ evm.precompiles = activePrecompiledContracts(evm.chainRules)
evm.interpreter = NewEVMInterpreter(evm, config)
return evm
}
@@ -223,36 +206,35 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
return evm.interpreter
}
+// SetPrecompiles sets the precompiled contracts for the EVM.
+// This method is only used through RPC calls.
+// It is not thread-safe.
+func (evm *EVM) SetPrecompiles(precompiles PrecompiledContracts) {
+ evm.precompiles = precompiles
+}
+
// Call executes the contract associated with the addr with the given input as
// parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer.
func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
- debug := evm.Config.Tracer != nil
- captureTraceEarly := func(err error) {
- if debug && evm.Config.FullCallTracing {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
- evm.Config.Tracer.CaptureEnd(ret, 0, err)
- } else {
- evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
- evm.Config.Tracer.CaptureExit(ret, 0, err)
- }
- }
+ // Capture the tracer start/end events in debug mode
+ if evm.Config.Tracer != nil {
+ evm.captureBegin(evm.depth, CALL, caller.Address(), addr, input, gas, value)
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
}
if evm.Config.NoRecursion && evm.depth > 0 {
- captureTraceEarly(nil)
return nil, gas, nil
}
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
- captureTraceEarly(ErrDepth)
return nil, gas, ErrDepth
}
// Fail if we're trying to transfer more than the available balance
if value.Sign() != 0 && !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
- captureTraceEarly(ErrInsufficientBalance)
return nil, gas, ErrInsufficientBalance
}
snapshot := evm.StateDB.Snapshot()
@@ -261,39 +243,14 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP158 && value.Sign() == 0 {
// Calling a non existing account, don't do anything, but ping the tracer
- if debug {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
- evm.Config.Tracer.CaptureEnd(ret, 0, nil)
- } else {
- evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
- evm.Config.Tracer.CaptureExit(ret, 0, nil)
- }
- }
return nil, gas, nil
}
evm.StateDB.CreateAccount(addr)
}
evm.Context.Transfer(evm.StateDB, caller.Address(), addr, value)
- // Capture the tracer start/end events in debug mode
- if debug {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureStart(evm, caller.Address(), addr, false, input, gas, value)
- defer func(startGas uint64, startTime time.Time) { // Lazy evaluation of the parameters
- evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err)
- }(gas, time.Now())
- } else {
- // Handle tracer events for entering and exiting a call frame
- evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
- defer func(startGas uint64) {
- evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
- }(gas)
- }
- }
-
if isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
} else {
// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
@@ -316,6 +273,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
+ evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
+ }
gas = 0
}
// TODO: consider clearing up unused snapshots:
@@ -333,6 +293,13 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
// CallCode differs from Call in the sense that it executes the given address'
// code with the caller as context.
func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) {
+ // Invoke tracer hooks that signal entering/exiting a call frame
+ if evm.Config.Tracer != nil {
+ evm.captureBegin(evm.depth, CALLCODE, caller.Address(), addr, input, gas, value)
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
+ }
if evm.Config.NoRecursion && evm.depth > 0 {
return nil, gas, nil
}
@@ -347,19 +314,11 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
return nil, gas, ErrInsufficientBalance
}
- var snapshot = evm.StateDB.Snapshot()
-
- // Invoke tracer hooks that signal entering/exiting a call frame
- if evm.Config.Tracer != nil {
- evm.Config.Tracer.CaptureEnter(CALLCODE, caller.Address(), addr, input, gas, value)
- defer func(startGas uint64) {
- evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
- }(gas)
- }
+ snapshot := evm.StateDB.Snapshot()
// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(caller, addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
} else {
addrCopy := addr
// Initialise a new contract and set the code that is to be used by the EVM.
@@ -372,6 +331,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
+ evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
+ }
gas = 0
}
}
@@ -384,41 +346,30 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// DelegateCall differs from CallCode in the sense that it executes the given address'
// code with the caller as context and the caller is set to the caller of the caller.
func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
- debug := evm.Config.Tracer != nil
- captureTraceEarly := func(err error) {
- if debug && evm.Config.FullCallTracing {
- parent := caller.(*Contract)
- evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
- evm.Config.Tracer.CaptureExit(ret, 0, err)
- }
- }
-
- if evm.Config.NoRecursion && evm.depth > 0 {
- captureTraceEarly(nil)
- return nil, gas, nil
- }
- // Fail if we're trying to execute above the call depth limit
- if evm.depth > int(params.CallCreateDepth) {
- captureTraceEarly(ErrDepth)
- return nil, gas, ErrDepth
- }
- var snapshot = evm.StateDB.Snapshot()
-
// Invoke tracer hooks that signal entering/exiting a call frame
if evm.Config.Tracer != nil {
// NOTE: caller must, at all times be a contract. It should never happen
// that caller is something other than a Contract.
parent := caller.(*Contract)
// DELEGATECALL inherits value from parent call
- evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
+ evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
defer func(startGas uint64) {
- evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
}(gas)
}
+ if evm.Config.NoRecursion && evm.depth > 0 {
+ return nil, gas, nil
+ }
+ // Fail if we're trying to execute above the call depth limit
+ if evm.depth > int(params.CallCreateDepth) {
+ return nil, gas, ErrDepth
+ }
+ snapshot := evm.StateDB.Snapshot()
+
// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(caller, addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
} else {
addrCopy := addr
// Initialise a new contract and make initialise the delegate values
@@ -430,6 +381,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
+ evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
+ }
gas = 0
}
}
@@ -441,6 +395,13 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
// Opcodes that attempt to perform such modifications will result in exceptions
// instead of performing the modifications.
func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) {
+ // Invoke tracer hooks that signal entering/exiting a call frame
+ if evm.Config.Tracer != nil {
+ evm.captureBegin(evm.depth, STATICCALL, caller.Address(), addr, input, gas, nil)
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
+ }
if evm.Config.NoRecursion && evm.depth > 0 {
return nil, gas, nil
}
@@ -453,24 +414,16 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// after all empty accounts were deleted, so this is not required. However, if we omit this,
// then certain tests start failing; stRevertTest/RevertPrecompiledTouchExactOOG.json.
// We could change this, but for now it's left for legacy reasons
- var snapshot = evm.StateDB.Snapshot()
+ snapshot := evm.StateDB.Snapshot()
// We do an AddBalance of zero here, just in order to trigger a touch.
// This doesn't matter on Mainnet, where all empties are gone at the time of Byzantium,
// but is the correct thing to do and matters on other networks, in tests, and potential
// future scenarios
- evm.StateDB.AddBalance(addr, big0)
-
- // Invoke tracer hooks that signal entering/exiting a call frame
- if evm.Config.Tracer != nil {
- evm.Config.Tracer.CaptureEnter(STATICCALL, caller.Address(), addr, input, gas, nil)
- defer func(startGas uint64) {
- evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
- }(gas)
- }
+ evm.StateDB.AddBalance(addr, big0, tracing.BalanceChangeTouchAccount)
if p, isPrecompile := evm.precompile(caller, addr); isPrecompile {
- ret, gas, err = RunPrecompiledContract(p, input, gas)
+ ret, gas, err = RunPrecompiledContract(p, input, gas, evm.Config.Tracer)
} else {
// At this point, we use a copy of address. If we don't, the go compiler will
// leak the 'contract' to the outer scope, and make allocation for 'contract'
@@ -489,6 +442,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
if err != nil {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
+ evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
+ }
gas = 0
}
}
@@ -508,19 +464,12 @@ func (c *codeAndHash) Hash() common.Hash {
}
// create creates a new contract using code as deployment code.
-func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) {
- debug := evm.Config.Tracer != nil
-
- captureTraceEarly := func(err error) {
- if debug && evm.Config.FullCallTracing {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
- evm.Config.Tracer.CaptureEnd(nil, 0, err)
- } else {
- evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
- evm.Config.Tracer.CaptureExit(nil, 0, err)
- }
- }
+func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *big.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) {
+ if evm.Config.Tracer != nil {
+ evm.captureBegin(evm.depth, typ, caller.Address(), address, codeAndHash.code, gas, value)
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
}
if evm.evmHook != nil {
@@ -534,12 +483,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if !evm.chainRules.IsVenoki {
if evm.chainRules.IsAntenna {
if !evm.StateDB.ValidDeployerV2(caller.Address(), evm.Context.Time, evm.ChainConfig().WhiteListDeployerContractV2Address) {
- captureTraceEarly(ErrExecutionReverted)
return nil, common.Address{}, gas, ErrExecutionReverted
}
} else if evm.chainRules.IsOdysseusFork {
if !evm.StateDB.ValidDeployer(caller.Address()) {
- captureTraceEarly(ErrExecutionReverted)
return nil, common.Address{}, gas, ErrExecutionReverted
}
}
@@ -548,17 +495,14 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth) {
- captureTraceEarly(ErrDepth)
return nil, common.Address{}, gas, ErrDepth
}
if !evm.Context.CanTransfer(evm.StateDB, caller.Address(), value) {
- captureTraceEarly(ErrInsufficientBalance)
return nil, common.Address{}, gas, ErrInsufficientBalance
}
nonce := evm.StateDB.GetNonce(caller.Address())
if nonce+1 < nonce {
- captureTraceEarly(ErrNonceUintOverflow)
return nil, common.Address{}, gas, ErrNonceUintOverflow
}
evm.StateDB.SetNonce(caller.Address(), nonce+1)
@@ -575,7 +519,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// - the storage is non-empty
contractHash := evm.StateDB.GetCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != emptyCodeHash) {
- captureTraceEarly(ErrContractAddressCollision)
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil {
+ evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution)
+ }
return nil, common.Address{}, 0, ErrContractAddressCollision
}
// Create a new account on the state only if the object was not present.
@@ -601,19 +547,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
contract.SetCodeOptionalHash(&address, codeAndHash)
if evm.Config.NoRecursion && evm.depth > 0 {
- captureTraceEarly(nil)
return nil, address, gas, nil
}
- if debug {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value)
- } else {
- evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
- }
- }
-
- ret, err := evm.interpreter.Run(contract, nil, false)
+ ret, err = evm.interpreter.Run(contract, nil, false)
// Check whether the max code size has been exceeded, assign err if the case.
if err == nil {
@@ -639,7 +576,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// by the error checking condition below.
if err == nil {
createDataGas := uint64(len(ret)) * params.CreateDataGas
- if contract.UseGas(createDataGas) {
+ if contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) {
evm.StateDB.SetCode(address, ret)
} else {
err = ErrCodeStoreOutOfGas
@@ -652,17 +589,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
- contract.UseGas(contract.Gas)
+ contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution)
}
}
- if debug {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureEnd(ret, gas-contract.Gas, err)
- } else {
- evm.Config.Tracer.CaptureExit(ret, gas-contract.Gas, err)
- }
- }
return ret, address, contract.Gas, err
}
@@ -763,3 +693,42 @@ func (evm *EVM) PublishEvent(
func (evm *EVM) SetHook(evmHook EVMHook) {
evm.evmHook = evmHook
}
+
+func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) {
+ tracer := evm.Config.Tracer
+ if tracer.OnEnter != nil {
+ tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value, evm.Context.Counter)
+ }
+ if tracer.OnGasChange != nil {
+ tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance)
+ }
+}
+
+func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) {
+ tracer := evm.Config.Tracer
+ if leftOverGas != 0 && tracer.OnGasChange != nil {
+ tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned)
+ }
+ var reverted bool
+ if err != nil {
+ reverted = true
+ }
+ if !evm.chainRules.IsHomestead && errors.Is(err, ErrCodeStoreOutOfGas) {
+ reverted = false
+ }
+ if tracer.OnExit != nil {
+ tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted)
+ }
+}
+
+// GetVMContext provides context about the block being executed as well as state
+// to the tracers.
+func (evm *EVM) GetVMContext() *tracing.VMContext {
+ return &tracing.VMContext{
+ Coinbase: evm.Context.Coinbase,
+ BlockNumber: evm.Context.BlockNumber,
+ Time: evm.Context.Time,
+ GasPrice: evm.TxContext.GasPrice,
+ StateDB: evm.StateDB,
+ }
+}
diff --git a/core/vm/evm_test.go b/core/vm/evm_test.go
index afc649f74..73a030644 100644
--- a/core/vm/evm_test.go
+++ b/core/vm/evm_test.go
@@ -11,8 +11,7 @@ import (
"github.com/ethereum/go-ethereum/params"
)
-type TestOpEvent struct {
-}
+type TestOpEvent struct{}
func (tx *TestOpEvent) Publish(
opcode OpCode,
@@ -64,6 +63,7 @@ func TestPublishEvents(t *testing.T) {
}
evm := &EVM{Context: ctx}
+ evm.SetPrecompiles(activePrecompiledContracts(evm.chainRules))
evm.PublishEvent(CALL, 1, common.Address{}, common.Address{}, big.NewInt(0), []byte(""), []byte(""), nil)
if len(*evm.Context.InternalTransactions) != 1 || (*evm.Context.InternalTransactions)[0].Type != "test" {
t.Error("Failed to publish opcode event")
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 4f6cd37f9..52244d813 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -18,6 +18,7 @@ package vm
import (
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
@@ -251,6 +252,7 @@ func opSha3(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
size.SetBytes(interpreter.hasherBuf[:])
return nil, nil
}
+
func opAddress(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Address().Bytes()))
return nil, nil
@@ -267,6 +269,7 @@ func opOrigin(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
scope.Stack.push(new(uint256.Int).SetBytes(interpreter.evm.Origin.Bytes()))
return nil, nil
}
+
func opCaller(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetBytes(scope.Contract.Caller().Bytes()))
return nil, nil
@@ -329,7 +332,7 @@ func opReturnDataCopy(pc *uint64, interpreter *EVMInterpreter, scope *ScopeConte
return nil, ErrReturnDataOutOfBounds
}
// we can reuse dataOffset now (aliasing it for clarity)
- var end = dataOffset
+ end := dataOffset
end.Add(&dataOffset, &length)
end64, overflow := end.Uint64WithOverflow()
if overflow || uint64(len(interpreter.returnData)) < end64 {
@@ -580,9 +583,9 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// reuse size int for stackvalue
stackvalue := size
- scope.Contract.UseGas(gas)
- //TODO: use uint256.Int instead of converting with toBig()
- var bigVal = big0
+ scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation)
+ // TODO: use uint256.Int instead of converting with toBig()
+ bigVal := big0
if !value.IsZero() {
bigVal = value.ToBig()
}
@@ -600,7 +603,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
stackvalue.SetBytes(addr.Bytes())
}
scope.Stack.push(&stackvalue)
- scope.Contract.Gas += returnGas
+ scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// call publish event to publish CREATE event
interpreter.evm.PublishEvent(CREATE, counter, scope.Contract.Address(), addr, bigVal, input, res, suberr)
@@ -621,10 +624,10 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
)
// Apply EIP150
gas -= gas / 64
- scope.Contract.UseGas(gas)
+ scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation2)
// reuse size int for stackvalue
stackvalue := size
- //TODO: use uint256.Int instead of converting with toBig()
+ // TODO: use uint256.Int instead of converting with toBig()
bigEndowment := big0
if !endowment.IsZero() {
bigEndowment = endowment.ToBig()
@@ -639,7 +642,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
stackvalue.SetBytes(addr.Bytes())
}
scope.Stack.push(&stackvalue)
- scope.Contract.Gas += returnGas
+ scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// call publish event to publish CREATE2 event
interpreter.evm.PublishEvent(CREATE2, counter, scope.Contract.Address(), addr, bigEndowment, input, res, suberr)
@@ -664,8 +667,8 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
cpyArgs := make([]byte, len(args))
copy(cpyArgs, args)
- var bigVal = big0
- //TODO: use uint256.Int instead of converting with toBig()
+ bigVal := big0
+ // TODO: use uint256.Int instead of converting with toBig()
// By using big0 here, we save an alloc for the most common case (non-ether-transferring contract calls),
// but it would make more sense to extend the usage of uint256.Int
if !value.IsZero() {
@@ -684,7 +687,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.Contract.Gas += returnGas
+ scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// call publish event to publish CALL event
interpreter.evm.PublishEvent(CALL, counter, scope.Contract.Address(), toAddr, bigVal, cpyArgs, ret, err)
return ret, nil
@@ -702,8 +705,8 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
// Get arguments from the memory.
args := scope.Memory.GetPtr(int64(inOffset.Uint64()), int64(inSize.Uint64()))
- //TODO: use uint256.Int instead of converting with toBig()
- var bigVal = big0
+ // TODO: use uint256.Int instead of converting with toBig()
+ bigVal := big0
if !value.IsZero() {
gas += params.CallStipend
bigVal = value.ToBig()
@@ -719,7 +722,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.Contract.Gas += returnGas
+ scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
return ret, nil
}
@@ -749,7 +752,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.Contract.Gas += returnGas
+ scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
// call publish event to publish CALL event
interpreter.evm.PublishEvent(DELEGATECALL, counter, scope.Contract.Address(), toAddr, scope.Contract.Value(), cpyArgs, ret, err)
@@ -778,7 +781,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
if err == nil || err == ErrExecutionReverted {
scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
}
- scope.Contract.Gas += returnGas
+ scope.Contract.RefundGas(returnGas, interpreter.evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded)
return ret, nil
}
@@ -804,11 +807,15 @@ func opStop(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
- interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
+ interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct(scope.Contract.Address())
- if interpreter.evm.Config.Tracer != nil {
- interpreter.cfg.Tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
- interpreter.cfg.Tracer.CaptureExit([]byte{}, 0, nil)
+ if tracer := interpreter.evm.Config.Tracer; tracer != nil {
+ if tracer.OnEnter != nil {
+ tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance, interpreter.evm.Context.Counter)
+ }
+ if tracer.OnExit != nil {
+ tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
+ }
}
return nil, nil
}
@@ -816,12 +823,16 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
beneficiary := scope.Stack.pop()
balance := interpreter.evm.StateDB.GetBalance(scope.Contract.Address())
- interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance)
- interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance)
+ interpreter.evm.StateDB.SubBalance(scope.Contract.Address(), balance, tracing.BalanceDecreaseSelfdestruct)
+ interpreter.evm.StateDB.AddBalance(beneficiary.Bytes20(), balance, tracing.BalanceIncreaseSelfdestruct)
interpreter.evm.StateDB.SelfDestruct6780(scope.Contract.Address())
if tracer := interpreter.evm.Config.Tracer; tracer != nil {
- tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance)
- tracer.CaptureExit([]byte{}, 0, nil)
+ if tracer.OnEnter != nil {
+ tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance, interpreter.evm.Context.Counter)
+ }
+ if tracer.OnExit != nil {
+ tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
+ }
}
return nil, nil
}
diff --git a/core/vm/interface.go b/core/vm/interface.go
index 49d8729a9..72f450c6e 100644
--- a/core/vm/interface.go
+++ b/core/vm/interface.go
@@ -20,6 +20,7 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
@@ -29,8 +30,8 @@ type StateDB interface {
CreateAccount(common.Address)
CreateContract(common.Address)
- SubBalance(common.Address, *big.Int)
- AddBalance(common.Address, *big.Int)
+ SubBalance(common.Address, *big.Int, tracing.BalanceChangeReason)
+ AddBalance(common.Address, *big.Int, tracing.BalanceChangeReason)
GetBalance(common.Address) *big.Int
GetNonce(common.Address) uint64
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index 01c49c837..cf147189e 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -22,17 +22,18 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/log"
+ "github.com/holiman/uint256"
)
// Config are the configuration options for the Interpreter
type Config struct {
- Debug bool // Enables debugging
- Tracer EVMLogger // Opcode logger
- FullCallTracing bool // Emit trace error
- NoRecursion bool // Disables call, callcode, delegate call and create
- NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
- EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
+ Debug bool // Enables debugging
+ Tracer *tracing.Hooks // Live tracer
+ NoRecursion bool // Disables call, callcode, delegate call and create
+ NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
+ EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
JumpTable [256]*operation // EVM instruction table, automatically populated if unset
@@ -49,6 +50,49 @@ type ScopeContext struct {
Contract *Contract
}
+// MemoryData returns the underlying memory slice. Callers must not modify the contents
+// of the returned data.
+func (ctx *ScopeContext) MemoryData() []byte {
+ if ctx.Memory == nil {
+ return nil
+ }
+ return ctx.Memory.Data()
+}
+
+// MemoryData returns the stack data. Callers must not modify the contents
+// of the returned data.
+func (ctx *ScopeContext) StackData() []uint256.Int {
+ if ctx.Stack == nil {
+ return nil
+ }
+ return ctx.Stack.Data()
+}
+
+// Caller returns the current caller.
+func (ctx *ScopeContext) Caller() common.Address {
+ return ctx.Contract.Caller()
+}
+
+// Address returns the address where this scope of execution is taking place.
+func (ctx *ScopeContext) Address() common.Address {
+ return ctx.Contract.Address()
+}
+
+// CallValue returns the value supplied with this call.
+func (ctx *ScopeContext) CallValue() *uint256.Int {
+ bigValue, ok := uint256.FromBig(ctx.Contract.Value())
+ if !ok {
+ return nil
+ }
+ return bigValue
+}
+
+// CallInput returns the input/calldata with this call. Callers must not modify
+// the contents of the returned data.
+func (ctx *ScopeContext) CallInput() []byte {
+ return ctx.Contract.Input
+}
+
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
@@ -129,7 +173,6 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
// considered a revert-and-consume-all-gas operation except for
// ErrExecutionReverted which means revert-and-keep-gas-left.
func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (ret []byte, err error) {
-
// Increment the call depth which is restricted to 1024
in.evm.depth++
defer func() { in.evm.depth-- }()
@@ -167,7 +210,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
// copies used by tracer
pcCopy uint64 // needed for the deferred EVMLogger
gasCopy uint64 // for EVMLogger to log gas remaining before execution
- logged bool // deferred EVMLogger should ignore already logged steps
+ logged bool // deferred Tracer should ignore already logged steps
res []byte // result of the opcode execution function
debug = in.evm.Config.Tracer != nil
)
@@ -181,15 +224,18 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
if debug {
defer func() {
- if err != nil {
- if !logged {
- in.cfg.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
- } else {
- in.cfg.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
- }
+ if err == nil {
+ return
+ }
+ if !logged && in.evm.Config.Tracer.OnOpcode != nil {
+ in.evm.Config.Tracer.OnOpcode(pcCopy, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
+ }
+ if logged && in.evm.Config.Tracer.OnFault != nil {
+ in.evm.Config.Tracer.OnFault(pcCopy, byte(op), gasCopy, cost, callContext, in.evm.depth, VMErrorFromErr(err))
}
}()
}
+
// The Interpreter main run loop (contextual). This loop runs until either an
// explicit STOP, RETURN or SELFDESTRUCT is executed, an error occurred during
// the execution of one of the operations or until the done flag is set by the
@@ -202,7 +248,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
if debug {
// Capture pre-execution values for tracing.
- logged, pcCopy, gasCopy = false, pc, contract.Gas
+ logged, logged, pcCopy, gasCopy = false, false, pc, contract.Gas
}
// Get the operation from the jump table and validate the stack to ensure there are
@@ -233,7 +279,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
// Static portion of gas
cost = operation.constantGas // For tracing
- if !contract.UseGas(operation.constantGas) {
+ if !contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
return nil, ErrOutOfGas
}
@@ -260,17 +306,23 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
var dynamicCost uint64
dynamicCost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize)
cost += dynamicCost // total cost, for debug tracing
- if err != nil || !contract.UseGas(dynamicCost) {
+ if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
return nil, ErrOutOfGas
}
}
- if memorySize > 0 {
- mem.Resize(memorySize)
- }
+ // Do tracing before memory expansion
if debug {
- in.cfg.Tracer.CaptureState(pc, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
- logged = true
+ if in.evm.Config.Tracer.OnGasChange != nil {
+ in.evm.Config.Tracer.OnGasChange(gasCopy, gasCopy-cost, tracing.GasChangeCallOpCode)
+ }
+ if in.evm.Config.Tracer.OnOpcode != nil {
+ in.evm.Config.Tracer.OnOpcode(pc, byte(op), gasCopy, cost, callContext, in.returnData, in.evm.depth, VMErrorFromErr(err))
+ logged = true
+ }
+ }
+ if memorySize > 0 {
+ mem.Resize(memorySize)
}
// execute the operation
diff --git a/core/vm/logger.go b/core/vm/logger.go
deleted file mode 100644
index 143cd0257..000000000
--- a/core/vm/logger.go
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 The go-ethereum Authors
-// This file is part of the go-ethereum library.
-//
-// The go-ethereum library is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// The go-ethereum library is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Lesser General Public License for more details.
-//
-// You should have received a copy of the GNU Lesser General Public License
-// along with the go-ethereum library. If not, see .
-
-package vm
-
-import (
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
-)
-
-// EVMLogger is used to collect execution traces from an EVM transaction
-// execution. CaptureState is called for each step of the VM with the
-// current VM state.
-// Note that reference types are actual VM data structures; make copies
-// if you need to retain them beyond the current call.
-type EVMLogger interface {
- // Transaction level
- CaptureTxStart(gasLimit uint64, payer *common.Address)
- CaptureTxEnd(restGas uint64)
- // 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)
- // Rest of call frames
- CaptureEnter(typ OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
- CaptureExit(output []byte, gasUsed uint64, err error)
- // Opcode level
- CaptureState(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error)
- CaptureFault(pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, depth int, err error)
-}
diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go
index fa4a65fd8..52ceaebb2 100644
--- a/core/vm/operations_acl.go
+++ b/core/vm/operations_acl.go
@@ -21,6 +21,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
)
@@ -79,7 +80,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
if original == value {
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
// EIP 2200 Original clause:
- //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
+ // evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200)
evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.WarmStorageReadCostEIP2929)
} else { // reset to original existing slot (2.2.2.2)
// EIP 2200 Original clause:
@@ -91,7 +92,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc {
}
}
// EIP-2200 original clause:
- //return params.SloadGasEIP2200, nil // dirty update (2.2)
+ // return params.SloadGasEIP2200, nil // dirty update (2.2)
return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.2)
}
}
@@ -170,7 +171,7 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
evm.StateDB.AddAddressToAccessList(addr)
// Charge the remaining difference here already, to correctly calculate available
// gas for call
- if !contract.UseGas(coldCost) {
+ if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
return 0, ErrOutOfGas
}
}
@@ -271,7 +272,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929
// Charge the remaining difference here already, to correctly calculate available
// gas for call
- if !contract.UseGas(coldCost) {
+ if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
return 0, ErrOutOfGas
}
total += coldCost
@@ -286,7 +287,7 @@ func makeCallVariantGasCallEIP7702(oldCalculator gasFunc) gasFunc {
evm.StateDB.AddAddressToAccessList(target)
cost = params.ColdAccountAccessCostEIP2929
}
- if !contract.UseGas(cost) {
+ if !contract.UseGas(cost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) {
return 0, ErrOutOfGas
}
total += cost
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index 14520345e..eec15959b 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -24,6 +24,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/crypto"
"github.com/ethereum/go-ethereum/params"
@@ -124,6 +125,9 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
sender = vm.AccountRef(cfg.Origin)
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
)
+ if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
+ cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
+ }
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
@@ -158,6 +162,9 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
sender = vm.AccountRef(cfg.Origin)
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
)
+ if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
+ cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
+ }
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
@@ -187,10 +194,16 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
statedb = cfg.State
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber)
)
+ if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
+ cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
+ }
// Execute the preparatory steps for state transition which includes:
// - prepare accessList(post-berlin)
// - reset transient storage(eip 1153)
statedb.Prepare(rules, cfg.Origin, cfg.Coinbase, &address, vm.ActivePrecompiles(rules), nil)
+ if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxStart != nil {
+ cfg.EVMConfig.Tracer.OnTxStart(vmenv.GetVMContext(), types.NewTx(&types.LegacyTx{To: &address, Data: input, Value: cfg.Value, Gas: cfg.GasLimit}), cfg.Origin)
+ }
// Call the code with the given configuration.
ret, leftOverGas, err := vmenv.Call(
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index 8c86b06f2..a41559829 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -331,12 +331,12 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
cfg.State, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
cfg.GasLimit = gas
if len(tracerCode) > 0 {
- tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil)
+ tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil, cfg.ChainConfig)
if err != nil {
b.Fatal(err)
}
cfg.EVMConfig = vm.Config{
- Tracer: tracer,
+ Tracer: tracer.Hooks,
}
}
var (
@@ -511,7 +511,7 @@ func TestEip2929Cases(t *testing.T) {
code, ops)
Execute(code, nil, &Config{
EVMConfig: vm.Config{
- Tracer: logger.NewMarkdownLogger(nil, os.Stdout),
+ Tracer: logger.NewMarkdownLogger(nil, os.Stdout).Hooks(),
ExtraEips: []int{2929},
},
})
@@ -664,7 +664,7 @@ func TestColdAccountAccessCost(t *testing.T) {
tracer := logger.NewStructLogger(nil)
Execute(tc.code, nil, &Config{
EVMConfig: vm.Config{
- Tracer: tracer,
+ Tracer: tracer.Hooks(),
},
})
have := tracer.StructLogs()[tc.step].GasCost
@@ -827,7 +827,7 @@ func TestRuntimeJSTracer(t *testing.T) {
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
statedb.SetCode(common.HexToAddress("0xff"), depressedCode)
- tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
+ tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MainnetChainConfig)
if err != nil {
t.Fatal(err)
}
@@ -835,7 +835,7 @@ func TestRuntimeJSTracer(t *testing.T) {
GasLimit: 1000000,
State: statedb,
EVMConfig: vm.Config{
- Tracer: tracer,
+ Tracer: tracer.Hooks,
}})
if err != nil {
t.Fatal("didn't expect error", err)
@@ -862,14 +862,14 @@ func TestJSTracerCreateTx(t *testing.T) {
code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)}
statedb, _ := state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
+ tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil, params.MainnetChainConfig)
if err != nil {
t.Fatal(err)
}
_, _, _, err = Create(code, &Config{
State: statedb,
EVMConfig: vm.Config{
- Tracer: tracer,
+ Tracer: tracer.Hooks,
}})
if err != nil {
t.Fatal(err)
@@ -975,7 +975,7 @@ func TestDelegatedAccountAccessCost(t *testing.T) {
ChainConfig: params.TestChainConfig,
State: statedb,
EVMConfig: vm.Config{
- Tracer: tracer,
+ Tracer: tracer.Hooks(),
},
})
have := tracer.StructLogs()[tc.step].GasCost
diff --git a/eth/api.go b/eth/api.go
index 368022234..7e9bfbf05 100644
--- a/eth/api.go
+++ b/eth/api.go
@@ -370,7 +370,7 @@ func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs,
} else {
blockRlp = fmt.Sprintf("0x%x", rlpBytes)
}
- if blockJSON, err = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil {
+ if blockJSON = ethapi.RPCMarshalBlock(block, true, true, api.eth.APIBackend.ChainConfig()); err != nil {
blockJSON = map[string]interface{}{"error": err.Error()}
}
results = append(results, &BadBlockArgs{
@@ -478,7 +478,6 @@ func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common
}
func storageRangeAt(st state.Trie, start []byte, maxResult int) (StorageRangeResult, error) {
-
trieIt, err := st.NodeIterator(start)
if err != nil {
return StorageRangeResult{}, err
@@ -608,7 +607,7 @@ func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64
pivot = *p
log.Info("Found fast-sync pivot marker", "number", pivot)
}
- var resolveNum = func(num rpc.BlockNumber) (uint64, error) {
+ resolveNum := func(num rpc.BlockNumber) (uint64, error) {
// We don't have state for pending (-2), so treat it as latest
if num.Int64() < 0 {
block := api.eth.blockchain.CurrentBlock()
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 9e3a3054d..649f9dd0e 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -286,7 +286,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil
}
-func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) {
+func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) {
if vmConfig == nil {
vmConfig = b.eth.blockchain.GetVMConfig()
}
@@ -466,6 +466,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
return b.eth.stateAtBlock(ctx, block, reexec, base, checkLive, 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)
}
diff --git a/eth/api_test.go b/eth/api_test.go
index 1819b1ec0..fbd250f58 100644
--- a/eth/api_test.go
+++ b/eth/api_test.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/crypto"
"github.com/ethereum/go-ethereum/trie"
@@ -78,7 +79,7 @@ func TestAccountRange(t *testing.T) {
hash := common.HexToHash(fmt.Sprintf("%x", i))
addr := common.BytesToAddress(crypto.Keccak256Hash(hash.Bytes()).Bytes())
addrs[i] = addr
- sdb.SetBalance(addrs[i], big.NewInt(1))
+ sdb.SetBalance(addrs[i], big.NewInt(1), tracing.BalanceChangeUnspecified)
if _, ok := m[addr]; ok {
t.Fatalf("bad")
} else {
diff --git a/eth/backend.go b/eth/backend.go
index 565863294..1b652a09c 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -18,6 +18,7 @@
package eth
import (
+ "encoding/json"
"errors"
"fmt"
"math/big"
@@ -52,6 +53,7 @@ import (
"github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/ethereum/go-ethereum/eth/protocols/ronin"
"github.com/ethereum/go-ethereum/eth/protocols/snap"
+ "github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
@@ -207,6 +209,17 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
StateScheme: config.StateScheme,
}
)
+ if config.VMTrace != "" {
+ traceConfig := json.RawMessage("{}")
+ if config.VMTraceConfig != "" {
+ traceConfig = json.RawMessage(config.VMTraceConfig)
+ }
+ t, err := tracers.LiveDirectory.New(config.VMTrace, traceConfig)
+ if err != nil {
+ return nil, fmt.Errorf("failed to create tracer %s: %v", config.VMTrace, err)
+ }
+ vmConfig.Tracer = t
+ }
eth.blockchain, err = core.NewBlockChain(chainDb, cacheConfig, config.Genesis, config.OverrideArrowGlacier, eth.engine, vmConfig, eth.shouldPreserve, &config.TransactionHistory)
if err != nil {
return nil, err
diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go
index 55e736b3d..678bcf2a6 100644
--- a/eth/catalyst/api.go
+++ b/eth/catalyst/api.go
@@ -81,7 +81,7 @@ type blockExecutionEnv struct {
func (env *blockExecutionEnv) commitTransaction(tx *types.Transaction, coinbase common.Address) error {
vmconfig := *env.chain.GetVMConfig()
snap := env.state.Snapshot()
- receipt, _, err := core.ApplyTransaction(env.chain.Config(), env.chain, &coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vmconfig, core.NewReceiptBloomGenerator())
+ receipt, _, err := core.ApplyTransaction(env.chain.Config(), env.chain, &coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vmconfig)
if err != nil {
env.state.RevertToSnapshot(snap)
return err
@@ -228,7 +228,7 @@ func (api *consensusAPI) AssembleBlock(params assembleBlockParams) (*executableD
}
func encodeTransactions(txs []*types.Transaction) [][]byte {
- var enc = make([][]byte, len(txs))
+ enc := make([][]byte, len(txs))
for i, tx := range txs {
enc[i], _ = tx.MarshalBinary()
}
@@ -236,7 +236,7 @@ func encodeTransactions(txs []*types.Transaction) [][]byte {
}
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
- var txs = make([]*types.Transaction, len(enc))
+ txs := make([]*types.Transaction, len(enc))
for i, encTx := range enc {
var tx types.Transaction
if err := tx.UnmarshalBinary(encTx); err != nil {
diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go
index 2efcb085f..2ad80755b 100644
--- a/eth/ethconfig/config.go
+++ b/eth/ethconfig/config.go
@@ -204,6 +204,10 @@ type Config struct {
// Enables tracking of SHA3 preimages in the VM
EnablePreimageRecording bool
+ // Enables VM tracing
+ VMTrace string
+ VMTraceConfig string
+
// Miscellaneous options
DocRoot string `toml:"-"`
diff --git a/eth/gasestimator/gasestimator.go b/eth/gasestimator/gasestimator.go
index 48aa7122f..c51122ff5 100644
--- a/eth/gasestimator/gasestimator.go
+++ b/eth/gasestimator/gasestimator.go
@@ -49,7 +49,7 @@ type Options struct {
// Estimate returns the lowest possible gas limit that allows the transaction to
// run successfully with the provided context optons. It returns an error if the
// transaction would always revert, or if there are unexpected failures.
-func Estimate(ctx context.Context, call core.Message, opts *Options, gasCap uint64) (uint64, []byte, error) {
+func Estimate(ctx context.Context, call *core.Message, opts *Options, gasCap uint64) (uint64, []byte, error) {
// Binary search the gas limit, as it may need to be higher than the amount used
var (
lo uint64 // lowest-known gas limit where tx execution fails
@@ -57,34 +57,34 @@ func Estimate(ctx context.Context, call core.Message, opts *Options, gasCap uint
)
// Determine the highest gas limit can be used during the estimation.
hi = opts.Header.GasLimit
- if call.Gas() >= params.TxGas {
- hi = call.Gas()
+ if call.GasLimit >= params.TxGas {
+ hi = call.GasLimit
}
// Normalize the max fee per gas the call is willing to spend.
var feeCap *big.Int
- if call.GasFeeCap() != nil {
- feeCap = call.GasFeeCap()
- } else if call.GasPrice() != nil {
- feeCap = call.GasPrice()
+ if call.GasFeeCap != nil {
+ feeCap = call.GasFeeCap
+ } else if call.GasPrice != nil {
+ feeCap = call.GasPrice
} else {
feeCap = common.Big0
}
// Recap the highest gas limit with account's available balance.
if feeCap.BitLen() != 0 {
- balance := opts.State.GetBalance(call.From())
+ balance := opts.State.GetBalance(call.From)
available := new(big.Int).Set(balance)
- if call.Value() != nil {
- if call.Value().Cmp(available) >= 0 {
+ if call.Amount != nil {
+ if call.Amount.Cmp(available) >= 0 {
return 0, nil, core.ErrInsufficientFundsForTransfer
}
- available.Sub(available, call.Value())
+ available.Sub(available, call.Amount)
}
- if opts.Config.IsCancun(opts.Header.Number) && len(call.BlobHashes()) > 0 {
+ if opts.Config.IsCancun(opts.Header.Number) && len(call.BlobHashes) > 0 {
blobGasPerBlob := new(big.Int).SetUint64(params.BlobTxBlobGasPerBlob)
- blobBalanceUsage := new(big.Int).SetUint64(uint64(len(call.BlobHashes())))
+ blobBalanceUsage := new(big.Int).SetUint64(uint64(len(call.BlobHashes)))
blobBalanceUsage.Mul(blobBalanceUsage, blobGasPerBlob)
- blobBalanceUsage.Mul(blobBalanceUsage, call.BlobGasFeeCap())
+ blobBalanceUsage.Mul(blobBalanceUsage, call.BlobGasFeeCap)
if blobBalanceUsage.Cmp(available) >= 0 {
return 0, nil, core.ErrInsufficientFunds
}
@@ -94,7 +94,7 @@ func Estimate(ctx context.Context, call core.Message, opts *Options, gasCap uint
// If the allowance is larger than maximum uint64, skip checking
if allowance.IsUint64() && hi > allowance.Uint64() {
- transfer := call.Value()
+ transfer := call.Amount
if transfer == nil {
transfer = new(big.Int)
}
@@ -112,8 +112,8 @@ func Estimate(ctx context.Context, call core.Message, opts *Options, gasCap uint
// directly try 21000. Returning 21000 without any execution is dangerous as
// some tx field combos might bump the price up even for plain transfers (e.g.
// unused access list items). Ever so slightly wasteful, but safer overall.
- if len(call.Data()) == 0 {
- if call.To() != nil && opts.State.GetCodeSize(*call.To()) == 0 {
+ if len(call.Data) == 0 {
+ if call.To != nil && opts.State.GetCodeSize(*call.To) == 0 {
failed, _, err := execute(ctx, call, opts, params.TxGas)
if !failed && err == nil {
return params.TxGas, nil, nil
@@ -195,24 +195,10 @@ func Estimate(ctx context.Context, call core.Message, opts *Options, gasCap uint
// returns true if the transaction fails for a reason that might be related to
// not enough gas. A non-nil error means execution failed due to reasons unrelated
// to the gas limit.
-func execute(ctx context.Context, call core.Message, opts *Options, gasLimit uint64) (bool, *core.ExecutionResult, error) {
- msg := types.NewMessage(
- call.From(),
- call.To(),
- call.Nonce(),
- call.Value(),
- gasLimit,
- call.GasPrice(),
- call.GasFeeCap(),
- call.GasTipCap(),
- call.Data(),
- call.AccessList(),
- // isFake == true means skipping nonce check
- true,
- call.BlobGasFeeCap(),
- call.BlobHashes(),
- call.SetCodeAuthorizations(),
- )
+func execute(ctx context.Context, msg *core.Message, opts *Options, gasLimit uint64) (bool, *core.ExecutionResult, error) {
+ // Configure the call for this specific execution (and revert the change after)
+ defer func(gas uint64) { msg.GasLimit = gas }(msg.GasLimit)
+ msg.GasLimit = gasLimit
// Execute the call and separate execution faults caused by a lack of gas or
// other non-fixable conditions
@@ -228,15 +214,25 @@ func execute(ctx context.Context, call core.Message, opts *Options, gasLimit uin
// run assembles the EVM as defined by the consensus rules and runs the requested
// call invocation.
-func run(ctx context.Context, call core.Message, opts *Options) (*core.ExecutionResult, error) {
+func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
// Assemble the call and the call context
var (
msgContext = core.NewEVMTxContext(call)
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
dirtyState = opts.State.Copy()
- evm = vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
)
+
+ // Lower the basefee to 0 to avoid breaking EVM
+ // invariants (basefee < feecap).
+ if msgContext.GasPrice.Sign() == 0 {
+ evmContext.BaseFee = new(big.Int)
+ }
+ if call.BlobGasFeeCap != nil && call.BlobGasFeeCap.BitLen() == 0 {
+ evmContext.BlobBaseFee = new(big.Int)
+ }
+ evm := vm.NewEVM(evmContext, msgContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
+
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
// a dangling goroutine until the outer estimation finishes, create an internal
// context for the lifetime of this method call.
@@ -253,7 +249,7 @@ func run(ctx context.Context, call core.Message, opts *Options) (*core.Execution
return nil, vmerr
}
if err != nil {
- return result, fmt.Errorf("failed with %d gas: %w", call.Gas(), err)
+ return result, fmt.Errorf("failed with %d gas: %w", call.GasLimit, err)
}
return result, nil
}
diff --git a/eth/state_accessor.go b/eth/state_accessor.go
index 3155b54f4..5b8eacc3c 100644
--- a/eth/state_accessor.go
+++ b/eth/state_accessor.go
@@ -218,7 +218,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")
@@ -247,11 +247,11 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
signer := types.MakeSigner(eth.blockchain.Config(), block.Number())
for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset
- msg, _ := tx.AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
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{})
diff --git a/eth/tracers/api.go b/eth/tracers/api.go
index e91a3e7d5..18aca133a 100644
--- a/eth/tracers/api.go
+++ b/eth/tracers/api.go
@@ -25,6 +25,7 @@ import (
"fmt"
"io/ioutil"
"math"
+ "math/big"
"os"
"runtime"
"sync"
@@ -94,7 +95,7 @@ type Backend interface {
// N.B: For executing transactions on block N, the required stateRoot is block N-1,
// so this method should be called with the parent.
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, checkLive, 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.
@@ -309,14 +310,14 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
- msg, _ := tx.AsMessage(signer, task.block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
txctx := &Context{
BlockHash: task.block.Hash(),
BlockNumber: task.block.Number(),
TxIndex: i,
TxHash: tx.Hash(),
}
- res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, task.block)
+ res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config, task.block, nil)
if err != nil {
task.results[i] = &txTraceResult{TransactionHash: tx.Hash(), Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
@@ -590,7 +591,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
return nil, err
}
var (
- msg, _ = tx.AsMessage(signer, block.BaseFee())
+ msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
txContext = core.NewEVMTxContext(msg)
vmenv = vm.NewEVM(vmctx, txContext, statedb, chainConfig, vm.Config{})
)
@@ -598,7 +599,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
- if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
+ if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
// We intentionally don't return the error here: if we do, then the RPC server will not
// return the roots. Most likely, the caller already knows that a certain transaction fails to
@@ -671,14 +672,14 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
}
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
- msg, _ := tx.AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txctx := &Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: i,
TxHash: tx.Hash(),
}
- res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config, block)
+ res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config, block, nil)
if err != nil {
return nil, err
}
@@ -714,7 +715,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
defer pend.Done()
// Fetch and execute the next transaction trace tasks
for task := range jobs {
- msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
txctx := &Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
@@ -726,7 +727,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
// concurrent use.
// See: https://github.com/ethereum/go-ethereum/issues/29114
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
- res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, block)
+ res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config, block, nil)
if err != nil {
results[task.index] = &txTraceResult{TransactionHash: txs[task.index].Hash(), Error: err.Error()}
continue
@@ -751,13 +752,13 @@ txloop:
}
// Generate the next state snapshot fast without tracing
- msg, _ := tx.AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
- if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
+ if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
failed = err
break txloop
}
@@ -821,7 +822,7 @@ func (api *API) traceInternalsAndAccounts(ctx context.Context, block *types.Bloc
defer pend.Done()
// Fetch and execute the next transaction trace tasks
for task := range jobs {
- msg, _ := txs[task.index].AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
txctx := &Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
@@ -833,7 +834,7 @@ func (api *API) traceInternalsAndAccounts(ctx context.Context, block *types.Bloc
// concurrent use.
// See: https://github.com/ethereum/go-ethereum/issues/29114
blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
- res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config, block)
+ res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config, block, nil)
if err != nil {
results.InternalTxs[task.index] = &txTraceResult{TransactionHash: txs[task.index].Hash(), Error: err.Error()}
continue
@@ -854,13 +855,13 @@ txloop:
}
// Generate the next state snapshot fast without tracing
- msg, _ := tx.AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
statedb.SetTxContext(tx.Hash(), i)
vmenv := vm.NewEVM(blockCtx, core.NewEVMTxContext(msg), statedb, api.backend.ChainConfig(), vm.Config{})
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
- if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas())); err != nil {
+ if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
failed = err
break txloop
}
@@ -953,7 +954,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
for i, tx := range block.Transactions() {
// Prepare the transaction for un-traced execution
var (
- msg, _ = tx.AsMessage(signer, block.BaseFee())
+ msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
txContext = core.NewEVMTxContext(msg)
vmConf vm.Config
dump *os.File
@@ -983,10 +984,12 @@ 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)
+ vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.Payer)
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, msg, block) {
vmenv.Config.IsSystemTransaction = true
}
- _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
+ vmRet, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
+ vmConf.Tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, err)
if writer != nil {
writer.Flush()
}
@@ -1043,11 +1046,16 @@ 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.BaseFee())
+ if err != nil {
+ return nil, err
+ }
txctx := &Context{
BlockHash: blockHash,
@@ -1055,7 +1063,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, block)
+ return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config, block, nil)
}
// TraceCall lets you trace a given eth_call. It collects the structured logs
@@ -1064,8 +1072,11 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) (interface{}, error) {
// Try to retrieve the specified block
var (
- err error
- block *types.Block
+ err error
+ block *types.Block
+ statedb *state.StateDB
+ release StateReleaseFunc
+ precompiles vm.PrecompiledContracts
)
if hash, ok := blockNrOrHash.Hash(); ok {
block, err = api.blockByHash(ctx, hash)
@@ -1090,7 +1101,7 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
- statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
+ statedb, release, err = api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
if err != nil {
return nil, err
}
@@ -1099,22 +1110,34 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
// Apply the customization rules if required.
if config != nil {
- if err := config.StateOverrides.Apply(statedb); err != nil {
+ config.BlockOverrides.Apply(&vmctx)
+ rules := api.backend.ChainConfig().Rules(vmctx.BlockNumber)
+ precompiles = vm.ActivePrecompiledContracts(rules)
+ if err := config.StateOverrides.Apply(statedb, precompiles); err != nil {
return nil, err
}
config.BlockOverrides.Apply(&vmctx)
}
// Execute the trace
- msg, err := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
- if err != nil {
+ if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
return nil, err
}
+ msg := args.ToMessage(api.backend.RPCGasCap(), block.BaseFee(), true)
+
+ // Lower the basefee to 0 to avoid breaking EVM
+ // invariants (basefee < feecap).
+ if msg.GasPrice.Sign() == 0 {
+ vmctx.BaseFee = new(big.Int)
+ }
+ if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
+ vmctx.BlobBaseFee = new(big.Int)
+ }
var traceConfig *TraceConfig
if config != nil {
traceConfig = &config.TraceConfig
}
- return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig, block)
+ return api.traceTx(ctx, args.ToTransaction(), msg, new(Context), vmctx, statedb, traceConfig, block, precompiles)
}
// traceTx configures a new tracer according to the provided configuration, and
@@ -1122,34 +1145,49 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
// be tracer dependent.
func (api *API) traceTx(
ctx context.Context,
- message core.Message,
+ tx *types.Transaction,
+ message *core.Message,
txctx *Context,
vmctx vm.BlockContext,
statedb *state.StateDB,
config *TraceConfig,
block *types.Block,
+ precompiles vm.PrecompiledContracts,
) (interface{}, error) {
// Assemble the structured logger or the JavaScript tracer
var (
- tracer Tracer
+ tracer *Tracer
err error
timeout = defaultTraceTimeout
txContext = core.NewEVMTxContext(message)
+ usedGas uint64
)
if config == nil {
config = &TraceConfig{}
}
// Default tracer is the struct logger
- tracer = logger.NewStructLogger(config.Config)
- if config.Tracer != nil {
- tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
+ if config.Tracer == nil {
+ logger := logger.NewStructLogger(config.Config)
+ tracer = &Tracer{
+ Hooks: logger.Hooks(),
+ GetResult: logger.GetResult,
+ Stop: logger.Stop,
+ }
+ } else {
+ tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig, api.backend.ChainConfig())
if err != nil {
return nil, err
}
}
+ // Set the tracer for the stateDB
+ statedb.SetLogger(tracer.Hooks)
+
// Run the transaction with tracing enabled.
- vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true, FullCallTracing: config.FullCallTracing})
+ vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
+ if precompiles != nil {
+ vmenv.SetPrecompiles(precompiles)
+ }
// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {
@@ -1174,7 +1212,7 @@ func (api *API) traceTx(
if consortium.HandleSystemTransaction(api.backend.Engine(), statedb, message, block) {
vmenv.Config.IsSystemTransaction = true
}
- _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas()))
+ _, _, err = core.ApplyMessageWithEVM(message, api.backend.ChainConfig(), new(core.GasPool).AddGas(message.GasLimit), statedb, vmctx.BlockNumber, txctx.BlockHash, tx, &usedGas, vmenv)
if err != nil {
return nil, fmt.Errorf("tracing failed: %w", err)
}
diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go
index 91c75dd2f..968398a59 100644
--- a/eth/tracers/api_test.go
+++ b/eth/tracers/api_test.go
@@ -166,7 +166,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
@@ -181,11 +181,11 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
// Recompute transactions up to the target index.
signer := types.MakeSigner(b.chainConfig, block.Number())
for idx, tx := range block.Transactions() {
- msg, _ := tx.AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
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 {
@@ -838,6 +838,7 @@ func TestTracingWithOverrides(t *testing.T) {
t.Parallel()
// Initialize test accounts
accounts := newAccounts(3)
+ ecRecoverAddress := common.HexToAddress("0x0000000000000000000000000000000000000001")
storageAccount := common.Address{0x13, 37}
genesis := &core.Genesis{
Config: params.TestChainConfig,
@@ -1021,7 +1022,7 @@ func TestTracingWithOverrides(t *testing.T) {
},
},
},
- //want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`,
+ // want: `{"gas":46900,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000539"}`,
// fakeStorage side effect
want: `{"gas":44100,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000001"}`,
},
@@ -1131,6 +1132,48 @@ func TestTracingWithOverrides(t *testing.T) {
},
want: `{"gas":25288,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000055"}`,
},
+ { // Call to precompile ECREC (0x01), but code was modified to add 1 to input
+ blockNumber: rpc.LatestBlockNumber,
+ call: ethapi.TransactionArgs{
+ From: &randomAccounts[0].addr,
+ To: &ecRecoverAddress,
+ Data: newRPCBytes(common.Hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001")),
+ },
+ config: &TraceCallConfig{
+ StateOverrides: ðapi.StateOverride{
+ randomAccounts[0].addr: ethapi.OverrideAccount{
+ Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))),
+ },
+ ecRecoverAddress: ethapi.OverrideAccount{
+ // The code below adds one to input
+ Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")),
+ MovePrecompileTo: &randomAccounts[2].addr,
+ },
+ },
+ },
+ want: `{"gas":21350,"failed":false,"returnValue":"0000000000000000000000000000000000000000000000000000000000000002"}`,
+ },
+ { // Call to ECREC Precompiled on a different address, expect the original behaviour of ECREC precompile
+ blockNumber: rpc.LatestBlockNumber,
+ call: ethapi.TransactionArgs{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr, // Moved EcRecover
+ Data: newRPCBytes(common.Hex2Bytes("82f3df49d3645876de6313df2bbe9fbce593f21341a7b03acdb9423bc171fcc9000000000000000000000000000000000000000000000000000000000000001cba13918f50da910f2d55a7ea64cf716ba31dad91856f45908dde900530377d8a112d60f36900d18eb8f9d3b4f85a697b545085614509e3520e4b762e35d0d6bd")),
+ },
+ config: &TraceCallConfig{
+ StateOverrides: ðapi.StateOverride{
+ randomAccounts[0].addr: ethapi.OverrideAccount{
+ Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether))),
+ },
+ ecRecoverAddress: ethapi.OverrideAccount{
+ // The code below adds one to input
+ Code: newRPCBytes(common.Hex2Bytes("60003560010160005260206000f3")),
+ MovePrecompileTo: &randomAccounts[2].addr, // Move EcRecover to this address
+ },
+ },
+ },
+ want: `{"gas":25664,"failed":false,"returnValue":"000000000000000000000000c6e93f4c1920eaeaa1e699f76a7a8c18e3056074"}`,
+ },
}
for i, tc := range testSuite {
result, err := api.TraceCall(context.Background(), tc.call, rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, tc.config)
diff --git a/eth/tracers/tracers.go b/eth/tracers/dir.go
similarity index 69%
rename from eth/tracers/tracers.go
rename to eth/tracers/dir.go
index 023f73ef3..1561c0328 100644
--- a/eth/tracers/tracers.go
+++ b/eth/tracers/dir.go
@@ -14,16 +14,15 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-// Package tracers is a manager for transaction tracing engines.
package tracers
import (
"encoding/json"
- "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/params"
)
// Context contains some contextual infos for a transaction execution that is not
@@ -35,17 +34,21 @@ type Context struct {
TxHash common.Hash // Hash of the transaction being traced (zero if dangling call)
}
-// Tracer interface extends vm.EVMLogger and additionally
-// allows collecting the tracing result.
-type Tracer interface {
- vm.EVMLogger
- GetResult() (json.RawMessage, error)
+// The set of methods that must be exposed by a tracer
+// for it to be available through the RPC interface.
+// This involves a method to retrieve results and one to
+// stop tracing.
+type Tracer struct {
+ *tracing.Hooks
+ GetResult func() (json.RawMessage, error)
// Stop terminates execution of the tracer at the first opportune moment.
- Stop(err error)
+ Stop func(err error)
}
-type ctorFn func(*Context, json.RawMessage) (Tracer, error)
-type jsCtorFn func(string, *Context, json.RawMessage) (Tracer, error)
+type (
+ ctorFn func(*Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
+ jsCtorFn func(string, *Context, json.RawMessage, *params.ChainConfig) (*Tracer, error)
+)
type elem struct {
ctor ctorFn
@@ -78,12 +81,15 @@ func (d *directory) RegisterJSEval(f jsCtorFn) {
// New returns a new instance of a tracer, by iterating through the
// registered lookups. Name is either name of an existing tracer
// or an arbitrary JS code.
-func (d *directory) New(name string, ctx *Context, cfg json.RawMessage) (Tracer, error) {
+func (d *directory) New(name string, ctx *Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*Tracer, error) {
+ if len(cfg) == 0 {
+ cfg = json.RawMessage("{}")
+ }
if elem, ok := d.elems[name]; ok {
- return elem.ctor(ctx, cfg)
+ return elem.ctor(ctx, cfg, chainConfig)
}
// Assume JS code
- return d.jsEval(name, ctx, cfg)
+ return d.jsEval(name, ctx, cfg, chainConfig)
}
// IsJS will return true if the given tracer will evaluate
@@ -96,27 +102,3 @@ func (d *directory) IsJS(name string) bool {
// JS eval will execute JS code
return true
}
-
-const (
- memoryPadLimit = 1024 * 1024
-)
-
-// GetMemoryCopyPadded returns offset + size as a new slice.
-// It zero-pads the slice if it extends beyond memory bounds.
-func GetMemoryCopyPadded(m *vm.Memory, offset, size int64) ([]byte, error) {
- if offset < 0 || size < 0 {
- return nil, fmt.Errorf("offset or size must not be negative")
- }
- if int(offset+size) < m.Len() { // slice fully inside memory
- return m.GetCopy(offset, size), nil
- }
- paddingNeeded := int(offset+size) - m.Len()
- if paddingNeeded > memoryPadLimit {
- return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded)
- }
- cpy := make([]byte, size)
- if overlap := int64(m.Len()) - offset; overlap > 0 {
- copy(cpy, m.GetPtr(offset, overlap))
- }
- return cpy, nil
-}
diff --git a/eth/tracers/internal/tracetest/calltrace2_test.go b/eth/tracers/internal/tracetest/calltrace2_test.go
index 9a37bddb7..42846922d 100644
--- a/eth/tracers/internal/tracetest/calltrace2_test.go
+++ b/eth/tracers/internal/tracetest/calltrace2_test.go
@@ -32,12 +32,12 @@ import (
"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"
"github.com/ethereum/go-ethereum/tests"
// Force-load native and js packages, to trigger registration
+ "github.com/ethereum/go-ethereum/eth/tracers"
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
)
@@ -166,19 +166,22 @@ func testCallTracer2(tracerName string, dirPath string, scheme string, t *testin
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, scheme)
)
defer triedb.Close()
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
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 {
+ evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer.Hooks})
+ statedb.SetLogger(tracer.Hooks)
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
+ vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
+ if err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
+ tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
// Retrieve the trace result and compare against the etalon
res, err := tracer.GetResult()
if err != nil {
@@ -249,7 +252,7 @@ func benchTracer2(tracerName string, test *callTracer2Test, b *testing.B) {
b.Fatalf("failed to parse testcase input: %v", err)
}
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err)
}
@@ -273,11 +276,11 @@ func benchTracer2(tracerName string, test *callTracer2Test, b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer})
+ evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Debug: true, Tracer: tracer.Hooks})
snap := statedb.Snapshot()
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil {
@@ -340,20 +343,24 @@ func TestZeroValueToNotExitCall2(t *testing.T) {
}
triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme)
defer triedb.Close()
+ chainConfig := params.MainnetChainConfig
// Create the tracer, the EVM environment and run it
- tracer, err := tracers.DefaultDirectory.New("callTracer2", new(tracers.Context), nil)
+ tracer, err := tracers.DefaultDirectory.New("callTracer2", new(tracers.Context), nil, chainConfig)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Debug: true, Tracer: tracer})
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
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 {
+ evm := vm.NewEVM(context, txContext, statedb, chainConfig, vm.Config{Debug: true, Tracer: tracer.Hooks})
+ statedb.SetLogger(tracer.Hooks)
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
+ vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
+ if err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
+ tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
// Retrieve the trace result and compare against the etalon
res, err := tracer.GetResult()
if err != nil {
@@ -363,10 +370,10 @@ func TestZeroValueToNotExitCall2(t *testing.T) {
if err := json.Unmarshal(res, have); err != nil {
t.Fatalf("failed to unmarshal trace result: %v", err)
}
- wantStr := `{"type":"CALL","order":0,"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0x7148","gasUsed":"0x2d0","input":"0x","output":"0x","calls":[{"type":"CALL","order":8,"from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}`
+ wantStr := `{"type":"CALL","order":0,"from":"0x682a80a6f560eec50d54e63cbeda1c324c5f8d1b","to":"0x00000000000000000000000000000000deadbeef","value":"0x0","gas":"0xc350","gasUsed":"0x54d8","input":"0x","output":"0x","calls":[{"type":"CALL","order":8,"from":"0x00000000000000000000000000000000deadbeef","to":"0x00000000000000000000000000000000000000ff","value":"0x0","gas":"0x6cbf","gasUsed":"0x0","input":"0x","output":"0x"}]}`
want := new(callTrace2)
json.Unmarshal([]byte(wantStr), want)
if !compareCallTrace2(have, want) {
- t.Error("have != want")
+ t.Errorf("trace mismatch: \nhave %+v\nwant %+v", have, want)
}
}
diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go
index 9142d5c09..96c6792fc 100644
--- a/eth/tracers/internal/tracetest/calltrace_test.go
+++ b/eth/tracers/internal/tracetest/calltrace_test.go
@@ -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"
@@ -47,9 +49,10 @@ type callContext struct {
// callLog is the result of LOG opCode
type callLog struct {
- Address common.Address `json:"address"`
- Topics []common.Hash `json:"topics"`
- Data hexutil.Bytes `json:"data"`
+ Address common.Address `json:"address"`
+ Topics []common.Hash `json:"topics"`
+ Data hexutil.Bytes `json:"data"`
+ Position hexutil.Uint `json:"position"`
}
// callTrace is the result of a callTracer run.
@@ -143,19 +146,22 @@ func testCallTracer(tracerName string, dirPath string, scheme string, t *testing
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, scheme)
)
triedb.Close()
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
+ evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
+ statedb.SetLogger(tracer.Hooks)
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
+ tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
// Retrieve the trace result and compare against the expected.
res, err := tracer.GetResult()
if err != nil {
@@ -223,7 +229,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.Fatalf("failed to parse testcase input: %v", err)
}
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)))
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err)
}
@@ -247,11 +253,11 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
+ tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
+ evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
snap := statedb.Snapshot()
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil {
@@ -266,13 +272,13 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
func TestInternals(t *testing.T) {
var (
+ config = params.MainnetChainConfig
to = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
- origin = common.HexToAddress("0x00000000000000000000000000000000feed")
- txContext = vm.TxContext{
- Origin: origin,
- GasPrice: big.NewInt(1),
- }
- context = vm.BlockContext{
+ originHex = "0x71562b71999873db5b286df957af199ec94617f7"
+ origin = common.HexToAddress(originHex)
+ signer = types.LatestSigner(config)
+ key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ context = vm.BlockContext{
CanTransfer: core.CanTransfer,
Transfer: core.Transfer,
Coinbase: common.Address{},
@@ -280,10 +286,11 @@ func TestInternals(t *testing.T) {
Time: 5,
Difficulty: big.NewInt(0x30000),
GasLimit: uint64(6000000),
+ BaseFee: new(big.Int),
}
)
- mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer {
- tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
+ mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer {
+ tr, err := tracers.DefaultDirectory.New(name, nil, cfg, config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
@@ -293,7 +300,7 @@ func TestInternals(t *testing.T) {
for _, tc := range []struct {
name string
code []byte
- tracer tracers.Tracer
+ tracer *tracers.Tracer
want string
}{
{
@@ -307,13 +314,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":"0x13880","gasUsed":"0x54d8","to":"0x00000000000000000000000000000000deadbeef","input":"0x","calls":[{"from":"0x00000000000000000000000000000000deadbeef","gas":"0xe01a","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":"0x13880","gasUsed":"0x13880","to":"0x00000000000000000000000000000000deadbeef","input":"0x","error":"stack underflow (0 \u003c=\u003e 5)","value":"0x0","type":"CALL"}`, originHex),
},
{
name: "Mem expansion in LOG0",
@@ -326,7 +333,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":"0x13880","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","position":"0x0"}],"value":"0x0","type":"CALL"}`, originHex),
},
{
// Leads to OOM on the prestate tracer
@@ -345,32 +352,53 @@ 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":"0x1c6bf52634000"}}`, originHex),
},
} {
- triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(),
- types.GenesisAlloc{
- to: core.GenesisAccount{
- Code: tc.code,
- },
- origin: core.GenesisAccount{
- Balance: big.NewInt(500000000000000),
- },
- }, false, rawdb.HashScheme)
- defer triedb.Close()
- evm := vm.NewEVM(context, txContext, statedb, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
- msg := types.NewMessage(origin, &to, 0, big.NewInt(0), 50000, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, false, nil, nil, nil)
- st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.Gas()))
- if _, err := st.TransitionDb(); err != nil {
- t.Fatalf("test %v: failed to execute transaction: %v", tc.name, err)
- }
- // Retrieve the trace result and compare against the expected
- res, err := tc.tracer.GetResult()
- if err != nil {
- t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err)
- }
- if string(res) != tc.want {
- t.Fatalf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want)
- }
+ t.Run(tc.name, func(t *testing.T) {
+ triedb, _, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(),
+ types.GenesisAlloc{
+ to: types.Account{
+ Code: tc.code,
+ },
+ origin: types.Account{
+ Balance: big.NewInt(500000000000000),
+ },
+ }, false, rawdb.HashScheme)
+ defer triedb.Close()
+ statedb.SetLogger(tc.tracer.Hooks)
+ tx, err := types.SignNewTx(key, signer, &types.LegacyTx{
+ To: &to,
+ Value: big.NewInt(0),
+ Gas: 80000,
+ GasPrice: big.NewInt(1),
+ })
+ if err != nil {
+ t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err)
+ }
+ txContext := vm.TxContext{
+ Origin: origin,
+ GasPrice: tx.GasPrice(),
+ }
+ evm := vm.NewEVM(context, txContext, statedb, config, vm.Config{Tracer: tc.tracer.Hooks})
+ 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.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
+ 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.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
+ // Retrieve the trace result and compare against the expected
+ res, err := tc.tracer.GetResult()
+ if err != nil {
+ t.Fatalf("test %v: failed to retrieve trace result: %v", tc.name, err)
+ }
+ if string(res) != tc.want {
+ t.Errorf("test %v: trace mismatch\n have: %v\n want: %v\n", tc.name, string(res), tc.want)
+ }
+ })
}
}
diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go
index 7f78bb8f2..9b6ff1325 100644
--- a/eth/tracers/internal/tracetest/flat_calltrace_test.go
+++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go
@@ -104,21 +104,22 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
defer triedb.Close()
// Create the tracer, the EVM environment and run it
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
return fmt.Errorf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
+ evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
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.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
+ 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.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
// Retrieve the trace result and compare against the etalon
res, err := tracer.GetResult()
diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go
index d1f86aaae..0ecea3240 100644
--- a/eth/tracers/internal/tracetest/prestate_test.go
+++ b/eth/tracers/internal/tracetest/prestate_test.go
@@ -114,19 +114,22 @@ func testPrestateDiffTracer(tracerName string, dirPath string, scheme string, t
triedb, _, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false, scheme)
)
defer triedb.Close()
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig, test.Genesis.Config)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer})
- msg, err := tx.AsMessage(signer, nil)
+ msg, err := core.TransactionToMessage(tx, signer, nil)
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 {
+ evm := vm.NewEVM(context, txContext, statedb, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
+ statedb.SetLogger(tracer.Hooks)
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.Payer)
+ vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
+ if err != nil {
t.Fatalf("failed to execute transaction: %v", err)
}
+ tracer.OnTxEnd(&types.Receipt{GasUsed: vmRet.UsedGas}, nil)
// Retrieve the trace result and compare against the expected
res, err := tracer.GetResult()
if err != nil {
diff --git a/eth/tracers/internal/tracetest/supply_test.go b/eth/tracers/internal/tracetest/supply_test.go
new file mode 100644
index 000000000..0def07a2b
--- /dev/null
+++ b/eth/tracers/internal/tracetest/supply_test.go
@@ -0,0 +1,557 @@
+// Copyright 2021 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package tracetest
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "math/big"
+ "os"
+ "path"
+ "path/filepath"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/consensus/ethash"
+ "github.com/ethereum/go-ethereum/core"
+ "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"
+
+ // Force-load live packages, to trigger registration
+ _ "github.com/ethereum/go-ethereum/eth/tracers/live"
+)
+
+type supplyInfoIssuance struct {
+ GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
+ Reward *hexutil.Big `json:"reward,omitempty"`
+ Withdrawals *hexutil.Big `json:"withdrawals,omitempty"`
+}
+
+type supplyInfoBurn struct {
+ EIP1559 *hexutil.Big `json:"1559,omitempty"`
+ Blob *hexutil.Big `json:"blob,omitempty"`
+ Misc *hexutil.Big `json:"misc,omitempty"`
+}
+
+type supplyInfo struct {
+ Issuance *supplyInfoIssuance `json:"issuance,omitempty"`
+ Burn *supplyInfoBurn `json:"burn,omitempty"`
+
+ // Block info
+ Number uint64 `json:"blockNumber"`
+ Hash common.Hash `json:"hash"`
+ ParentHash common.Hash `json:"parentHash"`
+}
+
+func emptyBlockGenerationFunc(b *core.BlockGen) {}
+
+func TestSupplyGenesisAlloc(t *testing.T) {
+ var (
+ key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ addr2 = crypto.PubkeyToAddress(key2.PublicKey)
+ eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
+
+ config = *params.AllEthashProtocolChanges
+
+ gspec = &core.Genesis{
+ Config: &config,
+ Alloc: types.GenesisAlloc{
+ addr1: {Balance: eth1},
+ addr2: {Balance: eth1},
+ },
+ }
+ )
+
+ expected := supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ GenesisAlloc: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
+ },
+ Number: 0,
+ Hash: common.HexToHash("0xbcc9466e9fc6a8b56f4b29ca353a421ff8b51a0c1a58ca4743b427605b08f2ca"),
+ ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
+ }
+
+ out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc)
+ if err != nil {
+ t.Fatalf("failed to test supply tracer: %v", err)
+ }
+
+ actual := out[expected.Number]
+
+ compareAsJSON(t, expected, actual)
+}
+
+func TestSupplyRewards(t *testing.T) {
+ var (
+ config = *params.AllEthashProtocolChanges
+
+ gspec = &core.Genesis{
+ Config: &config,
+ }
+ )
+
+ expected := supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
+ },
+ Number: 1,
+ Hash: common.HexToHash("0x3bb05ce32f14bce1e2334b59295eaa574cc09698b6442532a35c7b56e2403e5a"),
+ ParentHash: common.HexToHash("0xadeda0a83e337b6c073e3f0e9a17531a04009b397a9588c093b628f21b8bc5a3"),
+ }
+
+ out, _, err := testSupplyTracer(t, gspec, emptyBlockGenerationFunc)
+ if err != nil {
+ t.Fatalf("failed to test supply tracer: %v", err)
+ }
+
+ actual := out[expected.Number]
+
+ compareAsJSON(t, expected, actual)
+}
+
+func TestSupplyEip1559Burn(t *testing.T) {
+ var (
+ config = *params.AllEthashProtocolChanges
+
+ aa = common.HexToAddress("0x000000000000000000000000000000000000aaaa")
+ // A sender who makes transactions, has some eth1
+ key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei))
+ eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
+
+ gspec = &core.Genesis{
+ Config: &config,
+ BaseFee: big.NewInt(params.InitialBaseFee),
+ Alloc: types.GenesisAlloc{
+ addr1: {Balance: eth1},
+ },
+ }
+ )
+
+ gspec.Config.VenokiBlock = new(big.Int)
+ gspec.Config.KotaroBlock = new(big.Int)
+ signer := types.LatestSigner(gspec.Config)
+
+ eip1559BlockGenerationFunc := func(b *core.BlockGen) {
+ txdata := &types.DynamicFeeTx{
+ ChainID: gspec.Config.ChainID,
+ Nonce: 0,
+ To: &aa,
+ Gas: 21000,
+ GasFeeCap: gwei5,
+ GasTipCap: big.NewInt(2),
+ }
+ tx := types.NewTx(txdata)
+ tx, _ = types.SignTx(tx, signer, key1)
+
+ b.AddTx(tx)
+ b.SetBaseFee(new(big.Int).SetUint64(1000000000))
+ }
+
+ out, chain, err := testSupplyTracer(t, gspec, eip1559BlockGenerationFunc)
+ if err != nil {
+ t.Fatalf("failed to test supply tracer: %v", err)
+ }
+ var (
+ head = chain.CurrentBlock()
+ reward = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))
+ burn = new(big.Int).Mul(big.NewInt(21000), head.BaseFee())
+ expected = supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ Reward: (*hexutil.Big)(reward),
+ },
+ Burn: &supplyInfoBurn{
+ EIP1559: (*hexutil.Big)(burn),
+ },
+ Number: 1,
+ Hash: head.Hash(),
+ ParentHash: head.ParentHash(),
+ }
+ )
+
+ actual := out[expected.Number]
+ compareAsJSON(t, expected, actual)
+}
+
+// Tests fund retrieval after contract's selfdestruct.
+// Contract A calls contract B which selfdestructs, but B receives eth1
+// after the selfdestruct opcode executes from Contract A.
+// Because Contract B is removed only at the end of the transaction
+// the ether sent in between is burnt before Cancun hard fork.
+func TestSupplySelfdestruct(t *testing.T) {
+ var (
+ config = *params.TestChainConfig
+
+ aa = common.HexToAddress("0x1111111111111111111111111111111111111111")
+ bb = common.HexToAddress("0x2222222222222222222222222222222222222222")
+ dad = common.HexToAddress("0x0000000000000000000000000000000000000dad")
+ key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei))
+ eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
+
+ gspec = &core.Genesis{
+ Config: &config,
+ BaseFee: big.NewInt(params.InitialBaseFee),
+ Alloc: types.GenesisAlloc{
+ addr1: {Balance: eth1},
+ aa: {
+ Code: common.FromHex("0x61face60f01b6000527322222222222222222222222222222222222222226000806002600080855af160008103603457600080fd5b60008060008034865af1905060008103604c57600080fd5b5050"),
+ // Nonce: 0,
+ Balance: big.NewInt(0),
+ },
+ bb: {
+ Code: common.FromHex("0x6000357fface000000000000000000000000000000000000000000000000000000000000808203602f57610dad80ff5b5050"),
+ Nonce: 0,
+ Balance: eth1,
+ },
+ },
+ }
+ )
+
+ gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
+ gspec.Config.CancunBlock = nil
+ gspec.Config.ShanghaiBlock = nil
+ gspec.Config.VenokiBlock = nil
+ gspec.Config.KotaroBlock = nil
+
+ signer := types.LatestSigner(gspec.Config)
+
+ testBlockGenerationFunc := func(b *core.BlockGen) {
+ txdata := &types.LegacyTx{
+ Nonce: 0,
+ To: &aa,
+ Value: gwei5,
+ Gas: 150000,
+ GasPrice: gwei5,
+ Data: []byte{},
+ }
+
+ tx := types.NewTx(txdata)
+ tx, _ = types.SignTx(tx, signer, key1)
+
+ b.AddTx(tx)
+ }
+
+ // 1. Test pre Cancun
+ preCancunOutput, preCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
+ if err != nil {
+ t.Fatalf("Pre-cancun failed to test supply tracer: %v", err)
+ }
+
+ // Check balance at state:
+ // 1. 0x0000...000dad has 1 ether
+ // 2. A has 0 ether
+ // 3. B has 0 ether
+ statedb, _ := preCancunChain.State()
+ if got, exp := statedb.GetBalance(dad), eth1; got.Cmp(exp) != 0 {
+ t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", dad, got, exp)
+ }
+ if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.Cmp(exp) != 0 {
+ t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", aa, got, exp)
+ }
+ if got, exp := statedb.GetBalance(bb), big.NewInt(0); got.Cmp(exp) != 0 {
+ t.Fatalf("Pre-cancun address \"%v\" balance, got %v exp %v\n", bb, got, exp)
+ }
+
+ head := preCancunChain.CurrentBlock()
+ // Check live trace output
+ expected := supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
+ },
+ Burn: &supplyInfoBurn{
+ Misc: (*hexutil.Big)(big.NewInt(5000000000)),
+ },
+ Number: 1,
+ Hash: head.Hash(),
+ ParentHash: head.ParentHash(),
+ }
+
+ actual := preCancunOutput[expected.Number]
+
+ compareAsJSON(t, expected, actual)
+
+ // 2. Test post Cancun
+ gspec.Config.ShanghaiBlock = new(big.Int)
+ gspec.Config.CancunBlock = new(big.Int)
+
+ postCancunOutput, postCancunChain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
+ if err != nil {
+ t.Fatalf("Post-cancun failed to test supply tracer: %v", err)
+ }
+
+ // Check balance at state:
+ // 1. 0x0000...000dad has 1 ether
+ // 3. A has 0 ether
+ // 3. B has 5 gwei
+ statedb, _ = postCancunChain.State()
+ if got, exp := statedb.GetBalance(dad), eth1; got.Cmp(exp) != 0 {
+ t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", dad, got, exp)
+ }
+ if got, exp := statedb.GetBalance(aa), big.NewInt(0); got.Cmp(exp) != 0 {
+ t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", aa, got, exp)
+ }
+ if got, exp := statedb.GetBalance(bb), gwei5; got.Cmp(exp) != 0 {
+ t.Fatalf("Post-shanghai address \"%v\" balance, got %v exp %v\n", bb, got, exp)
+ }
+
+ // Check live trace output
+ head = postCancunChain.CurrentBlock()
+ expected = supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
+ },
+ Number: 1,
+ Hash: head.Hash(),
+ ParentHash: head.ParentHash(),
+ }
+
+ actual = postCancunOutput[expected.Number]
+
+ compareAsJSON(t, expected, actual)
+}
+
+// Tests selfdestructing contract to send its balance to itself (burn).
+// It tests both cases of selfdestructing succeding and being reverted.
+// - Contract A calls B and D.
+// - Contract B selfdestructs and sends the eth1 to itself (Burn amount to be counted).
+// - Contract C selfdestructs and sends the eth1 to itself.
+// - Contract D calls C and reverts (Burn amount of C
+// has to be reverted as well).
+func TestSupplySelfdestructItselfAndRevert(t *testing.T) {
+ var (
+ config = *params.TestChainConfig
+
+ aa = common.HexToAddress("0x1111111111111111111111111111111111111111")
+ bb = common.HexToAddress("0x2222222222222222222222222222222222222222")
+ cc = common.HexToAddress("0x3333333333333333333333333333333333333333")
+ dd = common.HexToAddress("0x4444444444444444444444444444444444444444")
+ key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ addr1 = crypto.PubkeyToAddress(key1.PublicKey)
+ gwei5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.GWei))
+ eth1 = new(big.Int).Mul(common.Big1, big.NewInt(params.Ether))
+ eth2 = new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))
+ eth5 = new(big.Int).Mul(big.NewInt(5), big.NewInt(params.Ether))
+
+ gspec = &core.Genesis{
+ Config: &config,
+ // BaseFee: big.NewInt(params.InitialBaseFee),
+ Alloc: types.GenesisAlloc{
+ addr1: {Balance: eth1},
+ aa: {
+ // Contract code in YUL:
+ //
+ // object "ContractA" {
+ // code {
+ // let B := 0x2222222222222222222222222222222222222222
+ // let D := 0x4444444444444444444444444444444444444444
+
+ // // Call to Contract B
+ // let resB:= call(gas(), B, 0, 0x0, 0x0, 0, 0)
+
+ // // Call to Contract D
+ // let resD := call(gas(), D, 0, 0x0, 0x0, 0, 0)
+ // }
+ // }
+ Code: common.FromHex("0x73222222222222222222222222222222222222222273444444444444444444444444444444444444444460006000600060006000865af160006000600060006000865af150505050"),
+ Balance: common.Big0,
+ },
+ bb: {
+ // Contract code in YUL:
+ //
+ // object "ContractB" {
+ // code {
+ // let self := address()
+ // selfdestruct(self)
+ // }
+ // }
+ Code: common.FromHex("0x3080ff50"),
+ Balance: eth5,
+ },
+ cc: {
+ Code: common.FromHex("0x3080ff50"),
+ Balance: eth1,
+ },
+ dd: {
+ // Contract code in YUL:
+ //
+ // object "ContractD" {
+ // code {
+ // let C := 0x3333333333333333333333333333333333333333
+
+ // // Call to Contract C
+ // let resC := call(gas(), C, 0, 0x0, 0x0, 0, 0)
+
+ // // Revert
+ // revert(0, 0)
+ // }
+ // }
+ Code: common.FromHex("0x73333333333333333333333333333333333333333360006000600060006000855af160006000fd5050"),
+ Balance: eth2,
+ },
+ },
+ }
+ )
+
+ gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
+ gspec.Config.CancunBlock = nil
+ gspec.Config.ShanghaiBlock = nil
+ gspec.Config.VenokiBlock = nil
+ gspec.Config.KotaroBlock = nil
+
+ signer := types.LatestSigner(gspec.Config)
+
+ testBlockGenerationFunc := func(b *core.BlockGen) {
+ txdata := &types.LegacyTx{
+ Nonce: 0,
+ To: &aa,
+ Value: common.Big0,
+ Gas: 150000,
+ GasPrice: gwei5,
+ Data: []byte{},
+ }
+
+ tx := types.NewTx(txdata)
+ tx, _ = types.SignTx(tx, signer, key1)
+
+ b.AddTx(tx)
+ }
+
+ output, chain, err := testSupplyTracer(t, gspec, testBlockGenerationFunc)
+ if err != nil {
+ t.Fatalf("failed to test supply tracer: %v", err)
+ }
+
+ // Check balance at state:
+ // 1. A has 0 ether
+ // 2. B has 0 ether, burned
+ // 3. C has 2 ether, selfdestructed but parent D reverted
+ // 4. D has 1 ether, reverted
+ statedb, _ := chain.State()
+ if got, exp := statedb.GetBalance(aa), common.Big0; got.Cmp(exp) != 0 {
+ t.Fatalf("address \"%v\" balance, got %v exp %v\n", aa, got, exp)
+ }
+ if got, exp := statedb.GetBalance(bb), common.Big0; got.Cmp(exp) != 0 {
+ t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
+ }
+ if got, exp := statedb.GetBalance(cc), eth1; got.Cmp(exp) != 0 {
+ t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
+ }
+ if got, exp := statedb.GetBalance(dd), eth2; got.Cmp(exp) != 0 {
+ t.Fatalf("address \"%v\" balance, got %v exp %v\n", bb, got, exp)
+ }
+
+ // Check live trace output
+ block := chain.GetBlockByNumber(1)
+
+ expected := supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ Reward: (*hexutil.Big)(new(big.Int).Mul(common.Big2, big.NewInt(params.Ether))),
+ },
+ Burn: &supplyInfoBurn{
+ Misc: (*hexutil.Big)(eth5), // 5ETH burned from contract B
+ },
+ Number: 1,
+ Hash: block.Hash(),
+ ParentHash: block.ParentHash(),
+ }
+
+ actual := output[expected.Number]
+
+ compareAsJSON(t, expected, actual)
+}
+
+func testSupplyTracer(t *testing.T, genesis *core.Genesis, gen func(*core.BlockGen)) ([]supplyInfo, *core.BlockChain, error) {
+ var (
+ engine = ethash.NewFaker()
+ )
+
+ traceOutputPath := filepath.ToSlash(t.TempDir())
+ traceOutputFilename := path.Join(traceOutputPath, "supply.jsonl")
+
+ // Load supply tracer
+ tracer, err := tracers.LiveDirectory.New("supply", json.RawMessage(fmt.Sprintf(`{"path":"%s"}`, traceOutputPath)))
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to create call tracer: %v", err)
+ }
+
+ chain, err := core.NewBlockChain(rawdb.NewMemoryDatabase(), core.DefaultCacheConfigWithScheme(rawdb.PathScheme), genesis, nil, engine, vm.Config{Tracer: tracer}, nil, nil)
+ if err != nil {
+ return nil, nil, fmt.Errorf("failed to create tester chain: %v", err)
+ }
+ defer chain.Stop()
+
+ _, blocks, _ := core.GenerateChainWithGenesis(genesis, engine, 1, func(i int, b *core.BlockGen) {
+ b.SetCoinbase(common.Address{1})
+ b.SetDifficulty(big.NewInt(7))
+ gen(b)
+ })
+
+ if n, err := chain.InsertChain(blocks, nil); err != nil {
+ return nil, chain, fmt.Errorf("block %d: failed to insert into chain: %v", n, err)
+ }
+
+ // Check and compare the results
+ file, err := os.OpenFile(traceOutputFilename, os.O_RDONLY, 0666)
+ if err != nil {
+ return nil, chain, fmt.Errorf("failed to open output file: %v", err)
+ }
+ defer file.Close()
+
+ var output []supplyInfo
+ scanner := bufio.NewScanner(file)
+
+ for scanner.Scan() {
+ blockBytes := scanner.Bytes()
+
+ var info supplyInfo
+ if err := json.Unmarshal(blockBytes, &info); err != nil {
+ return nil, chain, fmt.Errorf("failed to unmarshal result: %v", err)
+ }
+
+ output = append(output, info)
+ }
+
+ return output, chain, nil
+}
+
+func compareAsJSON(t *testing.T, expected interface{}, actual interface{}) {
+ want, err := json.Marshal(expected)
+ if err != nil {
+ t.Fatalf("failed to marshal expected value to JSON: %v", err)
+ }
+
+ have, err := json.Marshal(actual)
+ if err != nil {
+ t.Fatalf("failed to marshal actual value to JSON: %v", err)
+ }
+
+ if !bytes.Equal(want, have) {
+ t.Fatalf("incorrect supply info: expected %s, got %s", string(want), string(have))
+ }
+}
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json
index 9b45b52fe..ed3688a94 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json
@@ -56,6 +56,16 @@
"value": "0x0",
"gas": "0x1f97e",
"gasUsed": "0x72de",
- "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000"
+ "input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000",
+ "calls": [{
+ "from":"0x6c06b16512b332e6cd8293a2974872674716ce18",
+ "gas":"0x8fc",
+ "gasUsed":"0x0",
+ "to":"0x66fdfd05e46126a07465ad24e40cc0597bc1ef31",
+ "input":"0x",
+ "error":"insufficient balance for transfer",
+ "value":"0x14d1120d7b160000",
+ "type":"CALL"
+ }]
}
}
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/create.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/create.json
index 8699bf3e7..df0b2872b 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/create.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/create.json
@@ -47,8 +47,8 @@
"input": "0xf907ef098504e3b29200830897be8080b9079c606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a1129a01060f46676a5dff6f407f0f51eb6f37f5c8c54e238c70221e18e65fc29d3ea65a0557b01c50ff4ffaac8ed6e5d31237a4ecbac843ab1bfe8bb0165a0060df7c54f",
"result": {
"from": "0x13e4acefe6a6700604929946e70e6443e4e73447",
- "gas": "0x5e106",
- "gasUsed": "0x5e106",
+ "gas": "0x897be",
+ "gasUsed": "0x897be",
"input": "0x606060405260405160208061077c83398101604052808051906020019091905050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415151561007d57600080fd5b336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506001600460006101000a81548160ff02191690831515021790555050610653806101296000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029000000000000000000000000c65e620a3a55451316168d57e268f5702ef56a11",
"output": "0x606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806305e4382a146100855780631c02708d146100ae5780632e1a7d4d146100c35780635114cb52146100e6578063a37dda2c146100fe578063ae200e7914610153578063b5769f70146101a8575b005b341561009057600080fd5b6100986101d1565b6040518082815260200191505060405180910390f35b34156100b957600080fd5b6100c16101d7565b005b34156100ce57600080fd5b6100e460048080359060200190919050506102eb565b005b6100fc6004808035906020019091905050610513565b005b341561010957600080fd5b6101116105d6565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b341561015e57600080fd5b6101666105fc565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b34156101b357600080fd5b6101bb610621565b6040518082815260200191505060405180910390f35b60025481565b60011515600460009054906101000a900460ff1615151415156101f957600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102a15750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b15156102ac57600080fd5b6000600460006101000a81548160ff0219169083151502179055506003543073ffffffffffffffffffffffffffffffffffffffff163103600281905550565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806103935750600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16145b151561039e57600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16141561048357600060025411801561040757506002548111155b151561041257600080fd5b80600254036002819055506000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561047e57600080fd5b610510565b600060035411801561049757506003548111155b15156104a257600080fd5b8060035403600381905550600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f19350505050151561050f57600080fd5b5b50565b60011515600460009054906101000a900460ff16151514151561053557600080fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614801561059657506003548160035401115b80156105bd575080600354013073ffffffffffffffffffffffffffffffffffffffff163110155b15156105c857600080fd5b806003540160038190555050565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600354815600a165627a7a72305820c3b849e8440987ce43eae3097b77672a69234d516351368b03fe5b7de03807910029",
"to": "0x7dc9c9730689ff0b0fd506c67db815f12d90a448",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/deep_calls.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/deep_calls.json
index 5e89401ea..f96e851b2 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/deep_calls.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/deep_calls.json
@@ -115,8 +115,8 @@
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",
"input": "0x51a34eb80000000000000000000000000000000000000000000000280faf689c35ac0000",
"output": "0x",
- "gas": "0x37b38",
- "gasUsed": "0x12bb3",
+ "gas": "0x3d090",
+ "gasUsed": "0x1810b",
"value": "0x0",
"calls": [
{
@@ -441,4 +441,4 @@
}
]
}
-}
+}
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/delegatecall.json
index cca8f3087..1e8b3508b 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/delegatecall.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/delegatecall.json
@@ -90,10 +90,9 @@
],
"from": "0xa529806c67cc6486d4d62024471772f47f6fd672",
"order": 0,
- "gas": "0x2d6e28",
- "gasUsed": "0x64bd",
+ "gas": "0x2dc6c0",
+ "gasUsed": "0xbd55",
"input": "0x7065cb480000000000000000000000001523e55a1ca4efbae03355775ae89f8d7699ad9e",
- "output": "0x",
"to": "0x269296dddce321a6bcbaa2f0181127593d732cba",
"type": "CALL",
"value": "0x0"
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_create_oog_outer_throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_create_oog_outer_throw.json
index 2e540d84a..ea00c5576 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_create_oog_outer_throw.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_create_oog_outer_throw.json
@@ -62,7 +62,6 @@
"gas": "0x39ff0",
"gasUsed": "0x39ff0",
"input": "0x606060405234620000005760405160208062001fd283398101604052515b805b600a8054600160a060020a031916600160a060020a0383161790555b506001600d819055600e81905560408051808201909152600c8082527f566f74696e672053746f636b00000000000000000000000000000000000000006020928301908152600b805460008290528251601860ff1990911617825590947f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9600291831615610100026000190190921604601f0193909304830192906200010c565b828001600101855582156200010c579182015b828111156200010c578251825591602001919060010190620000ef565b5b50620001309291505b808211156200012c576000815560010162000116565b5090565b50506040805180820190915260038082527f43565300000000000000000000000000000000000000000000000000000000006020928301908152600c805460008290528251600660ff1990911617825590937fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c760026001841615610100026000190190931692909204601f010481019291620001f7565b82800160010185558215620001f7579182015b82811115620001f7578251825591602001919060010190620001da565b5b506200021b9291505b808211156200012c576000815560010162000116565b5090565b50505b505b611da280620002306000396000f3006060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182",
- "output": "0x6060604052361561019a5763ffffffff60e060020a600035041662e1986d811461019f57806302a72a4c146101d657806306eb4e421461020157806306fdde0314610220578063095ea7b3146102ad578063158ccb99146102dd57806318160ddd146102f85780631cf65a781461031757806323b872dd146103365780632c71e60a1461036c57806333148fd6146103ca578063435ebc2c146103f55780635eeb6e451461041e578063600e85b71461043c5780636103d70b146104a157806362c1e46a146104b05780636c182e99146104ba578063706dc87c146104f057806370a082311461052557806377174f851461055057806395d89b411461056f578063a7771ee3146105fc578063a9059cbb14610629578063ab377daa14610659578063b25dbb5e14610685578063b89a73cb14610699578063ca5eb5e1146106c6578063cbcf2e5a146106e1578063d21f05ba1461070e578063d347c2051461072d578063d96831e114610765578063dd62ed3e14610777578063df3c211b146107a8578063e2982c21146107d6578063eb944e4c14610801575b610000565b34610000576101d4600160a060020a036004351660243567ffffffffffffffff6044358116906064358116906084351661081f565b005b34610000576101ef600160a060020a0360043516610a30565b60408051918252519081900360200190f35b34610000576101ef610a4f565b60408051918252519081900360200190f35b346100005761022d610a55565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516602435610ae3565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516610b4e565b005b34610000576101ef610b89565b60408051918252519081900360200190f35b34610000576101ef610b8f565b60408051918252519081900360200190f35b34610000576102c9600160a060020a0360043581169060243516604435610b95565b604080519115158252519081900360200190f35b3461000057610388600160a060020a0360043516602435610bb7565b60408051600160a060020a039096168652602086019490945267ffffffffffffffff928316858501529082166060850152166080830152519081900360a00190f35b34610000576101ef600160a060020a0360043516610c21565b60408051918252519081900360200190f35b3461000057610402610c40565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d4600160a060020a0360043516602435610c4f565b005b3461000057610458600160a060020a0360043516602435610cc9565b60408051600160a060020a03909716875260208701959095528585019390935267ffffffffffffffff9182166060860152811660808501521660a0830152519081900360c00190f35b34610000576101d4610d9e565b005b6101d4610e1e565b005b34610000576104d3600160a060020a0360043516610e21565b6040805167ffffffffffffffff9092168252519081900360200190f35b3461000057610402600160a060020a0360043516610ead565b60408051600160a060020a039092168252519081900360200190f35b34610000576101ef600160a060020a0360043516610ef9565b60408051918252519081900360200190f35b34610000576101ef610f18565b60408051918252519081900360200190f35b346100005761022d610f1e565b604080516020808252835181830152835191928392908301918501908083838215610273575b80518252602083111561027357601f199092019160209182019101610253565b505050905090810190601f16801561029f5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34610000576102c9600160a060020a0360043516610fac565b604080519115158252519081900360200190f35b34610000576102c9600160a060020a0360043516602435610fc2565b604080519115158252519081900360200190f35b3461000057610402600435610fe2565b60408051600160a060020a039092168252519081900360200190f35b34610000576101d46004351515610ffd565b005b34610000576102c9600160a060020a036004351661104c565b604080519115158252519081900360200190f35b34610000576101d4600160a060020a0360043516611062565b005b34610000576102c9600160a060020a0360043516611070565b604080519115158252519081900360200190f35b34610000576101ef6110f4565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351667ffffffffffffffff602435166110fa565b60408051918252519081900360200190f35b34610000576101d4600435611121565b005b34610000576101ef600160a060020a03600435811690602435166111c6565b60408051918252519081900360200190f35b34610000576101ef6004356024356044356064356084356111f3565b60408051918252519081900360200190f35b34610000576101ef600160a060020a036004351661128c565b60408051918252519081900360200190f35b34610000576101d4600160a060020a036004351660243561129e565b005b6040805160a08101825260008082526020820181905291810182905260608101829052608081019190915267ffffffffffffffff848116908416101561086457610000565b8367ffffffffffffffff168267ffffffffffffffff16101561088557610000565b8267ffffffffffffffff168267ffffffffffffffff1610156108a657610000565b506040805160a081018252600160a060020a033381168252602080830188905267ffffffffffffffff80871684860152858116606085015287166080840152908816600090815260039091529190912080546001810180835582818380158290116109615760030281600302836000526020600020918201910161096191905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050916000526020600020906003020160005b5082518154600160a060020a031916600160a060020a03909116178155602083015160018201556040830151600290910180546060850151608086015167ffffffffffffffff1990921667ffffffffffffffff948516176fffffffffffffffff00000000000000001916604060020a918516919091021777ffffffffffffffff000000000000000000000000000000001916608060020a939091169290920291909117905550610a268686610fc2565b505b505050505050565b600160a060020a0381166000908152600360205260409020545b919050565b60055481565b600b805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b600160a060020a03338116600081815260026020908152604080832094871680845294825280832086905580518681529051929493927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060015b92915050565b600a5433600160a060020a03908116911614610b6957610000565b600a8054600160a060020a031916600160a060020a0383161790555b5b50565b60005481565b60005b90565b6000610ba2848484611600565b610bad8484846116e2565b90505b9392505050565b600360205281600052604060002081815481101561000057906000526020600020906003020160005b5080546001820154600290920154600160a060020a03909116935090915067ffffffffffffffff80821691604060020a8104821691608060020a9091041685565b600160a060020a0381166000908152600860205260409020545b919050565b600a54600160a060020a031681565b600a5433600160a060020a03908116911614610c6a57610000565b610c7660005482611714565b6000908155600160a060020a038316815260016020526040902054610c9b9082611714565b600160a060020a038316600090815260016020526040812091909155610cc390839083611600565b5b5b5050565b6000600060006000600060006000600360008a600160a060020a0316600160a060020a0316815260200190815260200160002088815481101561000057906000526020600020906003020160005b508054600182015460028301546040805160a081018252600160a060020a039094168085526020850184905267ffffffffffffffff808416928601839052604060020a8404811660608701819052608060020a9094041660808601819052909c50929a509197509095509350909150610d90904261172d565b94505b509295509295509295565b33600160a060020a038116600090815260066020526040902054801515610dc457610000565b8030600160a060020a0316311015610ddb57610000565b600160a060020a0382166000818152600660205260408082208290555183156108fc0291849190818181858888f193505050501515610cc357610000565b5b5050565b5b565b600160a060020a03811660009081526003602052604081205442915b81811015610ea557600160a060020a03841660009081526003602052604090208054610e9a9190839081101561000057906000526020600020906003020160005b5060020154604060020a900467ffffffffffffffff168461177d565b92505b600101610e3d565b5b5050919050565b600160a060020a0380821660009081526007602052604081205490911615610eef57600160a060020a0380831660009081526007602052604090205416610ef1565b815b90505b919050565b600160a060020a0381166000908152600160205260409020545b919050565b600d5481565b600c805460408051602060026001851615610100026000190190941693909304601f81018490048402820184019092528181529291830182828015610adb5780601f10610ab057610100808354040283529160200191610adb565b820191906000526020600020905b815481529060010190602001808311610abe57829003601f168201915b505050505081565b60006000610fb983610c21565b1190505b919050565b6000610fcf338484611600565b610fd983836117ac565b90505b92915050565b600460205260009081526040902054600160a060020a031681565b8015801561101a575061100f33610ef9565b61101833610c21565b115b1561102457610000565b33600160a060020a03166000908152600960205260409020805460ff19168215151790555b50565b60006000610fb983610ef9565b1190505b919050565b610b8533826117dc565b5b50565b600a54604080516000602091820181905282517fcbcf2e5a000000000000000000000000000000000000000000000000000000008152600160a060020a03868116600483015293519194939093169263cbcf2e5a92602480830193919282900301818787803b156100005760325a03f115610000575050604051519150505b919050565b600e5481565b6000610fd961110984846118b2565b61111385856119b6565b611a05565b90505b92915050565b600a5433600160a060020a0390811691161461113c57610000565b61114860005482611a1f565b600055600554600190101561116c57600a5461116c90600160a060020a0316611a47565b5b600a54600160a060020a03166000908152600160205260409020546111929082611a1f565b600a8054600160a060020a039081166000908152600160205260408120939093559054610b8592911683611600565b5b5b50565b600160a060020a038083166000908152600260209081526040808320938516835292905220545b92915050565b6000600060008487101561120a5760009250611281565b8387111561121a57879250611281565b61123f6112308961122b888a611714565b611a90565b61123a8689611714565b611abc565b915081925061124e8883611714565b905061127e8361127961126a8461122b8c8b611714565b611a90565b61123a888b611714565b611abc565b611a1f565b92505b505095945050505050565b60066020526000908152604090205481565b600160a060020a03821660009081526003602052604081208054829190849081101561000057906000526020600020906003020160005b50805490925033600160a060020a039081169116146112f357610000565b6040805160a0810182528354600160a060020a0316815260018401546020820152600284015467ffffffffffffffff80821693830193909352604060020a810483166060830152608060020a900490911660808201526113539042611af9565b600160a060020a0385166000908152600360205260409020805491925090849081101561000057906000526020600020906003020160005b508054600160a060020a031916815560006001820181905560029091018054600160c060020a0319169055600160a060020a0385168152600360205260409020805460001981019081101561000057906000526020600020906003020160005b50600160a060020a03851660009081526003602052604090208054859081101561000057906000526020600020906003020160005b5081548154600160a060020a031916600160a060020a03918216178255600180840154908301556002928301805493909201805467ffffffffffffffff191667ffffffffffffffff948516178082558354604060020a908190048616026fffffffffffffffff000000000000000019909116178082559254608060020a9081900490941690930277ffffffffffffffff00000000000000000000000000000000199092169190911790915584166000908152600360205260409020805460001981018083559190829080158290116115485760030281600302836000526020600020918201910161154891905b8082111561095d578054600160a060020a031916815560006001820155600281018054600160c060020a0319169055600301610926565b5090565b5b505050600160a060020a033316600090815260016020526040902054611570915082611a1f565b600160a060020a03338116600090815260016020526040808220939093559086168152205461159f9082611714565b600160a060020a038086166000818152600160209081526040918290209490945580518581529051339093169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a35b50505050565b600160a060020a0383161561166e576116466008600061161f86610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611714565b6008600061165386610ead565b600160a060020a031681526020810191909152604001600020555b600160a060020a038216156116dc576116b46008600061168d85610ead565b600160a060020a0316600160a060020a031681526020019081526020016000205482611a1f565b600860006116c185610ead565b600160a060020a031681526020810191909152604001600020555b5b505050565b600083826116f082426110fa565b8111156116fc57610000565b611707868686611b1b565b92505b5b50509392505050565b600061172283831115611b4d565b508082035b92915050565b6000610fd983602001518367ffffffffffffffff16856080015167ffffffffffffffff16866040015167ffffffffffffffff16876060015167ffffffffffffffff166111f3565b90505b92915050565b60008167ffffffffffffffff168367ffffffffffffffff1610156117a15781610fd9565b825b90505b92915050565b600033826117ba82426110fa565b8111156117c657610000565b6117d08585611b5d565b92505b5b505092915050565b6117e582610ef9565b6117ee83610c21565b11156117f957610000565b600160a060020a03811660009081526009602052604090205460ff16158015611834575081600160a060020a031681600160a060020a031614155b1561183e57610000565b61184782611070565b1561185157610000565b611864828261185f85610ef9565b611600565b600160a060020a0382811660009081526007602052604090208054600160a060020a031916918316918217905561189a82610ead565b600160a060020a031614610cc357610000565b5b5050565b600160a060020a038216600090815260036020526040812054815b818110156119885761197d836112796003600089600160a060020a0316600160a060020a0316815260200190815260200160002084815481101561000057906000526020600020906003020160005b506040805160a0810182528254600160a060020a031681526001830154602082015260029092015467ffffffffffffffff80821692840192909252604060020a810482166060840152608060020a900416608082015287611af9565b611a1f565b92505b6001016118cd565b600160a060020a0385166000908152600160205260409020546117d09084611714565b92505b505092915050565b600060006119c384611070565b80156119d157506000600d54115b90506119fb816119e9576119e485610ef9565b6119ec565b60005b6111138686611b7b565b611a05565b91505b5092915050565b60008183106117a15781610fd9565b825b90505b92915050565b6000828201611a3c848210801590611a375750838210155b611b4d565b8091505b5092915050565b611a508161104c565b15611a5a57610b85565b6005805460009081526004602052604090208054600160a060020a031916600160a060020a038416179055805460010190555b50565b6000828202611a3c841580611a37575083858381156100005704145b611b4d565b8091505b5092915050565b60006000611acc60008411611b4d565b8284811561000057049050611a3c838581156100005706828502018514611b4d565b8091505b5092915050565b6000610fd98360200151611b0d858561172d565b611714565b90505b92915050565b60008382611b2982426110fa565b811115611b3557610000565b611707868686611b8f565b92505b5b50509392505050565b801515610b8557610000565b5b50565b6000611b6883611a47565b610fd98383611c92565b90505b92915050565b6000610fd983610ef9565b90505b92915050565b600160a060020a038084166000908152600260209081526040808320338516845282528083205493861683526001909152812054909190611bd09084611a1f565b600160a060020a038086166000908152600160205260408082209390935590871681522054611bff9084611714565b600160a060020a038616600090815260016020526040902055611c228184611714565b600160a060020a038087166000818152600260209081526040808320338616845282529182902094909455805187815290519288169391927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef929181900390910190a3600191505b509392505050565b60003382611ca082426110fa565b811115611cac57610000565b6117d08585611cc2565b92505b5b505092915050565b600160a060020a033316600090815260016020526040812054611ce59083611714565b600160a060020a033381166000908152600160205260408082209390935590851681522054611d149083611a1f565b600160a060020a038085166000818152600160209081526040918290209490945580518681529051919333909316927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a35060015b929150505600a165627a7a72305820bfa5ddd3fecf3f43aed25385ec7ec3ef79638c2e58d99f85d9a3cc494183bf160029",
"type": "CREATE",
"value": "0x0"
}
@@ -70,10 +69,9 @@
"error": "invalid jump destination",
"from": "0xe4a13bc304682a903e9472f469c33801dd18d9e8",
"order": 0,
- "gas": "0x435c8",
- "gasUsed": "0x435c8",
+ "gas": "0x493e0",
+ "gasUsed": "0x493e0",
"input": "0x3b91f506000000000000000000000000a14bdd7e5666d784dcce98ad24d383a6b1cd4182000000000000000000000000e4a13bc304682a903e9472f469c33801dd18d9e8",
- "output": "0x",
"to": "0x1d3ddf7caf024f253487e18bc4a15b1a360c170a",
"type": "CALL",
"value": "0x0"
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_instafail.json
index 6e221b3c0..8c640b24a 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_instafail.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_instafail.json
@@ -51,13 +51,23 @@
"input": "0xf889038504a81557008301f97e946c06b16512b332e6cd8293a2974872674716ce1880a42e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b1600002aa0e2a6558040c5d72bc59f2fb62a38993a314c849cd22fb393018d2c5af3112095a01bdb6d7ba32263ccc2ecc880d38c49d9f0c5a72d8b7908e3122b31356d349745",
"result": {
"type": "CALL",
+ "order": 0,
"from": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31",
"to": "0x6c06b16512b332e6cd8293a2974872674716ce18",
"value": "0x0",
- "gas": "0x1a466",
- "gasUsed": "0x1dc6",
+ "gas": "0x1f97e",
+ "gasUsed": "0x72de",
"input": "0x2e1a7d4d00000000000000000000000000000000000000000000000014d1120d7b160000",
- "output": "0x",
- "calls": []
+ "calls": [{
+ "from":"0x6c06b16512b332e6cd8293a2974872674716ce18",
+ "order": 59,
+ "gas":"0x8fc",
+ "gasUsed":"0x0",
+ "to":"0x66fdfd05e46126a07465ad24e40cc0597bc1ef31",
+ "input":"0x",
+ "error":"insufficient balance for transfer",
+ "value":"0x14d1120d7b160000",
+ "type":"CALL"
+ }]
}
}
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_throw_outer_revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_throw_outer_revert.json
index e868908a4..5cc9914c3 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_throw_outer_revert.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/inner_throw_outer_revert.json
@@ -73,8 +73,8 @@
"error": "execution reverted",
"from": "0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826",
"order": 0,
- "gas": "0x78d9e",
- "gasUsed": "0x76fc0",
+ "gas": "0x7dfa6",
+ "gasUsed": "0x7c1c8",
"input": "0x",
"to": "0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76",
"type": "CALL",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/oog.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/oog.json
index de4fed6ab..333bdd038 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/oog.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/oog.json
@@ -50,8 +50,8 @@
"result": {
"error": "out of gas",
"from": "0x94194bc2aaf494501d7880b61274a169f6502a54",
- "gas": "0x7045",
- "gasUsed": "0x7045",
+ "gas": "0xca1d",
+ "gasUsed": "0xca1d",
"input": "0xa9059cbb000000000000000000000000e77b1ac803616503510bed0086e3a7be2627a69900000000000000000000000000000000000000000000000000000009502f9000",
"to": "0x43064693d3d38ad6a7cb579e0d6d9718c8aa6b62",
"type": "CALL",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/revert.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/revert.json
index 059040a1c..3207a298a 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/revert.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/revert.json
@@ -48,8 +48,8 @@
"result": {
"error": "execution reverted",
"from": "0x0f6cef2b7fbb504782e35aa82a2207e816a2b7a9",
- "gas": "0x2d55e8",
- "gasUsed": "0xc3",
+ "gas": "0x2dc6c0",
+ "gasUsed": "0x719b",
"input": "0x73b40a5c000000000000000000000000400de2e016bda6577407dfc379faba9899bc73ef0000000000000000000000002cc31912b2b0f3075a87b3640923d45a26cef3ee000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000064d79d8e6c7265636f76657279416464726573730000000000000000000000000000000000000000000000000000000000383e3ec32dc0f66d8fe60dbdc2f6815bdf73a988383e3ec32dc0f66d8fe60dbdc2f6815bdf73a98800000000000000000000000000000000000000000000000000000000000000000000000000000000",
"to": "0xabbcd5b340c80b5f1c0545c04c987b87310296ae",
"type": "CALL",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/revert_reason.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/revert_reason.json
index 094b04467..f02e5c686 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/revert_reason.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/revert_reason.json
@@ -27,7 +27,7 @@
"byzantiumBlock": 0,
"constantinopleBlock": 0,
"petersburgBlock": 0,
- "IstanbulBlock":1561651,
+ "IstanbulBlock": 1561651,
"chainId": 5,
"daoForkSupport": true,
"eip150Block": 0,
@@ -53,12 +53,13 @@
"result": {
"error": "execution reverted",
"from": "0xf7579c3d8a669c89d5ed246a22eb6db8f6fedbf1",
- "gas": "0x2d7308",
- "gasUsed": "0x588",
+ "gas": "0x2dc6c0",
+ "gasUsed": "0x5940",
"input": "0x5c19a95c000000000000000000000000f7579c3d8a669c89d5ed246a22eb6db8f6fedbf1",
"to": "0xf58833cf0c791881b494eb79d461e08a1f043f52",
"type": "CALL",
"value": "0x0",
- "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000"
+ "output": "0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001e53656c662d64656c65676174696f6e20697320646973616c6c6f7765642e0000",
+ "revertReason": "Self-delegation is disallowed."
}
}
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/selfdestruct.json
index 06667ccaa..90f10aa24 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/selfdestruct.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/selfdestruct.json
@@ -59,17 +59,16 @@
"gas": "0x0",
"gasUsed": "0x0",
"input": "0x",
- "to": "0x000000000000000000000000000000000000dEaD",
+ "to": "0x000000000000000000000000000000000000dead",
"type": "SELFDESTRUCT",
"value": "0x4d87094125a369d9bd5"
}
],
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"order": 0,
- "gas": "0x10738",
- "gasUsed": "0x7533",
+ "gas": "0x15f90",
+ "gasUsed": "0x6fcb",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
- "output": "0x",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
"type": "CALL",
"value": "0x0"
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/simple.json
index 303746fa5..d629e5286 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/simple.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/simple.json
@@ -71,8 +71,8 @@
],
"from": "0xb436ba50d378d4bbc8660d312a13df6af6e89dfb",
"order": 0,
- "gas": "0x10738",
- "gasUsed": "0x3ef9",
+ "gas": "0x15f90",
+ "gasUsed": "0x9751",
"input": "0x63e4bff40000000000000000000000000024f658a46fbb89d8ac105e98d7ac7cbbaf27c5",
"output": "0x0000000000000000000000000000000000000000000000000000000000000001",
"to": "0x3b873a919aa0512d5a0f09e6dcceaa4a6727fafe",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer2/throw.json b/eth/tracers/internal/tracetest/testdata/call_tracer2/throw.json
index 34ff602a1..499b449a6 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer2/throw.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer2/throw.json
@@ -52,9 +52,8 @@
"result": {
"error": "invalid jump destination",
"from": "0x70c9217d814985faef62b124420f8dfbddd96433",
- "order": 0,
- "gas": "0x37b38",
- "gasUsed": "0x37b38",
+ "gas": "0x3d090",
+ "gasUsed": "0x3d090",
"input": "0x51a34eb8000000000000000000000000000000000000000000000027fad02094277c0000",
"to": "0xc212e03b9e060e36facad5fd8f4435412ca22e6b",
"type": "CALL",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json
index c796804a4..a2386ea9c 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json
@@ -63,12 +63,27 @@
"address": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224"
},
"traceAddress": [],
- "subtraces": 0,
+ "subtraces": 1,
"transactionPosition": 74,
"transactionHash": "0x5ef60b27ac971c22a7d484e546e50093ca62300c8986d165154e47773764b6a4",
"blockNumber": 1555279,
"blockHash": "0xd6c98d1b87dfa92a210d99bad2873adaf0c9e51fe43addc63fd9cca03a5c6f46",
"time": "209.346µs"
+ },
+ {
+ "action": {
+ "balance": "0x0",
+ "callType": "callcode",
+ "from": "0x5f8a7e007172ba80afbff1b15f800eb0b260f224",
+ "gas": "0xaf64",
+ "to": "0x0000000000000000000000000000000000000004",
+ "value": "0x13"
+ },
+ "error": "insufficient balance for transfer",
+ "result": {},
+ "subtraces": 0,
+ "traceAddress": [0],
+ "type": "call"
}
]
}
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json
index 1d3886c3a..e5a37cbfd 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/delegatecall.json
@@ -104,7 +104,8 @@
"from": "0x13204f5d64c28326fd7bd05fd4ea855302d7f2ff",
"gas": "0x2bf459",
"input": "0x7d65837a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a529806c67cc6486d4d62024471772f47f6fd672",
- "to": "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2"
+ "to": "0x42b02b5deeb78f34cd5ac896473b63e6c99a71a2",
+ "value": "0x0"
},
"blockNumber": 0,
"result": {
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json
index 4de08f2cc..611e50e2c 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json
@@ -64,9 +64,23 @@
"gasUsed": "0x72de",
"output": "0x"
},
- "subtraces": 0,
+ "subtraces": 1,
"traceAddress": [],
"type": "call"
+ },
+ {
+ "action": {
+ "callType": "call",
+ "from": "0x6c06b16512b332e6cd8293a2974872674716ce18",
+ "gas": "0x8fc",
+ "to": "0x66fdfd05e46126a07465ad24e40cc0597bc1ef31",
+ "value": "0x14d1120d7b160000"
+ },
+ "error": "insufficient balance for transfer",
+ "result": {},
+ "subtraces": 0,
+ "traceAddress": [0],
+ "type": "call"
}
]
}
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json
index 28e96684b..f3a7d9a94 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/nested_create_inerror.json
@@ -70,12 +70,25 @@
"output": "0x"
},
"traceAddress": [],
- "subtraces": 0,
+ "subtraces": 1,
"transactionPosition": 26,
"transactionHash": "0xcb1090fa85d2a3da8326b75333e92b3dca89963c895d9c981bfdaa64643135e4",
"blockNumber": 839247,
"blockHash": "0xce7ff7d84ca97f0f89d6065e2c12409a795c9f607cdb14aef0713cad5d7e311c",
"time": "182.267µs"
+ },
+ {
+ "action": {
+ "from": "0x76554b33410b6d90b7dc889bfed0451ad195f27e",
+ "gas": "0x25a18",
+ "init": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "value": "0xa"
+ },
+ "error": "insufficient balance for transfer",
+ "result": {},
+ "subtraces": 0,
+ "traceAddress": [0],
+ "type": "create"
}
]
}
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json
index 74fd87cc6..3c5d6d9f2 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/selfdestruct.json
@@ -63,13 +63,26 @@
"address": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca"
},
"traceAddress": [],
- "subtraces": 1,
+ "subtraces": 2,
"transactionPosition": 14,
"transactionHash": "0xdd76f02407e2f8329303ba688e111cae4f7008ad0d14d6e42c5698424ea36d79",
"blockNumber": 1555146,
"blockHash": "0xafb4f1dd27b9054c805acb81a88ed04384788cb31d84164c21874935c81e5c7e",
"time": "187.145µs"
},
+ {
+ "action": {
+ "from": "0x1d99a1a3efa9181f540f9e24fa6e4e08eb7844ca",
+ "gas": "0x50ac",
+ "init": "0x5a",
+ "value": "0x1"
+ },
+ "error": "insufficient balance for transfer",
+ "result": {},
+ "subtraces": 0,
+ "traceAddress": [0],
+ "type": "create"
+ },
{
"type": "suicide",
"action": {
@@ -79,7 +92,7 @@
},
"result": null,
"traceAddress": [
- 0
+ 1
],
"subtraces": 0,
"transactionPosition": 14,
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json
index 96060d554..6911ed4b3 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/skip_no_balance_error.json
@@ -59,12 +59,25 @@
},
"error": "out of gas",
"traceAddress": [],
- "subtraces": 0,
+ "subtraces": 1,
"transactionPosition": 16,
"transactionHash": "0x384487e5ae8d2997aece8e28403d393cb9752425e6de358891bed981c5af1c05",
"blockNumber": 1555285,
"blockHash": "0x93231d8e9662adb4c5c703583a92c7b3112cd5448f43ab4fa1f0f00a0183ed3f",
"time": "665.278µs"
+ },
+ {
+ "action": {
+ "from": "0xf84bf5189ccd19f5897739756d214fa0dc099e0d",
+ "gas": "0x1d5c",
+ "init": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "value": "0xc350"
+ },
+ "error": "insufficient balance for transfer",
+ "result": {},
+ "subtraces": 0,
+ "traceAddress": [0],
+ "type": "create"
}
]
}
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json
index 9264f1e2f..dbece7229 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/calldata.json
@@ -95,14 +95,16 @@
"topics": [
"0xe1c52dc63b719ade82e8bea94cc41a0d5d28e4aaf536adb5e9cccc9ff8c1aeda"
],
- "data": "0x0000000000000000000000004f5777744b500616697cb655dcb02ee6cd51deb5be96016bb57376da7a6d296e0a405ee1501778227dfa604df0a81cb1ae018598"
+ "data": "0x0000000000000000000000004f5777744b500616697cb655dcb02ee6cd51deb5be96016bb57376da7a6d296e0a405ee1501778227dfa604df0a81cb1ae018598",
+ "position": "0x0"
},
{
"address": "0x200edd17f30485a8735878661960cd7a9a95733f",
"topics": [
"0xacbdb084c721332ac59f9b8e392196c9eb0e4932862da8eb9beaf0dad4f550da"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x0"
}
],
"value": "0x8ac7230489e80000",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json
index f63dbd47d..2b03dbb8d 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/delegatecall.json
@@ -257,7 +257,8 @@
"0x0000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add",
"0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5"
],
- "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac"
+ "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -278,7 +279,8 @@
"0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5",
"0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd"
],
- "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac"
+ "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -307,7 +309,8 @@
"0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5",
"0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd"
],
- "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac"
+ "data": "0x00000000000000000000000000000000000000000000000080d29fa5cccfadac",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -328,7 +331,8 @@
"0x0000000000000000000000005aae5c59d642e5fd45b427df6ed478b49d55fefd",
"0x000000000000000000000000950ca4a06c78934a148b7a3ff3ea8fc366f77a06"
],
- "data": "0x0000000000000000000000000000000000000000000000000041f50e27d56848"
+ "data": "0x0000000000000000000000000000000000000000000000000041f50e27d56848",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -391,7 +395,8 @@
"0x0000000000000000000000006ca7f214ab2ddbb9a8e1a1e2c8550e3164e9dba5",
"0x0000000000000000000000003de712784baf97260455ae25fb74f574ec9c1add"
],
- "data": "0x000000000000000000000000000000000000000000000000de0b6b3a76400000"
+ "data": "0x000000000000000000000000000000000000000000000000de0b6b3a76400000",
+ "position": "0x0"
}
],
"type": "DELEGATECALL",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json
new file mode 100644
index 000000000..c46fe080f
--- /dev/null
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json
@@ -0,0 +1,189 @@
+{
+ "genesis": {
+ "difficulty": "7797655526461",
+ "extraData": "0xd583010203844765746885676f312e35856c696e7578",
+ "gasLimit": "3141592",
+ "hash": "0x4ad333086cb86a6d261329504c9e1ca4d571212f56d6635dd213b700e1e85a6f",
+ "miner": "0x2a65aca4d5fc5b5c859090a6c34d164135398226",
+ "mixHash": "0xdaca4c8bd9a6e6707059736633543ebf50f97c07700a9ed55859b97275c19ea5",
+ "nonce": "0x894c15d74e8ae8bd",
+ "number": "469666",
+ "stateRoot": "0xf9c50965ffae3f99310483a7836c545a025cc680303adaf3671dbeef99edf03a",
+ "timestamp": "1446318401",
+ "totalDifficulty": "2462705215747880313",
+ "alloc": {
+ "0x0000000000000000000000000000000000000004": {
+ "balance": "0x0"
+ },
+ "0x0047a8033cc6d6ca2ed5044674fd421f44884de8": {
+ "balance": "0x44f5ced08fe37cf7",
+ "nonce": "872"
+ },
+ "0x1d11e5eae3112dbd44f99266872ff1d07c77dce8": {
+ "balance": "0x0",
+ "code": "0x60606040526000357c01000000000000000000000000000000000000000000000000000000009004806338cc48311461004f578063767800de14610088578063d1d80fdf146100c15761004d565b005b61005c60048050506100ff565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b61009560048050506100d9565b604051808273ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6100d7600480803590602001909190505061012e565b005b600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b6000600060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905061012b565b90565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614151561018a57610002565b80600060006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908302179055505b5056",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0x000000000000000000000000f631e3b3aafa084bc51c714825aacf505d2059be"
+ }
+ },
+ "0xe48430c4e88a929bba0ee3dce284866a9937b609": {
+ "balance": "0x26758774d51d8677a",
+ "nonce": "261"
+ },
+ "0xf631e3b3aafa084bc51c714825aacf505d2059be": {
+ "balance": "0x0",
+ "code": "0x606060405236156100da5760e060020a600035046323dc42e781146100ff5780632ef3accc146101a5578063385928321461021d57806345362978146102b65780634c7737951461034a578063524f38891461035c5780635c242c59146103ad578063772286591461044a5780637e1c42051461052457806381ade30714610601578063a2ec191a14610696578063adf59f991461071b578063ae815843146107b5578063bf1fe4201461084f578063de4b326214610890578063e8025731146108d4578063e839e65e14610970578063fbf8041814610a44575b610b20604051600160a060020a03331690600090349082818181858883f15050505050565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050505050505060008260006000610c0b83335b60006113fd8362030d40846101f5565b6040805160206004803580820135601f8101849004840285018401909552848452610b22949193602493909291840191908190840183828082843750949650509335935050505060006113fd8383335b600160a060020a03811660009081526003602052604081205460ff168114156114b557610b57565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050506000610d5885858585610841565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c01359182018390048302840183019094528083529799986044989297509290920194509250829150840183828082843750949650505050505050600082600060006114068333610195565b610b34600154600160a060020a031681565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375094965050505050505060006114008233610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b60008360006000610d5f8333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050505050505060008360006000610cb88333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897608497919650602491909101945090925082915084018382808284375094965050933593505050505b60008460006000610f288333610195565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c0135918201839004830284018301909452808352979998604498929750929092019450925082915084018382808284375094965050505050505060006113fd6000848462030d40610439565b6040805160206004803580820135601f8101849004840285018401909552848452610b209491936024939092918401919081908401838280828437509496505093359350505050600254600090600160a060020a039081163391909116148015906107115750600154600160a060020a039081163390911614155b156111fd57610002565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505050505050506000610c0484848462030d40610439565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050933593505050505b6000610d5885858585610439565b610b20600435600254600160a060020a039081163391909116148015906108865750600154600160a060020a039081163390911614155b156114b057610002565b610b20600435600254600090600160a060020a039081163391909116148015906108ca5750600154600160a060020a039081163390911614155b1561134d57610002565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760649791965060249190910194509092508291508401838280828437509496505093359350505050600083600060006111618333610195565b6040805160206004803580820135601f8101849004840285018401909552848452610b2294919360249390929184019190819084018382808284375050604080516020601f8935808c01359182018390048302840183019094528083529799986044989297509290920194509250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a01909352828252969897606497919650602491909101945090925082915084018382808284375094965050505050505060008360006000610b5e8333610195565b60408051602060046024803582810135601f8101859004850286018501909652858552610b229583359593946044949392909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a0190935282825296989760849791965060249190910194509092508291508401838280828437509496505093359350505050600084600060006112a68333610195565b005b60408051918252519081900360200190f35b60408051600160a060020a03929092168252519081900360200190f35b93505050505b9392505050565b91508160001415610b8d57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610bee57604051600160a060020a03331690600090839082818181858883f150505050505b610b51600088888862030d406105f0565b610002565b9050610b57565b91508160001415610c3a57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610c9b57604051600160a060020a03331690600090839082818181858883f150505050505b610b5187878762030d40610439565b93505050505b949350505050565b91508160001415610ce757600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610d4857604051600160a060020a03331690600090839082818181858883f150505050505b610caa8888888862030d406105f0565b9050610cb0565b91508160001415610d8e57600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610def57604051600160a060020a03331690600090839082818181858883f150505050505b604080516000805442810183528351928390036020908101842060019290920183558184528381018d9052608084018a905260a09484018581528c51958501959095528b519198507f1f28d876aff267c3302a63cd25ebcca53e6f60691049df42275b6d06ab455c679489948e948e948e948e9492606085019260c086019289810192829185918391869190600490601f850104600302600f01f150905090810190601f168015610eb45780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610f0d5780820380516001836020036101000a031916815260200191505b5097505050505050505060405180910390a150610cb0915050565b91508160001415610f5757600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f15050503484900392508211159050610fb857604051600160a060020a03331690600090839082818181858883f150505050505b60006000505442016040518082815260200191505060405180910390209350835060006000818150548092919060010191905055507f4e65aab8959da44521dc50a6ce3dfbd65016d8cfab70a47ea7541458206c4d5b848a8a8a8a8a604051808781526020018681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561108e5780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110e75780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111405780820380516001836020036101000a031916815260200191505b50995050505050505050505060405180910390a15050505b95945050505050565b9150816000141561119057600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f150505034849003925082111590506111f157604051600160a060020a03331690600090839082818181858883f150505050505b610caa88888888610439565b82604051808280519060200190808383829060006004602084601f0104600302600f01f1506007805491909301849003909320600184018084559095508594509192918391508280158290116112765781836000526020600020918201910161127691905b808211156112a25760008155600101611262565b505050815481101561000257600091825260208083209091019290925591825260069052604090205550565b5090565b915081600014156112d557600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f1505050348490039250821115905061133657604051600160a060020a03331690600090839082818181858883f150505050505b61134389898989896105f0565b9350505050611158565b50600481905560005b6007548110156113f957600780546006916000918490811015610002575080547fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c6888501548352602093909352604082205485029260059291908590811015610002579082527fa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a8736c688018150548152602081019190915260400160002055600101611356565b5050565b90505b92915050565b9150816000141561143557600160a060020a0333166000908152600360205260409020805460ff191660011790555b34829010610bff5760405173f65b3b60010d57d0bb8478aa6ced15fe720621b490600090849082818181858883f1505050348490039250821115905061149657604051600160a060020a03331690600090839082818181858883f150505050505b6114a66000878762030d40610439565b9350505050611400565b600855565b6005600050600085604051808280519060200190808383829060006004602084601f0104600302600f01f1509091018290039091208352505060209190915260409020546008548402019050610b5756",
+ "storage": {
+ "0x0000000000000000000000000000000000000000000000000000000000000000": "0x0000000000000000000000000000000000000000000000000000000000000004",
+ "0xde5cab2c6836c23f6388364c9a0e20bd1c8c7e6c3b5d0339cd8a2f7c4b36208c": "0x0000000000000000000000000000000000000000000000000000000000000000"
+ }
+ },
+ "0xf65b3b60010d57d0bb8478aa6ced15fe720621b4": {
+ "balance": "0x2c52a97273d2164"
+ }
+ },
+ "config": {
+ "chainId": 1,
+ "homesteadBlock": 1150000,
+ "daoForkBlock": 1920000,
+ "daoForkSupport": true,
+ "eip150Block": 2463000,
+ "eip155Block": 2675000,
+ "eip158Block": 2675000,
+ "byzantiumBlock": 4370000,
+ "constantinopleBlock": 7280000,
+ "petersburgBlock": 7280000,
+ "istanbulBlock": 9069000,
+ "muirGlacierBlock": 9200000,
+ "berlinBlock": 12244000,
+ "londonBlock": 12965000,
+ "arrowGlacierBlock": 13773000,
+ "grayGlacierBlock": 15050000,
+ "shanghaiTime": 1681338455,
+ "terminalTotalDifficulty": 7797655526461000,
+ "terminalTotalDifficultyPassed": true,
+ "ethash": {}
+ }
+ },
+ "context": {
+ "number": "469667",
+ "difficulty": "7793848077478",
+ "timestamp": "1446318425",
+ "gasLimit": "3141592",
+ "miner": "0xe48430c4e88a929bba0ee3dce284866a9937b609"
+ },
+ "input": "0xf91ec7820368850ba43b7400831b77408080b91e72606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b50561ca083d25971e732af3acb0a223dea6258f37407bf2d075fd852a83312238fca7cdea01f5a1189b054e947a0a140c565c4fc829b584e7348c9a7f65a890fe688e8b67f",
+ "tracerConfig": {
+ "withLog": true
+ },
+ "result": {
+ "from": "0x0047a8033cc6d6ca2ed5044674fd421f44884de8",
+ "gas": "0x1b7740",
+ "gasUsed": "0x9274f",
+ "input": "0x606060405260018054600160a060020a0319163317905561036f600360609081527f55524c0000000000000000000000000000000000000000000000000000000000608052610120604052604c60a09081527f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707560c0527f626c69632f5469636b65723f706169723d455448584254292e726573756c742e60e0527f58455448585842542e632e3000000000000000000000000000000000000000006101005261037d919062030d417f38cc483100000000000000000000000000000000000000000000000000000000610120908152600090731d11e5eae3112dbd44f99266872ff1d07c77dce89081906338cc4831906101249060209060048188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc8887604051837c010000000000000000000000000000000000000000000000000000000002815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156102255780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f11561000257505060405180517f385928320000000000000000000000000000000000000000000000000000000082526004828101888152606484018a90526080602485018181528d5160848701528d519496508a958e958e958e9594604484019360a40192909181908490829085908e906020601f850104600302600f01f150905090810190601f1680156102e65780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561033f5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151979650505050505050565b611af2806103806000396000f35b5056606060405236156100985760e060020a6000350463056e1059811461009a57806327dc297e14610391578063346b306a146103e257806341c0e1b51461075e578063489306eb146107855780635731f35714610a5e57806365a4dfb314610de05780637975c56e14611179578063a2e6204514611458578063ae152cf414611528578063b77644751461181b578063d594877014611876575b005b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561025e5780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103085780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156103615780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f115610002575050604051519350610dd892505050565b60408051602060248035600481810135601f81018590048502860185019096528585526100989581359591946044949293909201918190840183828082843750949650505050505050611a2761187a565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156105d15780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106795780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156106d25780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561072b5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b9392505050565b610098600154600160a060020a03908116339091161415611a255733600160a060020a0316ff5b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f8101839004830284018301909452838352979998604498929750919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109345780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150600087876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156109d75780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610a305780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f115610002575050604051519695505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166377228659600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889886040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610c535780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f1156100025750505060405180519060200150888888886040518660e060020a028152600401808581526020018060200180602001806020018481038452878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610cfa5780820380516001836020036101000a031916815260200191505b508481038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610d535780820380516001836020036101000a031916815260200191505b508481038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610dac5780820380516001836020036101000a031916815260200191505b5097505050505050505060206040518083038185886185025a03f1156100025750506040515193505050505b949350505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976084979196506024919091019450909250829150840183828082843750949650509335935050505060006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663fbf80418600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc89876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f168015610fe45780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015089898989896040518760e060020a028152600401808681526020018060200180602001806020018581526020018481038452888181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110935780820380516001836020036101000a031916815260200191505b508481038352878181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156110ec5780820380516001836020036101000a031916815260200191505b508481038252868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156111455780820380516001836020036101000a031916815260200191505b509850505050505050505060206040518083038185886185025a03f115610002575050604051519998505050505050505050565b60408051602060248035600481810135601f81018590048502860185019096528585526119559581359591946044949293909201918190840183828082843750506040805160209735808a0135601f81018a90048a0283018a019093528282529698976064979196506024919091019450909250829150840183828082843750506040805160e060020a6338cc48310281529051959760009750731d11e5eae3112dbd44f99266872ff1d07c77dce8968796506338cc4831955082820194506020935091829003018188876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a031663adf59f99600060009054906101000a9004600160a060020a0316600160a060020a031663524f3889876040518260e060020a02815260040180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f16801561132e5780820380516001836020036101000a031916815260200191505b50925050506020604051808303816000876161da5a03f11561000257505050604051805190602001508787876040518560e060020a0281526004018084815260200180602001806020018381038352858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156113d05780820380516001836020036101000a031916815260200191505b508381038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156114295780820380516001836020036101000a031916815260200191505b509550505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6100985b611aef604060405190810160405280600381526020017f55524c0000000000000000000000000000000000000000000000000000000000815260200150608060405190810160405280604c81526020017f6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f707581526020017f626c69632f5469636b65723f706169723d455448584254292e726573756c742e81526020017f58455448585842542e632e30000000000000000000000000000000000000000081526020015062030d416115ae565b6040805160206004803580820135601f8101849004840285018401909552848452611955949193602493909291840191908190840183828082843750506040805160208835808b0135601f810183900483028401830190945283835297999860449892975091909101945090925082915084018382808284375094965050933593505050505b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f1156100025750505060405180519060200150600060006101000a815481600160a060020a0302191690830217905550600060009054906101000a9004600160a060020a0316600160a060020a03166338592832600060009054906101000a9004600160a060020a0316600160a060020a0316632ef3accc88876040518360e060020a02815260040180806020018381526020018281038252848181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156116e75780820380516001836020036101000a031916815260200191505b5093505050506020604051808303816000876161da5a03f115610002575050506040518051906020015060008888886040518660e060020a0281526004018085815260200180602001806020018481526020018381038352868181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117925780820380516001836020036101000a031916815260200191505b508381038252858181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156117eb5780820380516001836020036101000a031916815260200191505b50965050505050505060206040518083038185886185025a03f11561000257505060405151935061075792505050565b6040805160028054602060018216156101000260001901909116829004601f81018290048202840182019094528383526119679390830182828015611a1d5780601f106119f257610100808354040283529160200191611a1d565b6119d55b60006000731d11e5eae3112dbd44f99266872ff1d07c77dce8905080600160a060020a03166338cc48316040518160e060020a0281526004018090506020604051808303816000876161da5a03f115610002575050604080518051855473ffffffffffffffffffffffffffffffffffffffff1916178086557f4c7737950000000000000000000000000000000000000000000000000000000082529151600160a060020a03929092169250634c773795916004828101926020929190829003018188876161da5a03f115610002575050604051519250505090565b60408051918252519081900360200190f35b60405180806020018281038252838181518152602001915080519060200190808383829060006004602084601f0104600302600f01f150905090810190601f1680156119c75780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60408051600160a060020a03929092168252519081900360200190f35b820191906000526020600020905b815481529060010190602001808311611a0057829003601f168201915b505050505081565b565b600160a060020a031633600160a060020a0316141515611a4657610002565b8060026000509080519060200190828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611aad57805160ff19168380011785555b50611add9291505b80821115611ae75760008155600101611a99565b82800160010185558215611a91579182015b82811115611a91578251826000505591602001919060010190611abf565b5050611aeb61145c565b5090565b5050565b5056",
+ "error": "contract creation code storage out of gas",
+ "calls": [
+ {
+ "from": "0xc24431c1a1147456414355b1f1769de450e524da",
+ "gas": "0x12c54b",
+ "gasUsed": "0x106",
+ "to": "0x1d11e5eae3112dbd44f99266872ff1d07c77dce8",
+ "input": "0x38cc4831",
+ "output": "0x000000000000000000000000f631e3b3aafa084bc51c714825aacf505d2059be",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xc24431c1a1147456414355b1f1769de450e524da",
+ "gas": "0x12",
+ "gasUsed": "0x12",
+ "to": "0x0000000000000000000000000000000000000004",
+ "input": "0x55524c",
+ "output": "0x55524c",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xc24431c1a1147456414355b1f1769de450e524da",
+ "gas": "0x127270",
+ "gasUsed": "0x26b",
+ "to": "0xf631e3b3aafa084bc51c714825aacf505d2059be",
+ "input": "0x2ef3accc00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000",
+ "output": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xc24431c1a1147456414355b1f1769de450e524da",
+ "gas": "0x12",
+ "gasUsed": "0x12",
+ "to": "0x0000000000000000000000000000000000000004",
+ "input": "0x55524c",
+ "output": "0x55524c",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xc24431c1a1147456414355b1f1769de450e524da",
+ "gas": "0x18",
+ "gasUsed": "0x18",
+ "to": "0x0000000000000000000000000000000000000004",
+ "input": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30",
+ "output": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xc24431c1a1147456414355b1f1769de450e524da",
+ "gas": "0x124995",
+ "gasUsed": "0x78f5",
+ "to": "0xf631e3b3aafa084bc51c714825aacf505d2059be",
+ "input": "0x385928320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e300000000000000000000000000000000000000000",
+ "output": "0x55bc8431ce52389ac668a9b14a0943290cb7263732251186e960bc8b249b5f32",
+ "calls": [
+ {
+ "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be",
+ "gas": "0x0",
+ "gasUsed": "0x0",
+ "to": "0xf65b3b60010d57d0bb8478aa6ced15fe720621b4",
+ "input": "0x",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be",
+ "gas": "0x12",
+ "gasUsed": "0x12",
+ "to": "0x0000000000000000000000000000000000000004",
+ "input": "0x55524c",
+ "output": "0x55524c",
+ "value": "0x0",
+ "type": "CALL"
+ },
+ {
+ "from": "0xf631e3b3aafa084bc51c714825aacf505d2059be",
+ "gas": "0x18",
+ "gasUsed": "0x18",
+ "to": "0x0000000000000000000000000000000000000004",
+ "input": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30",
+ "output": "0x6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e30",
+ "value": "0x0",
+ "type": "CALL"
+ }
+ ],
+ "logs":[
+ {
+ "address": "0xf631e3b3aafa084bc51c714825aacf505d2059be",
+ "topics": ["0x1f28d876aff267c3302a63cd25ebcca53e6f60691049df42275b6d06ab455c67"],
+ "data":"0x55bc8431ce52389ac668a9b14a0943290cb7263732251186e960bc8b249b5f32000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000030d41000000000000000000000000000000000000000000000000000000000000000355524c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004c6a736f6e2868747470733a2f2f6170692e6b72616b656e2e636f6d2f302f7075626c69632f5469636b65723f706169723d455448584254292e726573756c742e58455448585842542e632e300000000000000000000000000000000000000000",
+ "position":"0x3"
+ }
+ ],
+ "value": "0x0",
+ "type": "CALL"
+ }
+ ],
+ "value": "0x0",
+ "type": "CREATE"
+ }
+}
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json
index 5e5d95386..263e88d6e 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multi_contracts.json
@@ -357,7 +357,8 @@
"0x000000000000000000000000c0ee9db1a9e07ca63e4ff0d5fb6f86bf68d47b89",
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd"
],
- "data": "0x00000000000000000000000000000000000000000001819451f999d617dafa93"
+ "data": "0x00000000000000000000000000000000000000000001819451f999d617dafa93",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -370,7 +371,8 @@
"topics": [
"0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"
],
- "data": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa93"
+ "data": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa93",
+ "position": "0x1"
}
],
"value": "0x0",
@@ -491,7 +493,8 @@
"0x000000000000000000000000f835a0247b0063c04ef22006ebe57c5f11977cc4",
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd"
],
- "data": "0x00000000000000000000000000000000000000000001819451f999d617dafa76"
+ "data": "0x00000000000000000000000000000000000000000001819451f999d617dafa76",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -504,7 +507,8 @@
"topics": [
"0x69ca02dd4edd7bf0a4abb9ed3b7af3f14778db5d61921c7dc7cd545266326de2"
],
- "data": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa76"
+ "data": "0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd00000000000000000000000000000000000000000001819451f999d617dafa76",
+ "position": "0x1"
}
],
"value": "0x0",
@@ -692,7 +696,8 @@
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd",
"0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc"
],
- "data": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd"
+ "data": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccd",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -874,7 +879,8 @@
"0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc",
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd"
],
- "data": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccc"
+ "data": "0x0000000000000000000000000000000000000000000181a7ae53ea2f0bef8ccc",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -892,7 +898,8 @@
"0x9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc",
"0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc"
],
- "data": "0x0000000000000000000000000000000000000000000000022b1c8c12279fffff"
+ "data": "0x0000000000000000000000000000000000000000000000022b1c8c12279fffff",
+ "position": "0x1"
}
],
"value": "0x0",
@@ -914,7 +921,8 @@
"0x9735b0cb909f3d21d5c16bbcccd272d85fa11446f6d679f6ecb170d2dabfecfc",
"0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc"
],
- "data": "0x0000000000000000000000000000000000000000000000022b1c8c12279fffff"
+ "data": "0x0000000000000000000000000000000000000000000000022b1c8c12279fffff",
+ "position": "0x1"
}
],
"value": "0x0",
@@ -939,7 +947,8 @@
"0x0000000000000000000000006e715ab4f598eacf0016b9b35ef33e4141844ccc",
"0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000001"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000001",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -952,14 +961,16 @@
"topics": [
"0x07cf7e805770612a8b2ee8e0bcbba8aa908df5f85fbc4f9e2ef384cf75315038"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x6"
},
{
"address": "0x6e715ab4f598eacf0016b9b35ef33e4141844ccc",
"topics": [
"0x7027eecbd2a688fc1fa281702b311ed7168571514adfd17014a55d828cb43382"
],
- "data": "0x000000000000000000000000000000000000000000000004563918244f400000"
+ "data": "0x000000000000000000000000000000000000000000000004563918244f400000",
+ "position": "0x8"
}
],
"value": "0x0",
@@ -1035,7 +1046,8 @@
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd",
"0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000063"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000063",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -1162,7 +1174,8 @@
"0x0000000000000000000000006dbfc63479ffc031f23e94dc91befa38bec2c25f",
"0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000064"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000064",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -1175,14 +1188,16 @@
"topics": [
"0x4b0bc4f25f8d0b92d2e12b686ba96cd75e4e69325e6cf7b1f3119d14eaf2cbdf"
],
- "data": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526"
+ "data": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e96526",
+ "position": "0x6"
},
{
"address": "0x6dbfc63479ffc031f23e94dc91befa38bec2c25f",
"topics": [
"0xf340c079d598119636d42046c6a2d2faf7a68c04aecee516f0e0b8a9e79b8666"
],
- "data": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e9652600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000da4a4626d3e16e094de3225a751aab7128e9652600000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x9"
}
],
"value": "0x0",
@@ -1231,7 +1246,8 @@
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd",
"0x0000000000000000000000007498bb5749c9801f1f7e490baf5f966dbfe4e97b"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000001"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000001",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -1324,7 +1340,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000001"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1417,7 +1434,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000002"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1510,7 +1528,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000003"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1603,7 +1622,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000004"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1696,7 +1716,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000005"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1789,7 +1810,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000006"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1882,7 +1904,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000007"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -1975,7 +1998,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000008"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -2068,7 +2092,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x0000000000000000000000000000000000000000000000000000000000000009"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -2161,7 +2186,8 @@
"0x5790de2c279e58269b93b12828f56fd5f2bc8ad15e61ce08572585c81a38756f",
"0x000000000000000000000000000000000000000000000000000000000000000a"
],
- "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000"
+ "data": "0x000000000000000000000000be3ae5cb97c253dda67181c6e34e43f5c275e08b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000",
+ "position": "0x2"
}
],
"value": "0x0",
@@ -2213,7 +2239,8 @@
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd",
"0x0000000000000000000000007ccbc69292c7a6d7b538c91f3b283de97906cf30"
],
- "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c"
+ "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -2234,7 +2261,8 @@
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd",
"0x0000000000000000000000001b9ec8ba24630b75a7a958153ffff56dd6d4b6a2"
],
- "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c"
+ "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -2255,7 +2283,8 @@
"0x0000000000000000000000004fd27b205895e698fa350f7ea57cec8a21927fcd",
"0x000000000000000000000000c3a2c744ad1f5253c736875b93bacce5b01b060b"
],
- "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c"
+ "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c",
+ "position": "0x0"
}
],
"value": "0x0",
@@ -2268,21 +2297,24 @@
"topics": [
"0xc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b"
],
- "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c"
+ "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c",
+ "position": "0x2"
},
{
"address": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd",
"topics": [
"0xc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b"
],
- "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c"
+ "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c",
+ "position": "0x3"
},
{
"address": "0x4fd27b205895e698fa350f7ea57cec8a21927fcd",
"topics": [
"0xc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b"
],
- "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c"
+ "data": "0x00000000000000000000000000000000000000000001010d8bfbbbe40fe7518c",
+ "position": "0x4"
}
],
"value": "0x0",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json
index 1ffffd240..66d458200 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/multilogs.json
@@ -178,350 +178,400 @@
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebeb0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffebebeb0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8888880000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8888880000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b30000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb3b3b30000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e30000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe3e3e30000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3e0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3e3e3e0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdb0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbdbdb0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f40000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f4f40000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfb0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfb0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002ff000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000341000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b00000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0b0b00000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a00000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0a0a00000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5b0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b5b5b0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababa0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababa0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaea0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaea0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a90000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9a9a90000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b90000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb9b9b90000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfb0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbfbfb0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffefefe0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababa0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbababa0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6363630000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6363630000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f90000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9f9f90000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaea0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeaeaea0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9c0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9c9c9c0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f80000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8f8f80000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034200000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcfcfc0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fe000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdfdfd0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000000342000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e530000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4d4e530000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x000000000000000000000000000000000000000000000000000000000000034300000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
},
{
"address": "0x350e0ffc780a6a75b44cc52e1ff9092870668945",
"topics": [
"0xcacb62d8acea4678658eb5dc4aaa889b34d893b967c96a5f8c066e6549fa3f42"
],
- "data": "0x00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b0000000000000000000000000000000000000000000000000011c37937e08000"
+ "data": "0x00000000000000000000000000000000000000000000000000000000000002fd00000000000000000000000000000000000000000000000000000000000000370000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fcb0342353c541e210013aaddc2e740b9a33d08ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4f494b0000000000000000000000000000000000000000000000000011c37937e08000",
+ "position": "0x0"
}
],
"value": "0x3782dace9d90000",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json
index 116606b3c..762ccbe58 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/notopic.json
@@ -266,7 +266,8 @@
"topics": [
"0xaf30e4d66b2f1f23e63ef4591058a897f67e6867233e33ca3508b982dcc4129b"
],
- "data": "0x00000000000000000000000050739060a2c32dc076e507ae1a893aab28ecfe68d1b13c1538a940417bf0e73b2498634436753c854c7fb971224d971bd2ae3e8800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000249f011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000355524c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000436a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d0000000000000000000000000000000000000000"
+ "data": "0x00000000000000000000000050739060a2c32dc076e507ae1a893aab28ecfe68d1b13c1538a940417bf0e73b2498634436753c854c7fb971224d971bd2ae3e8800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000249f011000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000355524c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000436a736f6e2868747470733a2f2f6170692e72616e646f6d2e6f72672f6a736f6e2d7270632f312f696e766f6b65292e726573756c742e72616e646f6d2e646174612e300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012c4244584a68725670424a35336f3243786c4a526c51745a4a4b5a714c5974354951652b37335944533448744e6a5335486f64624942337476666f773755717579416b303835566b4c6e4c3945704b67777157517a375a4c64477673516c526432734b78496f6c4e673944626e6650737047714c684c62625953566e4e38437776736a7041586353536f33632b34634e774339307946346f4e69626b764433797461706f5a37676f5453796f5559546677536a6e773374692b484a5648374e332b633069774f43715a6a4464734751556358336d33532f494857624f4f5151356f734f344c626a33476730783155644e7466557a5943465937396e7a596757495145464375524249306e364e42764251573732372b4f73445259304a2f392f676a74387563696248576963303d0000000000000000000000000000000000000000",
+ "position": "0x4"
}
],
"value": "0x179d63013c5654",
@@ -277,7 +278,8 @@
{
"address": "0x50739060a2c32dc076e507ae1a893aab28ecfe68",
"topics": [],
- "data": "0x62616e6b726f6c6c5f6d69736d61746368"
+ "data": "0x62616e6b726f6c6c5f6d69736d61746368",
+ "position": "0x2"
}
],
"value": "0x429d069189e0000",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json
index 30f177706..64941dd4d 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/simple.json
@@ -75,7 +75,8 @@
"0x000000000000000000000000d1220a0cf47c7b9be7a2e6ba89f429762e7b9adb",
"0x000000000000000000000000dbf03b407c01e7cd3cbea99509d93f8dddc8c6fb"
],
- "data": "0x0000000000000000000000000000000000000000000000000000000000989680"
+ "data": "0x0000000000000000000000000000000000000000000000000000000000989680",
+ "position": "0x0"
}
],
"value": "0x0",
diff --git a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json
index eb2514427..6faf898a0 100644
--- a/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json
+++ b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/tx_partial_failed.json
@@ -98,7 +98,8 @@
"topics": [
"0x92ca3a80853e6663fa31fa10b99225f18d4902939b4c53a9caae9043f6efd004"
],
- "data": "0x00000000000000000000000001115b41bd2731353dd3e6abf44818fdc035aaf10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c1894130000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008861393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030"
+ "data": "0x00000000000000000000000001115b41bd2731353dd3e6abf44818fdc035aaf10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bb9bc244d798123fde783fcc1c72d3bb8c1894130000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008861393035396362623030303030303030303030303030303030303030303030303930643363313831326465323636396266383037626437373538636562316533343937616337653430303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303030303031633662663532363334303030",
+ "position": "0x0"
}
],
"value": "0x0",
diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json
new file mode 100644
index 000000000..3a0d8e9ab
--- /dev/null
+++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json
@@ -0,0 +1,62 @@
+{
+ "genesis": {
+ "baseFeePerGas": "875000000",
+ "difficulty": "0",
+ "extraData": "0xd983010d05846765746888676f312e32312e318664617277696e",
+ "gasLimit": "11511229",
+ "hash": "0xd462585c6c5a3b3bf14850ebcde71b6615b9aaf6541403f9a0457212dd0502e0",
+ "miner": "0x0000000000000000000000000000000000000000",
+ "mixHash": "0xfa51e868d6a7c0728f18800e4cc8d4cc1c87430cc9975e947eb6c9c03599b4e2",
+ "nonce": "0x0000000000000000",
+ "number": "1",
+ "stateRoot": "0xd2ebe0a7f3572ffe3e5b4c78147376d3fca767f236e4dd23f9151acfec7cb0d1",
+ "timestamp": "1699617692",
+ "totalDifficulty": "0",
+ "withdrawals": [],
+ "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
+ "alloc": {
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x5208"
+ },
+ "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": {
+ "balance": "0x8ac7230489e80000"
+ }
+ },
+ "config": {
+ "chainId": 1337,
+ "homesteadBlock": 0,
+ "eip150Block": 0,
+ "eip155Block": 0,
+ "eip158Block": 0,
+ "byzantiumBlock": 0,
+ "constantinopleBlock": 0,
+ "petersburgBlock": 0,
+ "istanbulBlock": 0,
+ "muirGlacierBlock": 0,
+ "berlinBlock": 0,
+ "londonBlock": 0,
+ "arrowGlacierBlock": 0,
+ "grayGlacierBlock": 0,
+ "shanghaiBlock": 0,
+ "terminalTotalDifficulty": 0,
+ "terminalTotalDifficultyPassed": true,
+ "isDev": true
+ }
+ },
+ "context": {
+ "number": "2",
+ "difficulty": "0",
+ "timestamp": "1699617847",
+ "gasLimit": "11522469",
+ "miner": "0x0000000000000000000000000000000000000000"
+ },
+ "input": "0x02f902b48205398084b2d05e0085011b1f3f8083031ca88080b90258608060405234801561001057600080fd5b5060405161001d906100e3565b604051809103906000f080158015610039573d6000803e3d6000fd5b50600080546001600160a01b0319166001600160a01b039290921691821781556040517fc66247bafd1305823857fb4c3e651e684d918df8554ef560bbbcb025fdd017039190a26000546040516360fe47b160e01b8152600560048201526001600160a01b03909116906360fe47b190602401600060405180830381600087803b1580156100c657600080fd5b505af11580156100da573d6000803e3d6000fd5b505050506100ef565b60ca8061018e83390190565b6091806100fd6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806380de699314602d575b600080fd5b600054603f906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f3fea2646970667358221220dab781465e7f4cf20304cc388130a763508e20edd25b4bc8ea8f57743a0de8da64736f6c634300081700336080604052348015600f57600080fd5b5060ac8061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806360fe47b11460375780636d4ce63c146049575b600080fd5b60476042366004605e565b600055565b005b60005460405190815260200160405180910390f35b600060208284031215606f57600080fd5b503591905056fea264697066735822122049e09da6320793487d58eaa7b97f802618a062cbc35f08ca1ce92c17349141f864736f6c63430008170033c080a01d4fce93ad08bf413052645721f20e6136830cf5a2759fa57e76a134e90899a7a0399a72832d52118991dc04c4f9e1c0fec3d5e441ad7d4b055f0cf03130d8f815",
+ "result": {
+ "0x0000000000000000000000000000000000000000": {
+ "balance": "0x5208"
+ },
+ "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266": {
+ "balance": "0x8ac7230489e80000"
+ }
+ }
+}
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json
new file mode 100644
index 000000000..205b472da
--- /dev/null
+++ b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_post_eip158.json
@@ -0,0 +1,64 @@
+{
+ "genesis": {
+ "baseFeePerGas": "7",
+ "difficulty": "2",
+ "extraData": "0xd983010d0e846765746888676f312e32312e318664617277696e0000000000001713699f05f79a59abec177c7a87b90ceda79b72ff5edc9197dd7627a447cde45b079bbc3765a236cdf680e2d4d2247135d0e6bb6fd92b50638b92504ddb274f00",
+ "gasLimit": "30000000",
+ "hash": "0x6ad5258175c66f4e883d238a92a08428d8ebcbeac631ab7b972634cc05effab3",
+ "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0",
+ "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "nonce": "0x0000000000000000",
+ "number": "39137",
+ "stateRoot": "0x715f00df764dbadd4863247a215ac44b5420beafde3ec458b15db7aafa89be0c",
+ "timestamp": "1709022192",
+ "totalDifficulty": "78275",
+ "alloc": {
+ "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": {
+ "balance": "0x10f06447a8d44dba190",
+ "nonce": "2"
+ },
+ "0x82211934c340b29561381392348d48413e15adc8": {
+ "balance": "0x6abd7a808913ed2",
+ "nonce": "64"
+ }
+ },
+ "config": {
+ "chainId": 12345,
+ "homesteadBlock": 0,
+ "eip150Block": 0,
+ "eip155Block": 0,
+ "eip158Block": 0,
+ "byzantiumBlock": 0,
+ "constantinopleBlock": 0,
+ "petersburgBlock": 0,
+ "istanbulBlock": 0,
+ "muirGlacierBlock": 0,
+ "berlinBlock": 0,
+ "londonBlock": 0,
+ "arrowGlacierBlock": 0,
+ "grayGlacierBlock": 0,
+ "clique": {
+ "period": 5,
+ "epoch": 30000
+ }
+ }
+ },
+ "context": {
+ "number": "39138",
+ "difficulty": "2",
+ "timestamp": "1709022197",
+ "gasLimit": "30000000",
+ "miner": "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0"
+ },
+ "input": "0x02f902af823039408459682f008459682f088302b3538080b90254608060405234801561001057600080fd5b50610234806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806309ce9ccb1461003b5780633fb5c1cb14610059575b600080fd5b610043610075565b60405161005091906100e2565b60405180910390f35b610073600480360381019061006e919061012e565b61007b565b005b60005481565b80600081905550600a8111156100c6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100bd906101de565b60405180910390fd5b50565b6000819050919050565b6100dc816100c9565b82525050565b60006020820190506100f760008301846100d3565b92915050565b600080fd5b61010b816100c9565b811461011657600080fd5b50565b60008135905061012881610102565b92915050565b600060208284031215610144576101436100fd565b5b600061015284828501610119565b91505092915050565b600082825260208201905092915050565b7f4e756d6265722069732067726561746572207468616e2031302c207472616e7360008201527f616374696f6e2072657665727465642e00000000000000000000000000000000602082015250565b60006101c860308361015b565b91506101d38261016c565b604082019050919050565b600060208201905081810360008301526101f7816101bb565b905091905056fea264697066735822122069018995fecf03bda91a88b6eafe41641709dee8b4a706fe301c8a569fe8c1b364736f6c63430008130033c001a0a8cf4729b7e4664687abb3e2559853d7d489eb441519be2a17493061fb4c3a03a04b5a904ba8a6e59c6c40049c4d14a73233aeb8a45b38403199f304630dc0d453",
+ "result": {
+ "0x2445e8c26a2bf3d1e59f1bb9b1d442caf90768e0": {
+ "balance": "0x10f06447a8d44dba190",
+ "nonce": 2
+ },
+ "0x82211934c340b29561381392348d48413e15adc8": {
+ "balance": "0x6abd7a808913ed2",
+ "nonce": 64
+ }
+ }
+}
diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go
new file mode 100644
index 000000000..18a372d19
--- /dev/null
+++ b/eth/tracers/internal/util.go
@@ -0,0 +1,81 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+package internal
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/holiman/uint256"
+)
+
+const (
+ memoryPadLimit = 1024 * 1024
+)
+
+// GetMemoryCopyPadded returns offset + size as a new slice.
+// It zero-pads the slice if it extends beyond memory bounds.
+func GetMemoryCopyPadded(m []byte, offset, size int64) ([]byte, error) {
+ if offset < 0 || size < 0 {
+ return nil, errors.New("offset or size must not be negative")
+ }
+ length := int64(len(m))
+ if offset+size < length { // slice fully inside memory
+ return memoryCopy(m, offset, size), nil
+ }
+ paddingNeeded := offset + size - length
+ if paddingNeeded > memoryPadLimit {
+ return nil, fmt.Errorf("reached limit for padding memory slice: %d", paddingNeeded)
+ }
+ cpy := make([]byte, size)
+ if overlap := length - offset; overlap > 0 {
+ copy(cpy, MemoryPtr(m, offset, overlap))
+ }
+ return cpy, nil
+}
+
+func memoryCopy(m []byte, offset, size int64) (cpy []byte) {
+ if size == 0 {
+ return nil
+ }
+
+ if len(m) > int(offset) {
+ cpy = make([]byte, size)
+ copy(cpy, m[offset:offset+size])
+
+ return
+ }
+
+ return
+}
+
+// MemoryPtr returns a pointer to a slice of memory.
+func MemoryPtr(m []byte, offset, size int64) []byte {
+ if size == 0 {
+ return nil
+ }
+
+ if len(m) > int(offset) {
+ return m[offset : offset+size]
+ }
+
+ return nil
+}
+
+// Back returns the n'th item in stack
+func StackBack(st []uint256.Int, n int) *uint256.Int {
+ return &st[len(st)-n-1]
+}
diff --git a/eth/tracers/internal/util_test.go b/eth/tracers/internal/util_test.go
new file mode 100644
index 000000000..6a467314c
--- /dev/null
+++ b/eth/tracers/internal/util_test.go
@@ -0,0 +1,60 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+package internal
+
+import (
+ "testing"
+
+ "github.com/ethereum/go-ethereum/core/vm"
+)
+
+func TestMemCopying(t *testing.T) {
+ for i, tc := range []struct {
+ memsize int64
+ offset int64
+ size int64
+ wantErr string
+ wantSize int
+ }{
+ {0, 0, 100, "", 100}, // Should pad up to 100
+ {0, 100, 0, "", 0}, // No need to pad (0 size)
+ {100, 50, 100, "", 100}, // Should pad 100-150
+ {100, 50, 5, "", 5}, // Wanted range fully within memory
+ {100, -50, 0, "offset or size must not be negative", 0}, // Error
+ {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Error
+ {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Error
+
+ } {
+ mem := vm.NewMemory()
+ mem.Resize(uint64(tc.memsize))
+ cpy, err := GetMemoryCopyPadded(mem.Data(), tc.offset, tc.size)
+ if want := tc.wantErr; want != "" {
+ if err == nil {
+ t.Fatalf("test %d: want '%v' have no error", i, want)
+ }
+ if have := err.Error(); want != have {
+ t.Fatalf("test %d: want '%v' have '%v'", i, want, have)
+ }
+ continue
+ }
+ if err != nil {
+ t.Fatalf("test %d: unexpected error: %v", i, err)
+ }
+ if want, have := tc.wantSize, len(cpy); have != want {
+ t.Fatalf("test %d: want %v have %v", i, want, have)
+ }
+ }
+}
diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go
index fb253563f..3faee1e94 100644
--- a/eth/tracers/js/goja.go
+++ b/eth/tracers/js/goja.go
@@ -23,12 +23,17 @@ import (
"math/big"
"github.com/dop251/goja"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/internal"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/holiman/uint256"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/eth/tracers"
jsassets "github.com/ethereum/go-ethereum/eth/tracers/js/internal/tracers"
)
@@ -41,10 +46,10 @@ func init() {
if err != nil {
panic(err)
}
- type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error)
+ type ctorFn = func(*tracers.Context, json.RawMessage, *params.ChainConfig) (*tracers.Tracer, error)
lookup := func(code string) ctorFn {
- return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
- return newJsTracer(code, ctx, cfg)
+ return func(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
+ return newJsTracer(code, ctx, cfg, chainConfig)
}
}
for name, code := range assetTracers {
@@ -57,9 +62,11 @@ func init() {
// hex strings into big ints.
var bigIntProgram = goja.MustCompile("bigInt", bigIntegerJS, false)
-type toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error)
-type toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error)
-type fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error)
+type (
+ toBigFn = func(vm *goja.Runtime, val string) (goja.Value, error)
+ toBufFn = func(vm *goja.Runtime, val []byte) (goja.Value, error)
+ fromBufFn = func(vm *goja.Runtime, buf goja.Value, allowString bool) ([]byte, error)
+)
func toBuf(vm *goja.Runtime, bufType goja.Value, val []byte) (goja.Value, error) {
// bufType is usually Uint8Array. This is equivalent to `new Uint8Array(val)` in JS.
@@ -86,17 +93,18 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
if !obj.Get("constructor").SameAs(bufType) {
break
}
- b := obj.Get("buffer").Export().(goja.ArrayBuffer).Bytes()
+ b := obj.Export().([]byte)
return b, nil
}
- return nil, fmt.Errorf("invalid buffer type")
+ return nil, errors.New("invalid buffer type")
}
// jsTracer is an implementation of the Tracer interface which evaluates
// JS functions on the relevant EVM hooks. It uses Goja as its JS engine.
type jsTracer struct {
vm *goja.Runtime
- env *vm.EVM
+ env *tracing.VMContext
+ chainConfig *params.ChainConfig
toBig toBigFn // Converts a hex string into a JS bigint
toBuf toBufFn // Converts a []byte into a JS buffer
fromBuf fromBufFn // Converts an array, hex string or Uint8Array to a []byte
@@ -104,7 +112,6 @@ type jsTracer struct {
activePrecompiles []common.Address // List of active precompiles at current block
traceStep bool // True if tracer object exposes a `step()` method
traceFrame bool // True if tracer object exposes the `enter()` and `exit()` methods
- gasLimit uint64 // Amount of gas bought for the whole tx
err error // Any error that should stop tracing
obj *goja.Object // Trace object
@@ -134,27 +141,38 @@ type jsTracer struct {
// The methods `result` and `fault` are required to be present.
// The methods `step`, `enter`, and `exit` are optional, but note that
// `enter` and `exit` always go together.
-func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
vm := goja.New()
// By default field names are exported to JS as is, i.e. capitalized.
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
t := &jsTracer{
- vm: vm,
- ctx: make(map[string]goja.Value),
+ vm: vm,
+ ctx: make(map[string]goja.Value),
+ chainConfig: chainConfig,
}
+
+ t.setTypeConverters()
+ t.setBuiltinFunctions()
+
if ctx == nil {
ctx = new(tracers.Context)
}
if ctx.BlockHash != (common.Hash{}) {
- t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes())
+ blockHash, err := t.toBuf(vm, ctx.BlockHash.Bytes())
+ if err != nil {
+ return nil, err
+ }
+ t.ctx["blockHash"] = blockHash
if ctx.TxHash != (common.Hash{}) {
t.ctx["txIndex"] = vm.ToValue(ctx.TxIndex)
- t.ctx["txHash"] = vm.ToValue(ctx.TxHash.Bytes())
+ txHash, err := t.toBuf(vm, ctx.TxHash.Bytes())
+ if err != nil {
+ return nil, err
+ }
+ t.ctx["txHash"] = txHash
}
}
- t.setTypeConverters()
- t.setBuiltinFunctions()
ret, err := vm.RunString("(" + code + ")")
if err != nil {
return nil, err
@@ -207,50 +225,95 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer
t.frameValue = t.frame.setupObject()
t.frameResultValue = t.frameResult.setupObject()
t.logValue = t.log.setupObject()
- return t, nil
-}
-// CaptureTxStart implements the Tracer interface and is invoked at the beginning of
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnOpcode: t.OnOpcode,
+ OnFault: t.OnFault,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
+}
+
+// OnTxStart implements the Tracer interface and is invoked at the beginning of
// transaction processing.
-func (t *jsTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {
- t.gasLimit = gasLimit
+func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ t.env = env
+ // Need statedb access for db object
+ db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
+ t.dbValue = db.setupObject()
+ // Update list of precompiles based on current block
+ rules := t.chainConfig.Rules(env.BlockNumber)
+ t.activePrecompiles = vm.ActivePrecompiles(rules)
+ t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
+ t.ctx["gas"] = t.vm.ToValue(tx.Gas())
+ gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String())
+ if err != nil {
+ t.err = err
+ return
+ }
+ t.ctx["gasPrice"] = gasPriceBig
}
-// CaptureTxEnd implements the Tracer interface and is invoked at the end of
+// OnTxEnd 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) OnTxEnd(receipt *types.Receipt, err error) {
+ if t.err != nil {
+ return
+ }
+ if err != nil {
+ // Don't override vm error
+ if _, ok := t.ctx["error"]; !ok {
+ t.ctx["error"] = t.vm.ToValue(err.Error())
+ }
+ return
+ }
+ t.ctx["gasUsed"] = t.vm.ToValue(receipt.GasUsed)
}
-// CaptureStart implements the Tracer interface to initialize the tracing operation.
-func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- t.env = env
- db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
- t.dbValue = db.setupObject()
+// onStart implements the Tracer interface to initialize the tracing operation.
+func (t *jsTracer) onStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+ if t.err != nil {
+ return
+ }
if create {
t.ctx["type"] = t.vm.ToValue("CREATE")
} else {
t.ctx["type"] = t.vm.ToValue("CALL")
}
- t.ctx["from"] = t.vm.ToValue(from.Bytes())
- t.ctx["to"] = t.vm.ToValue(to.Bytes())
- t.ctx["input"] = t.vm.ToValue(input)
- t.ctx["gas"] = t.vm.ToValue(t.gasLimit)
- t.ctx["gasPrice"] = t.vm.ToValue(env.TxContext.GasPrice)
+ fromVal, err := t.toBuf(t.vm, from.Bytes())
+ if err != nil {
+ t.err = err
+ return
+ }
+ t.ctx["from"] = fromVal
+ toVal, err := t.toBuf(t.vm, to.Bytes())
+ if err != nil {
+ t.err = err
+ return
+ }
+ t.ctx["to"] = toVal
+ inputVal, err := t.toBuf(t.vm, input)
+ if err != nil {
+ t.err = err
+ return
+ }
+ t.ctx["input"] = inputVal
valueBig, err := t.toBig(t.vm, value.String())
if err != nil {
t.err = err
return
}
t.ctx["value"] = valueBig
- t.ctx["block"] = t.vm.ToValue(env.Context.BlockNumber.Uint64())
- // Update list of precompiles based on current block
- rules := env.ChainConfig().Rules(env.Context.BlockNumber)
- t.activePrecompiles = vm.ActivePrecompiles(rules)
}
-// CaptureState implements the Tracer interface to trace a single step of VM execution.
-func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
+// OnOpcode implements the Tracer interface to trace a single step of VM execution.
+func (t *jsTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
if !t.traceStep {
return
}
@@ -259,10 +322,10 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope
}
log := t.log
- log.op.op = op
- log.memory.memory = scope.Memory
- log.stack.stack = scope.Stack
- log.contract.contract = scope.Contract
+ log.op.op = vm.OpCode(op)
+ log.memory.memory = scope.MemoryData()
+ log.stack.stack = scope.StackData()
+ log.contract.scope = scope
log.pc = pc
log.gas = gas
log.cost = cost
@@ -274,36 +337,48 @@ func (t *jsTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope
}
}
-// CaptureFault implements the Tracer interface to trace an execution fault
-func (t *jsTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
+// OnFault implements the Tracer interface to trace an execution fault
+func (t *jsTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
if t.err != nil {
return
}
- // Other log fields have been already set as part of the last CaptureState.
+ // Other log fields have been already set as part of the last OnOpcode.
t.log.err = err
if _, err := t.fault(t.obj, t.logValue, t.dbValue); err != nil {
t.onError("fault", err)
}
}
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
- t.ctx["output"] = t.vm.ToValue(output)
+// onEnd is called after the call finishes to finalize the tracing.
+func (t *jsTracer) onEnd(output []byte, gasUsed uint64, err error, reverted bool) {
+ if t.err != nil {
+ return
+ }
if err != nil {
t.ctx["error"] = t.vm.ToValue(err.Error())
}
+ outputVal, err := t.toBuf(t.vm, output)
+ if err != nil {
+ t.err = err
+ return
+ }
+ t.ctx["output"] = outputVal
}
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
- if !t.traceFrame {
+// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
+func (t *jsTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, _ uint64) {
+ if t.err != nil {
return
}
- if t.err != nil {
+ if depth == 0 {
+ t.onStart(from, to, vm.OpCode(typ) == vm.CREATE, input, gas, value)
+ return
+ }
+ if !t.traceFrame {
return
}
- t.frame.typ = typ.String()
+ t.frame.typ = vm.OpCode(typ).String()
t.frame.from = from
t.frame.to = to
t.frame.input = common.CopyBytes(input)
@@ -318,9 +393,16 @@ func (t *jsTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Ad
}
}
-// CaptureExit is called when EVM exits a scope, even if the scope didn't
+// OnExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
-func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
+func (t *jsTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if t.err != nil {
+ return
+ }
+ if depth == 0 {
+ t.onEnd(output, gasUsed, err, reverted)
+ return
+ }
if !t.traceFrame {
return
}
@@ -336,6 +418,9 @@ func (t *jsTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
func (t *jsTracer) GetResult() (json.RawMessage, error) {
+ if t.err != nil {
+ return nil, t.err
+ }
ctx := t.vm.ToValue(t.ctx)
res, err := t.result(t.obj, ctx, t.dbValue)
if err != nil {
@@ -345,7 +430,7 @@ func (t *jsTracer) GetResult() (json.RawMessage, error) {
if err != nil {
return nil, err
}
- return json.RawMessage(encoded), t.err
+ return encoded, t.err
}
// Stop terminates execution of the tracer at the first opportune moment.
@@ -358,9 +443,6 @@ func (t *jsTracer) Stop(err error) {
// execution.
func (t *jsTracer) onError(context string, err error) {
t.err = wrapError(context, err)
- // `env` is set on CaptureStart which comes before any JS execution.
- // So it should be non-nil.
- t.env.Cancel()
}
func wrapError(context string, err error) error {
@@ -460,13 +542,13 @@ func (t *jsTracer) setBuiltinFunctions() {
}
return false
})
- vm.Set("slice", func(slice goja.Value, start, end int) goja.Value {
+ vm.Set("slice", func(slice goja.Value, start, end int64) goja.Value {
b, err := t.fromBuf(vm, slice, false)
if err != nil {
vm.Interrupt(err)
return nil
}
- if start < 0 || start > end || end > len(b) {
+ if start < 0 || start > end || end > int64(len(b)) {
vm.Interrupt(fmt.Sprintf("Tracer accessed out of bound memory: available %d, offset %d, size %d", len(b), start, end-start))
return nil
}
@@ -539,7 +621,7 @@ func (o *opObj) setupObject() *goja.Object {
}
type memoryObj struct {
- memory *vm.Memory
+ memory []byte
vm *goja.Runtime
toBig toBigFn
toBuf toBufFn
@@ -567,7 +649,7 @@ func (mo *memoryObj) slice(begin, end int64) ([]byte, error) {
if end < begin || begin < 0 {
return nil, fmt.Errorf("tracer accessed out of bound memory: offset %d, end %d", begin, end)
}
- slice, err := tracers.GetMemoryCopyPadded(mo.memory, begin, end-begin)
+ slice, err := internal.GetMemoryCopyPadded(mo.memory, begin, end-begin)
if err != nil {
return nil, err
}
@@ -590,14 +672,14 @@ func (mo *memoryObj) GetUint(addr int64) goja.Value {
// getUint returns the 32 bytes at the specified address interpreted as a uint.
func (mo *memoryObj) getUint(addr int64) (*big.Int, error) {
- if mo.memory.Len() < int(addr)+32 || addr < 0 {
- return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", mo.memory.Len(), addr, 32)
+ if len(mo.memory) < int(addr)+32 || addr < 0 {
+ return nil, fmt.Errorf("tracer accessed out of bound memory: available %d, offset %d, size %d", len(mo.memory), addr, 32)
}
- return new(big.Int).SetBytes(mo.memory.GetPtr(addr, 32)), nil
+ return new(big.Int).SetBytes(internal.MemoryPtr(mo.memory, addr, 32)), nil
}
func (mo *memoryObj) Length() int {
- return mo.memory.Len()
+ return len(mo.memory)
}
func (m *memoryObj) setupObject() *goja.Object {
@@ -609,7 +691,7 @@ func (m *memoryObj) setupObject() *goja.Object {
}
type stackObj struct {
- stack *vm.Stack
+ stack []uint256.Int
vm *goja.Runtime
toBig toBigFn
}
@@ -630,14 +712,14 @@ func (s *stackObj) Peek(idx int) goja.Value {
// peek returns the nth-from-the-top element of the stack.
func (s *stackObj) peek(idx int) (*big.Int, error) {
- if len(s.stack.Data()) <= idx || idx < 0 {
- return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack.Data()), idx)
+ if len(s.stack) <= idx || idx < 0 {
+ return nil, fmt.Errorf("tracer accessed out of bound stack: size %d, index %d", len(s.stack), idx)
}
- return s.stack.Back(idx).ToBig(), nil
+ return internal.StackBack(s.stack, idx).ToBig(), nil
}
func (s *stackObj) Length() int {
- return len(s.stack.Data())
+ return len(s.stack)
}
func (s *stackObj) setupObject() *goja.Object {
@@ -648,7 +730,7 @@ func (s *stackObj) setupObject() *goja.Object {
}
type dbObj struct {
- db vm.StateDB
+ db tracing.StateDB
vm *goja.Runtime
toBig toBigFn
toBuf toBufFn
@@ -740,14 +822,14 @@ func (do *dbObj) setupObject() *goja.Object {
}
type contractObj struct {
- contract *vm.Contract
- vm *goja.Runtime
- toBig toBigFn
- toBuf toBufFn
+ scope tracing.OpContext
+ vm *goja.Runtime
+ toBig toBigFn
+ toBuf toBufFn
}
func (co *contractObj) GetCaller() goja.Value {
- caller := co.contract.Caller().Bytes()
+ caller := co.scope.Caller().Bytes()
res, err := co.toBuf(co.vm, caller)
if err != nil {
co.vm.Interrupt(err)
@@ -757,7 +839,7 @@ func (co *contractObj) GetCaller() goja.Value {
}
func (co *contractObj) GetAddress() goja.Value {
- addr := co.contract.Address().Bytes()
+ addr := co.scope.Address().Bytes()
res, err := co.toBuf(co.vm, addr)
if err != nil {
co.vm.Interrupt(err)
@@ -767,7 +849,7 @@ func (co *contractObj) GetAddress() goja.Value {
}
func (co *contractObj) GetValue() goja.Value {
- value := co.contract.Value()
+ value := co.scope.CallValue()
res, err := co.toBig(co.vm, value.String())
if err != nil {
co.vm.Interrupt(err)
@@ -777,7 +859,7 @@ func (co *contractObj) GetValue() goja.Value {
}
func (co *contractObj) GetInput() goja.Value {
- input := common.CopyBytes(co.contract.Input)
+ input := common.CopyBytes(co.scope.CallInput())
res, err := co.toBuf(co.vm, input)
if err != nil {
co.vm.Interrupt(err)
diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go
index c7a2646a0..a8da0cd23 100644
--- a/eth/tracers/js/tracer_test.go
+++ b/eth/tracers/js/tracer_test.go
@@ -26,9 +26,11 @@ 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"
+ "github.com/holiman/uint256"
)
type account struct{}
@@ -37,9 +39,9 @@ func (account) SubBalance(amount *big.Int) {}
func (account) AddBalance(amount *big.Int) {}
func (account) SetAddress(common.Address) {}
func (account) Value() *big.Int { return nil }
-func (account) SetBalance(*big.Int) {}
+func (account) SetBalance(*uint256.Int) {}
func (account) SetNonce(uint64) {}
-func (account) Balance() *big.Int { return nil }
+func (account) Balance() *uint256.Int { return nil }
func (account) Address() common.Address { return common.Address{} }
func (account) SetCode(common.Hash, []byte) {}
func (account) ForEachStorage(cb func(key, value common.Hash) bool) {}
@@ -60,9 +62,9 @@ func testCtx() *vmContext {
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
}
-func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
+func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
var (
- env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer})
+ env = vm.NewEVM(vmctx.blockCtx, vmctx.txCtx, &dummyStatedb{}, chaincfg, vm.Config{Tracer: tracer.Hooks})
gasLimit uint64 = 31000
startGas uint64 = 10000
value = big.NewInt(0)
@@ -73,12 +75,12 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
contract.Code = contractCode
}
- tracer.CaptureTxStart(gasLimit, nil)
- tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value)
+ tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
+ tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value, 0)
ret, err := env.Interpreter().Run(contract, []byte{}, false)
- tracer.CaptureEnd(ret, startGas-contract.Gas, err)
+ tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
// Rest gas assumes no refund
- tracer.CaptureTxEnd(contract.Gas)
+ tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil)
if err != nil {
return nil, err
}
@@ -88,11 +90,12 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
func TestTracer(t *testing.T) {
execTracer := func(code string, contract []byte) ([]byte, string) {
t.Helper()
- tracer, err := newJsTracer(code, nil, nil)
+ chainConfig := params.TestChainConfig
+ tracer, err := newJsTracer(code, nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
- ret, err := runTrace(tracer, testCtx(), params.TestChainConfig, contract)
+ ret, err := runTrace(tracer, testCtx(), chainConfig, contract)
if err != nil {
return nil, err.Error() // Stringify to allow comparison without nil checks
}
@@ -162,7 +165,8 @@ func TestTracer(t *testing.T) {
func TestHalt(t *testing.T) {
timeout := errors.New("stahp")
- tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil)
+ chainConfig := params.TestChainConfig
+ tracer, err := newJsTracer("{step: function() { while(1); }, result: function() { return null; }, fault: function(){}}", nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
@@ -176,19 +180,21 @@ func TestHalt(t *testing.T) {
}
func TestHaltBetweenSteps(t *testing.T) {
- tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil)
+ chainConfig := params.TestChainConfig
+ tracer, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }}", nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
- env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer})
scope := &vm.ScopeContext{
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
}
- tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 0, big.NewInt(0))
- tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil)
+ env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(1)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer.Hooks})
+ tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
+ tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 0, big.NewInt(0), 0)
+ tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
timeout := errors.New("stahp")
tracer.Stop(timeout)
- tracer.CaptureState(0, 0, 0, 0, scope, nil, 0, nil)
+ tracer.OnOpcode(0, 0, 0, 0, scope, nil, 0, nil)
if _, err := tracer.GetResult(); !strings.Contains(err.Error(), timeout.Error()) {
t.Errorf("Expected timeout error, got %v", err)
@@ -200,13 +206,15 @@ func TestHaltBetweenSteps(t *testing.T) {
func TestNoStepExec(t *testing.T) {
execTracer := func(code string) []byte {
t.Helper()
- tracer, err := newJsTracer(code, nil, nil)
+ chainConfig := params.TestChainConfig
+ tracer, err := newJsTracer(code, nil, nil, chainConfig)
if err != nil {
t.Fatal(err)
}
- env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: tracer})
- tracer.CaptureStart(env, common.Address{}, common.Address{}, false, []byte{}, 1000, big.NewInt(0))
- tracer.CaptureEnd(nil, 0, nil)
+ env := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, vm.TxContext{GasPrice: big.NewInt(100)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks})
+ tracer.OnTxStart(env.GetVMContext(), types.NewTx(&types.LegacyTx{}), common.Address{})
+ tracer.OnEnter(0, byte(vm.CALL), common.Address{}, common.Address{}, []byte{}, 1000, big.NewInt(0), 0)
+ tracer.OnExit(0, nil, 0, nil, false)
ret, err := tracer.GetResult()
if err != nil {
t.Fatal(err)
@@ -229,12 +237,12 @@ func TestNoStepExec(t *testing.T) {
}
func TestIsPrecompile(t *testing.T) {
- chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP150Hash: common.Hash{}, EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil}
+ chaincfg := ¶ms.ChainConfig{ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(0), DAOForkBlock: nil, DAOForkSupport: false, EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(0), EIP158Block: big.NewInt(0), ByzantiumBlock: big.NewInt(100), ConstantinopleBlock: big.NewInt(0), PetersburgBlock: big.NewInt(0), IstanbulBlock: big.NewInt(200), MuirGlacierBlock: big.NewInt(0), BerlinBlock: big.NewInt(300), LondonBlock: big.NewInt(0), TerminalTotalDifficulty: nil, Ethash: new(params.EthashConfig), Clique: nil}
chaincfg.ByzantiumBlock = big.NewInt(100)
chaincfg.IstanbulBlock = big.NewInt(200)
chaincfg.BerlinBlock = big.NewInt(300)
txCtx := vm.TxContext{GasPrice: big.NewInt(100000)}
- tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
+ tracer, err := newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
if err != nil {
t.Fatal(err)
}
@@ -248,7 +256,7 @@ func TestIsPrecompile(t *testing.T) {
t.Errorf("tracer should not consider blake2f as precompile in byzantium")
}
- tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil)
+ tracer, _ = newJsTracer("{addr: toAddress('0000000000000000000000000000000000000009'), res: null, step: function() { this.res = isPrecompiled(this.addr); }, fault: function() {}, result: function() { return this.res; }}", nil, nil, chaincfg)
blockCtx = vm.BlockContext{BlockNumber: big.NewInt(250)}
res, err = runTrace(tracer, &vmContext{blockCtx, txCtx}, chaincfg, nil)
if err != nil {
@@ -260,23 +268,24 @@ func TestIsPrecompile(t *testing.T) {
}
func TestEnterExit(t *testing.T) {
+ chainConfig := params.TestChainConfig
// test that either both or none of enter() and exit() are defined
- if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil {
+ if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil, chainConfig); err == nil {
t.Fatal("tracer creation should've failed without exit() definition")
}
- if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil {
+ if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil, chainConfig); err != nil {
t.Fatal(err)
}
// test that the enter and exit method are correctly invoked and the values passed
- tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil)
+ tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil, chainConfig)
if err != nil {
t.Fatal(err)
}
scope := &vm.ScopeContext{
Contract: vm.NewContract(&account{}, &account{}, big.NewInt(0), 0),
}
- tracer.CaptureEnter(vm.CALL, scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int))
- tracer.CaptureExit([]byte{}, 400, nil)
+ tracer.OnEnter(1, byte(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int), 0)
+ tracer.OnExit(1, []byte{}, 400, nil, false)
have, err := tracer.GetResult()
if err != nil {
@@ -289,8 +298,9 @@ func TestEnterExit(t *testing.T) {
}
func TestSetup(t *testing.T) {
+ chainConfig := params.TestChainConfig
// Test empty config
- _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil)
+ _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil, chainConfig)
if err != nil {
t.Error(err)
}
@@ -300,12 +310,12 @@ func TestSetup(t *testing.T) {
t.Fatal(err)
}
// Test no setup func
- _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg)
+ _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg, chainConfig)
if err != nil {
t.Fatal(err)
}
// Test config value
- tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg)
+ tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg, chainConfig)
if err != nil {
t.Fatal(err)
}
diff --git a/eth/tracers/live.go b/eth/tracers/live.go
new file mode 100644
index 000000000..894ce7b9b
--- /dev/null
+++ b/eth/tracers/live.go
@@ -0,0 +1,34 @@
+package tracers
+
+import (
+ "encoding/json"
+ "errors"
+
+ "github.com/ethereum/go-ethereum/core/tracing"
+)
+
+type ctorFunc func(config json.RawMessage) (*tracing.Hooks, error)
+
+// LiveDirectory is the collection of tracers which can be used
+// during normal block import operations.
+var LiveDirectory = liveDirectory{elems: make(map[string]ctorFunc)}
+
+type liveDirectory struct {
+ elems map[string]ctorFunc
+}
+
+// Register registers a tracer constructor by name.
+func (d *liveDirectory) Register(name string, f ctorFunc) {
+ d.elems[name] = f
+}
+
+// New instantiates a tracer by name.
+func (d *liveDirectory) New(name string, config json.RawMessage) (*tracing.Hooks, error) {
+ if len(config) == 0 {
+ config = json.RawMessage("{}")
+ }
+ if f, ok := d.elems[name]; ok {
+ return f(config)
+ }
+ return nil, errors.New("not found")
+}
diff --git a/eth/tracers/live/gen_supplyinfoburn.go b/eth/tracers/live/gen_supplyinfoburn.go
new file mode 100644
index 000000000..d01eda397
--- /dev/null
+++ b/eth/tracers/live/gen_supplyinfoburn.go
@@ -0,0 +1,49 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package live
+
+import (
+ "encoding/json"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+var _ = (*supplyInfoBurnMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (s supplyInfoBurn) MarshalJSON() ([]byte, error) {
+ type supplyInfoBurn struct {
+ EIP1559 *hexutil.Big `json:"1559,omitempty"`
+ Blob *hexutil.Big `json:"blob,omitempty"`
+ Misc *hexutil.Big `json:"misc,omitempty"`
+ }
+ var enc supplyInfoBurn
+ enc.EIP1559 = (*hexutil.Big)(s.EIP1559)
+ enc.Blob = (*hexutil.Big)(s.Blob)
+ enc.Misc = (*hexutil.Big)(s.Misc)
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (s *supplyInfoBurn) UnmarshalJSON(input []byte) error {
+ type supplyInfoBurn struct {
+ EIP1559 *hexutil.Big `json:"1559,omitempty"`
+ Blob *hexutil.Big `json:"blob,omitempty"`
+ Misc *hexutil.Big `json:"misc,omitempty"`
+ }
+ var dec supplyInfoBurn
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.EIP1559 != nil {
+ s.EIP1559 = (*big.Int)(dec.EIP1559)
+ }
+ if dec.Blob != nil {
+ s.Blob = (*big.Int)(dec.Blob)
+ }
+ if dec.Misc != nil {
+ s.Misc = (*big.Int)(dec.Misc)
+ }
+ return nil
+}
diff --git a/eth/tracers/live/gen_supplyinfoissuance.go b/eth/tracers/live/gen_supplyinfoissuance.go
new file mode 100644
index 000000000..23a43804a
--- /dev/null
+++ b/eth/tracers/live/gen_supplyinfoissuance.go
@@ -0,0 +1,43 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package live
+
+import (
+ "encoding/json"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+)
+
+var _ = (*supplyInfoIssuanceMarshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (s supplyInfoIssuance) MarshalJSON() ([]byte, error) {
+ type supplyInfoIssuance struct {
+ GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
+ Reward *hexutil.Big `json:"reward,omitempty"`
+ }
+ var enc supplyInfoIssuance
+ enc.GenesisAlloc = (*hexutil.Big)(s.GenesisAlloc)
+ enc.Reward = (*hexutil.Big)(s.Reward)
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (s *supplyInfoIssuance) UnmarshalJSON(input []byte) error {
+ type supplyInfoIssuance struct {
+ GenesisAlloc *hexutil.Big `json:"genesisAlloc,omitempty"`
+ Reward *hexutil.Big `json:"reward,omitempty"`
+ }
+ var dec supplyInfoIssuance
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.GenesisAlloc != nil {
+ s.GenesisAlloc = (*big.Int)(dec.GenesisAlloc)
+ }
+ if dec.Reward != nil {
+ s.Reward = (*big.Int)(dec.Reward)
+ }
+ return nil
+}
diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go
new file mode 100644
index 000000000..5d4510304
--- /dev/null
+++ b/eth/tracers/live/noop.go
@@ -0,0 +1,96 @@
+package live
+
+import (
+ "encoding/json"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/params"
+)
+
+func init() {
+ tracers.LiveDirectory.Register("noop", newNoopTracer)
+}
+
+// noop is a no-op live tracer. It's there to
+// catch changes in the tracing interface, as well as
+// for testing live tracing performance. Can be removed
+// as soon as we have a real live tracer.
+type noop struct{}
+
+func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) {
+ t := &noop{}
+ return &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnOpcode: t.OnOpcode,
+ OnFault: t.OnFault,
+ OnGasChange: t.OnGasChange,
+ OnBlockchainInit: t.OnBlockchainInit,
+ OnBlockStart: t.OnBlockStart,
+ OnBlockEnd: t.OnBlockEnd,
+ OnSkippedBlock: t.OnSkippedBlock,
+ OnGenesisBlock: t.OnGenesisBlock,
+ OnBalanceChange: t.OnBalanceChange,
+ OnNonceChange: t.OnNonceChange,
+ OnCodeChange: t.OnCodeChange,
+ OnStorageChange: t.OnStorageChange,
+ OnLog: t.OnLog,
+ }, nil
+}
+
+func (t *noop) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
+}
+
+func (t *noop) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) {
+}
+
+func (t *noop) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64) {
+}
+
+func (t *noop) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+}
+
+func (t *noop) OnTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) {
+}
+
+func (t *noop) OnTxEnd(receipt *types.Receipt, err error) {
+}
+
+func (t *noop) OnBlockStart(ev tracing.BlockEvent) {
+}
+
+func (t *noop) OnBlockEnd(err error) {
+}
+
+func (t *noop) OnSkippedBlock(ev tracing.BlockEvent) {}
+
+func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) {
+}
+
+func (t *noop) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) {
+}
+
+func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
+}
+
+func (t *noop) OnNonceChange(a common.Address, prev, new uint64) {
+}
+
+func (t *noop) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
+}
+
+func (t *noop) OnStorageChange(a common.Address, k, prev, new common.Hash) {
+}
+
+func (t *noop) OnLog(l *types.Log) {
+
+}
+
+func (t *noop) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
+}
diff --git a/eth/tracers/live/supply.go b/eth/tracers/live/supply.go
new file mode 100644
index 000000000..5c3ad2ddf
--- /dev/null
+++ b/eth/tracers/live/supply.go
@@ -0,0 +1,301 @@
+package live
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math/big"
+ "path/filepath"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/consensus/misc/eip4844"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "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/log"
+ "gopkg.in/natefinch/lumberjack.v2"
+)
+
+func init() {
+ tracers.LiveDirectory.Register("supply", newSupplyTracer)
+}
+
+type supplyInfoIssuance struct {
+ GenesisAlloc *big.Int `json:"genesisAlloc,omitempty"`
+ Reward *big.Int `json:"reward,omitempty"`
+}
+
+//go:generate go run github.com/fjl/gencodec -type supplyInfoIssuance -field-override supplyInfoIssuanceMarshaling -out gen_supplyinfoissuance.go
+type supplyInfoIssuanceMarshaling struct {
+ GenesisAlloc *hexutil.Big
+ Reward *hexutil.Big
+}
+
+type supplyInfoBurn struct {
+ EIP1559 *big.Int `json:"1559,omitempty"`
+ Blob *big.Int `json:"blob,omitempty"`
+ Misc *big.Int `json:"misc,omitempty"`
+}
+
+//go:generate go run github.com/fjl/gencodec -type supplyInfoBurn -field-override supplyInfoBurnMarshaling -out gen_supplyinfoburn.go
+type supplyInfoBurnMarshaling struct {
+ EIP1559 *hexutil.Big
+ Blob *hexutil.Big
+ Misc *hexutil.Big
+}
+
+type supplyInfo struct {
+ Issuance *supplyInfoIssuance `json:"issuance,omitempty"`
+ Burn *supplyInfoBurn `json:"burn,omitempty"`
+
+ // Block info
+ Number uint64 `json:"blockNumber"`
+ Hash common.Hash `json:"hash"`
+ ParentHash common.Hash `json:"parentHash"`
+}
+
+type supplyTxCallstack struct {
+ calls []supplyTxCallstack
+ burn *big.Int
+}
+
+type supplyTracer struct {
+ delta supplyInfo
+ txCallstack []supplyTxCallstack // Callstack for current transaction
+ logger *lumberjack.Logger
+}
+
+type supplyTracerConfig struct {
+ Path string `json:"path"` // Path to the directory where the tracer logs will be stored
+ MaxSize int `json:"maxSize"` // MaxSize is the maximum size in megabytes of the tracer log file before it gets rotated. It defaults to 100 megabytes.
+}
+
+func newSupplyTracer(cfg json.RawMessage) (*tracing.Hooks, error) {
+ var config supplyTracerConfig
+ if cfg != nil {
+ if err := json.Unmarshal(cfg, &config); err != nil {
+ return nil, fmt.Errorf("failed to parse config: %v", err)
+ }
+ }
+ if config.Path == "" {
+ return nil, errors.New("supply tracer output path is required")
+ }
+
+ // Store traces in a rotating file
+ logger := &lumberjack.Logger{
+ Filename: filepath.Join(config.Path, "supply.jsonl"),
+ }
+ if config.MaxSize > 0 {
+ logger.MaxSize = config.MaxSize
+ }
+
+ t := &supplyTracer{
+ delta: newSupplyInfo(),
+ logger: logger,
+ }
+ return &tracing.Hooks{
+ OnBlockStart: t.onBlockStart,
+ OnBlockEnd: t.onBlockEnd,
+ OnGenesisBlock: t.onGenesisBlock,
+ OnTxStart: t.onTxStart,
+ OnBalanceChange: t.onBalanceChange,
+ OnEnter: t.onEnter,
+ OnExit: t.onExit,
+ OnClose: t.onClose,
+ }, nil
+}
+
+func newSupplyInfo() supplyInfo {
+ return supplyInfo{
+ Issuance: &supplyInfoIssuance{
+ GenesisAlloc: big.NewInt(0),
+ Reward: big.NewInt(0),
+ },
+ Burn: &supplyInfoBurn{
+ EIP1559: big.NewInt(0),
+ Blob: big.NewInt(0),
+ Misc: big.NewInt(0),
+ },
+
+ Number: 0,
+ Hash: common.Hash{},
+ ParentHash: common.Hash{},
+ }
+}
+
+func (s *supplyTracer) resetDelta() {
+ s.delta = newSupplyInfo()
+}
+
+func (s *supplyTracer) onBlockStart(ev tracing.BlockEvent) {
+ s.resetDelta()
+
+ s.delta.Number = ev.Block.NumberU64()
+ s.delta.Hash = ev.Block.Hash()
+ s.delta.ParentHash = ev.Block.ParentHash()
+
+ // Calculate Burn for this block
+ if ev.Block.BaseFee() != nil {
+ burn := new(big.Int).Mul(new(big.Int).SetUint64(ev.Block.GasUsed()), ev.Block.BaseFee())
+ s.delta.Burn.EIP1559 = burn
+ }
+ // Blob burnt gas
+ if blobGas := ev.Block.BlobGasUsed(); blobGas != nil && *blobGas > 0 && ev.Block.ExcessBlobGas() != nil {
+ var (
+ excess = *ev.Block.ExcessBlobGas()
+ baseFee = eip4844.CalcBlobFee(excess)
+ burn = new(big.Int).Mul(new(big.Int).SetUint64(*blobGas), baseFee)
+ )
+ s.delta.Burn.Blob = burn
+ }
+}
+
+func (s *supplyTracer) onBlockEnd(err error) {
+ s.write(s.delta)
+}
+
+func (s *supplyTracer) onGenesisBlock(b *types.Block, alloc types.GenesisAlloc) {
+ s.resetDelta()
+
+ s.delta.Number = b.NumberU64()
+ s.delta.Hash = b.Hash()
+ s.delta.ParentHash = b.ParentHash()
+
+ // Initialize supply with total allocation in genesis block
+ for _, account := range alloc {
+ s.delta.Issuance.GenesisAlloc.Add(s.delta.Issuance.GenesisAlloc, account.Balance)
+ }
+
+ s.write(s.delta)
+}
+
+func (s *supplyTracer) onBalanceChange(a common.Address, prevBalance, newBalance *big.Int, reason tracing.BalanceChangeReason) {
+ diff := new(big.Int).Sub(newBalance, prevBalance)
+
+ // NOTE: don't handle "BalanceIncreaseGenesisBalance" because it is handled in onGenesisBlock
+ switch reason {
+ case tracing.BalanceIncreaseRewardMineUncle:
+ case tracing.BalanceIncreaseRewardMineBlock:
+ s.delta.Issuance.Reward.Add(s.delta.Issuance.Reward, diff)
+ case tracing.BalanceDecreaseSelfdestructBurn:
+ // BalanceDecreaseSelfdestructBurn is non-reversible as it happens
+ // at the end of the transaction.
+ s.delta.Burn.Misc.Sub(s.delta.Burn.Misc, diff)
+ default:
+ return
+ }
+}
+
+func (s *supplyTracer) onTxStart(vm *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ s.txCallstack = make([]supplyTxCallstack, 0, 1)
+}
+
+// internalTxsHandler handles internal transactions burned amount
+func (s *supplyTracer) internalTxsHandler(call *supplyTxCallstack) {
+ // Handle Burned amount
+ if call.burn != nil {
+ s.delta.Burn.Misc.Add(s.delta.Burn.Misc, call.burn)
+ }
+
+ if len(call.calls) > 0 {
+ // Recursivelly handle internal calls
+ for _, call := range call.calls {
+ callCopy := call
+ s.internalTxsHandler(&callCopy)
+ }
+ }
+}
+
+func (s *supplyTracer) onEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64) {
+ call := supplyTxCallstack{
+ calls: make([]supplyTxCallstack, 0),
+ }
+
+ // This is a special case of burned amount which has to be handled here
+ // which happens when type == selfdestruct and from == to.
+ if vm.OpCode(typ) == vm.SELFDESTRUCT && from == to && value.Cmp(common.Big0) == 1 {
+ call.burn = value
+ }
+
+ // Append call to the callstack, so we can fill the details in CaptureExit
+ s.txCallstack = append(s.txCallstack, call)
+}
+
+func (s *supplyTracer) onExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth == 0 {
+ // No need to handle Burned amount if transaction is reverted
+ if !reverted {
+ s.internalTxsHandler(&s.txCallstack[0])
+ }
+ return
+ }
+
+ size := len(s.txCallstack)
+ if size <= 1 {
+ return
+ }
+ // Pop call
+ call := s.txCallstack[size-1]
+ s.txCallstack = s.txCallstack[:size-1]
+ size -= 1
+
+ // In case of a revert, we can drop the call and all its subcalls.
+ // Caution, that this has to happen after popping the call from the stack.
+ if reverted {
+ return
+ }
+ s.txCallstack[size-1].calls = append(s.txCallstack[size-1].calls, call)
+}
+
+func (s *supplyTracer) onClose() {
+ if err := s.logger.Close(); err != nil {
+ log.Warn("failed to close supply tracer log file", "error", err)
+ }
+}
+
+func (s *supplyTracer) write(data any) {
+ supply, ok := data.(supplyInfo)
+ if !ok {
+ log.Warn("failed to cast supply tracer data on write to log file")
+ return
+ }
+
+ // Remove empty fields
+ if supply.Issuance.GenesisAlloc.Sign() == 0 {
+ supply.Issuance.GenesisAlloc = nil
+ }
+
+ if supply.Issuance.Reward.Sign() == 0 {
+ supply.Issuance.Reward = nil
+ }
+
+ if supply.Issuance.GenesisAlloc == nil && supply.Issuance.Reward == nil {
+ supply.Issuance = nil
+ }
+
+ if supply.Burn.EIP1559.Sign() == 0 {
+ supply.Burn.EIP1559 = nil
+ }
+
+ if supply.Burn.Blob.Sign() == 0 {
+ supply.Burn.Blob = nil
+ }
+
+ if supply.Burn.Misc.Sign() == 0 {
+ supply.Burn.Misc = nil
+ }
+
+ if supply.Burn.EIP1559 == nil && supply.Burn.Blob == nil && supply.Burn.Misc == nil {
+ supply.Burn = nil
+ }
+
+ out, _ := json.Marshal(supply)
+ if _, err := s.logger.Write(out); err != nil {
+ log.Warn("failed to write to supply tracer log file", "error", err)
+ }
+ if _, err := s.logger.Write([]byte{'\n'}); err != nil {
+ log.Warn("failed to write to supply tracer log file", "error", err)
+ }
+}
diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go
index 78bfcc9cc..15fbf9ae0 100644
--- a/eth/tracers/logger/access_list_tracer.go
+++ b/eth/tracers/logger/access_list_tracer.go
@@ -17,9 +17,8 @@
package logger
import (
- "math/big"
-
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
)
@@ -126,17 +125,20 @@ func NewAccessListTracer(acl types.AccessList, addressesToExclude map[common.Add
}
}
-func (a *AccessListTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+func (a *AccessListTracer) Hooks() *tracing.Hooks {
+ return &tracing.Hooks{
+ OnOpcode: a.OnOpcode,
+ }
}
-// CaptureState captures all opcodes that touch storage or addresses and adds them to the accesslist.
-func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
- stack := scope.Stack
- stackData := stack.Data()
+// OnOpcode captures all opcodes that touch storage or addresses and adds them to the accesslist.
+func (a *AccessListTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
+ stackData := scope.StackData()
stackLen := len(stackData)
+ op := vm.OpCode(opcode)
if (op == vm.SLOAD || op == vm.SSTORE) && stackLen >= 1 {
slot := common.Hash(stackData[stackLen-1].Bytes32())
- a.list.addSlot(scope.Contract.Address(), slot)
+ a.list.addSlot(scope.Address(), slot)
}
if (op == vm.EXTCODECOPY || op == vm.EXTCODEHASH || op == vm.EXTCODESIZE || op == vm.BALANCE || op == vm.SELFDESTRUCT) && stackLen >= 1 {
addr := common.Address(stackData[stackLen-1].Bytes20())
@@ -152,20 +154,6 @@ func (a *AccessListTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint6
}
}
-func (*AccessListTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
-}
-
-func (*AccessListTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {}
-
-func (*AccessListTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
-}
-
-func (*AccessListTracer) CaptureExit(output []byte, gasUsed uint64, err error) {}
-
-func (*AccessListTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {}
-
-func (*AccessListTracer) CaptureTxEnd(restGas uint64) {}
-
// AccessList returns the current accesslist maintained by the tracer.
func (a *AccessListTracer) AccessList() types.AccessList {
return a.list.accessList()
diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go
index 5fad1cdb7..99f296b98 100644
--- a/eth/tracers/logger/logger.go
+++ b/eth/tracers/logger/logger.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/params"
@@ -83,7 +84,7 @@ type structLogMarshaling struct {
GasCost math.HexOrDecimal64
Memory hexutil.Bytes
ReturnData hexutil.Bytes
- Stack []hexutil.U256
+ Stack []uint256.Int
OpName string `json:"opName"` // adds call to OpName() in MarshalJSON
ErrorString string `json:"error,omitempty"` // adds call to ErrorString() in MarshalJSON
}
@@ -108,14 +109,13 @@ func (s *StructLog) ErrorString() string {
// contract their storage.
type StructLogger struct {
cfg Config
- env *vm.EVM
+ env *tracing.VMContext
- 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
@@ -132,6 +132,15 @@ func NewStructLogger(cfg *Config) *StructLogger {
return logger
}
+func (l *StructLogger) Hooks() *tracing.Hooks {
+ return &tracing.Hooks{
+ OnTxStart: l.OnTxStart,
+ OnTxEnd: l.OnTxEnd,
+ OnExit: l.OnExit,
+ OnOpcode: l.OnOpcode,
+ }
+}
+
// Reset clears the data held by the logger.
func (l *StructLogger) Reset() {
l.storage = make(map[common.Address]Storage)
@@ -140,15 +149,10 @@ func (l *StructLogger) Reset() {
l.err = nil
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- l.env = env
-}
-
-// CaptureState logs a new structured log message and pushes it out to the environment
+// OnOpcode logs a new structured log message and pushes it out to the environment
//
-// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
-func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
+// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
+func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
// If tracing was interrupted, set the error and stop
if l.interrupt.Load() {
return
@@ -158,49 +162,47 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
return
}
- memory := scope.Memory
- stack := scope.Stack
- contract := scope.Contract
+ op := vm.OpCode(opcode)
+ memory := scope.MemoryData()
+ stack := scope.StackData()
// Copy a snapshot of the current memory state to a new buffer
var mem []byte
if l.cfg.EnableMemory {
- mem = make([]byte, len(memory.Data()))
- copy(mem, memory.Data())
+ mem = make([]byte, len(memory))
+ copy(mem, memory)
}
// Copy a snapshot of the current stack state to a new buffer
var stck []uint256.Int
if !l.cfg.DisableStack {
- stck = make([]uint256.Int, len(stack.Data()))
- for i, item := range stack.Data() {
- stck[i] = item
- }
+ stck = make([]uint256.Int, len(stack))
+ copy(stck, stack)
}
- stackData := stack.Data()
- stackLen := len(stackData)
+ contractAddr := scope.Address()
+ stackLen := len(stack)
// Copy a snapshot of the current storage to a new container
var storage Storage
if !l.cfg.DisableStorage && (op == vm.SLOAD || op == vm.SSTORE) {
// initialise new changed values storage container for this contract
// if not present.
- if l.storage[contract.Address()] == nil {
- l.storage[contract.Address()] = make(Storage)
+ if l.storage[contractAddr] == nil {
+ l.storage[contractAddr] = make(Storage)
}
// capture SLOAD opcodes and record the read entry in the local storage
if op == vm.SLOAD && stackLen >= 1 {
var (
- address = common.Hash(stackData[stackLen-1].Bytes32())
- value = l.env.StateDB.GetState(contract.Address(), address)
+ address = common.Hash(stack[stackLen-1].Bytes32())
+ value = l.env.StateDB.GetState(contractAddr, address)
)
- l.storage[contract.Address()][address] = value
- storage = l.storage[contract.Address()].Copy()
+ l.storage[contractAddr][address] = value
+ storage = l.storage[contractAddr].Copy()
} else if op == vm.SSTORE && stackLen >= 2 {
// capture SSTORE opcodes and record the written entry in the local storage.
var (
- value = common.Hash(stackData[stackLen-2].Bytes32())
- address = common.Hash(stackData[stackLen-1].Bytes32())
+ value = common.Hash(stack[stackLen-2].Bytes32())
+ address = common.Hash(stack[stackLen-1].Bytes32())
)
- l.storage[contract.Address()][address] = value
- storage = l.storage[contract.Address()].Copy()
+ l.storage[contractAddr][address] = value
+ storage = l.storage[contractAddr].Copy()
}
}
var rdata []byte
@@ -209,17 +211,15 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
copy(rdata, rData)
}
// create a new snapshot of the EVM.
- log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
+ log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
l.logs = append(l.logs, log)
}
-// CaptureFault implements the EVMLogger interface to trace an execution fault
-// while running an opcode.
-func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
-}
-
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
+// OnExit is called a call frame finishes processing.
+func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth != 0 {
+ return
+ }
l.output = output
l.err = err
if l.cfg.Debug {
@@ -230,12 +230,6 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
}
}
-func (l *StructLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
-}
-
-func (l *StructLogger) CaptureExit(output []byte, gasUsed uint64, err error) {
-}
-
func (l *StructLogger) GetResult() (json.RawMessage, error) {
// Tracing aborted
if l.reason != nil {
@@ -262,12 +256,19 @@ func (l *StructLogger) Stop(err error) {
l.interrupt.Store(true)
}
-func (l *StructLogger) CaptureTxStart(gasLimit uint64, payer *common.Address) {
- l.gasLimit = gasLimit
+func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ l.env = env
}
-func (l *StructLogger) CaptureTxEnd(restGas uint64) {
- l.usedGas = l.gasLimit - restGas
+func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) {
+ if err != nil {
+ // Don't override vm error
+ if l.err == nil {
+ l.err = err
+ }
+ return
+ }
+ l.usedGas = receipt.GasUsed
}
// StructLogs returns the captured log entries.
@@ -329,7 +330,7 @@ func WriteLogs(writer io.Writer, logs []*types.Log) {
type mdLogger struct {
out io.Writer
cfg *Config
- env *vm.EVM
+ env *tracing.VMContext
}
// NewMarkdownLogger creates a logger which outputs information in a format adapted
@@ -342,8 +343,25 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger {
return l
}
-func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+func (t *mdLogger) Hooks() *tracing.Hooks {
+ return &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnOpcode: t.OnOpcode,
+ OnFault: t.OnFault,
+ }
+}
+
+func (t *mdLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
t.env = env
+}
+
+func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, _ uint64) {
+ if depth != 0 {
+ return
+ }
+ create := vm.OpCode(typ) == vm.CREATE
if !create {
fmt.Fprintf(t.out, "From: `%v`\nTo: `%v`\nData: `%#x`\nGas: `%d`\nValue `%v` wei\n",
from.String(), to.String(),
@@ -360,15 +378,22 @@ func (t *mdLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Addr
`)
}
-// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
-func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
- stack := scope.Stack
+func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth == 0 {
+ fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
+ output, gasUsed, err)
+ }
+}
+
+// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
+func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
+ stack := scope.StackData()
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost)
if !t.cfg.DisableStack {
// format stack
var a []string
- for _, elem := range stack.Data() {
+ for _, elem := range stack {
a = append(a, elem.Hex())
}
b := fmt.Sprintf("[%v]", strings.Join(a, ","))
@@ -381,24 +406,10 @@ func (t *mdLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope
}
}
-func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
+func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
}
-func (t *mdLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
- fmt.Fprintf(t.out, "\nOutput: `%#x`\nConsumed gas: `%d`\nError: `%v`\n",
- output, gasUsed, err)
-}
-
-func (t *mdLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
-}
-
-func (t *mdLogger) CaptureExit(output []byte, gasUsed uint64, err error) {}
-
-func (*mdLogger) CaptureTxStart(gasLimit uint64, payer *common.Address) {}
-
-func (*mdLogger) CaptureTxEnd(restGas uint64) {}
-
// ExecutionResult groups all structured logs emitted by the EVM
// while replaying a transaction in debug mode as well as transaction
// execution status, the amount of gas used and the return value
@@ -419,6 +430,7 @@ type StructLogRes struct {
Depth int `json:"depth"`
Error string `json:"error,omitempty"`
Stack *[]string `json:"stack,omitempty"`
+ ReturnData string `json:"returnData,omitempty"`
Memory *[]string `json:"memory,omitempty"`
Storage *map[string]string `json:"storage,omitempty"`
RefundCounter uint64 `json:"refund,omitempty"`
@@ -444,6 +456,9 @@ func formatLogs(logs []StructLog) []StructLogRes {
}
formatted[index].Stack = &stack
}
+ if trace.ReturnData != nil && len(trace.ReturnData) > 0 {
+ formatted[index].ReturnData = hexutil.Bytes(trace.ReturnData).String()
+ }
if trace.Memory != nil {
memory := make([]string, 0, (len(trace.Memory)+31)/32)
for i := 0; i+32 <= len(trace.Memory); i += 32 {
diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go
index e59e2b2b7..6fac2d115 100644
--- a/eth/tracers/logger/logger_json.go
+++ b/eth/tracers/logger/logger_json.go
@@ -19,58 +19,59 @@ package logger
import (
"encoding/json"
"io"
- "math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
)
-type JSONLogger struct {
+type jsonLogger struct {
encoder *json.Encoder
cfg *Config
- env *vm.EVM
+ env *tracing.VMContext
}
// NewJSONLogger creates a new EVM tracer that prints execution steps as JSON objects
// into the provided stream.
-func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger {
- l := &JSONLogger{encoder: json.NewEncoder(writer), cfg: cfg}
+func NewJSONLogger(cfg *Config, writer io.Writer) *tracing.Hooks {
+ l := &jsonLogger{encoder: json.NewEncoder(writer), cfg: cfg}
if l.cfg == nil {
l.cfg = &Config{}
}
- return l
-}
-
-func (l *JSONLogger) CaptureStart(env *vm.EVM, from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- l.env = env
+ return &tracing.Hooks{
+ OnTxStart: l.OnTxStart,
+ OnExit: l.OnExit,
+ OnOpcode: l.OnOpcode,
+ OnFault: l.OnFault,
+ }
}
-func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) {
+func (l *jsonLogger) OnFault(pc uint64, op byte, gas uint64, cost uint64, scope tracing.OpContext, depth int, err error) {
// TODO: Add rData to this interface as well
- l.CaptureState(pc, op, gas, cost, scope, nil, depth, err)
+ l.OnOpcode(pc, op, gas, cost, scope, nil, depth, err)
}
-// CaptureState outputs state information on the logger.
-func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
- memory := scope.Memory
- stack := scope.Stack
+func (l *jsonLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
+ memory := scope.MemoryData()
+ stack := scope.StackData()
log := StructLog{
Pc: pc,
- Op: op,
+ Op: vm.OpCode(op),
Gas: gas,
GasCost: cost,
- MemorySize: memory.Len(),
+ MemorySize: len(memory),
Depth: depth,
RefundCounter: l.env.StateDB.GetRefund(),
Err: err,
}
if l.cfg.EnableMemory {
- log.Memory = memory.Data()
+ log.Memory = memory
}
if !l.cfg.DisableStack {
- log.Stack = stack.Data()
+ log.Stack = stack
}
if l.cfg.EnableReturnData {
log.ReturnData = rData
@@ -78,8 +79,10 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
l.encoder.Encode(log)
}
-// CaptureEnd is triggered at end of execution.
-func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
+func (l *jsonLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth > 0 {
+ return
+ }
type endLog struct {
Output string `json:"output"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
@@ -92,11 +95,6 @@ func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
l.encoder.Encode(endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), errMsg})
}
-func (l *JSONLogger) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+func (l *jsonLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ l.env = env
}
-
-func (l *JSONLogger) CaptureExit(output []byte, gasUsed uint64, err error) {}
-
-func (l *JSONLogger) CaptureTxStart(gasLimit uint64, payer *common.Address) {}
-
-func (l *JSONLogger) CaptureTxEnd(restGas uint64) {}
diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go
index bde43e5ff..d3bfc13a0 100644
--- a/eth/tracers/logger/logger_test.go
+++ b/eth/tracers/logger/logger_test.go
@@ -18,7 +18,7 @@ package logger
import (
"encoding/json"
- "fmt"
+ "errors"
"math/big"
"testing"
@@ -55,12 +55,12 @@ func (*dummyStatedb) SetState(_ common.Address, _ common.Hash, _ common.Hash) {}
func TestStoreCapture(t *testing.T) {
var (
logger = NewStructLogger(nil)
- env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger})
+ env = vm.NewEVM(vm.BlockContext{}, vm.TxContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()})
contract = vm.NewContract(&dummyContractRef{}, &dummyContractRef{}, new(big.Int), 100000)
)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
var index common.Hash
- logger.CaptureStart(env, common.Address{}, contract.Address(), false, nil, 0, nil)
+ logger.OnTxStart(env.GetVMContext(), nil, common.Address{})
_, err := env.Interpreter().Run(contract, []byte{}, false)
if err != nil {
t.Fatal(err)
@@ -85,7 +85,7 @@ func TestStructLogMarshalingOmitEmpty(t *testing.T) {
}{
{"empty err and no fields", &StructLog{},
`{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memSize":0,"stack":null,"depth":0,"refund":0,"opName":"STOP"}`},
- {"with err", &StructLog{Err: fmt.Errorf("this failed")},
+ {"with err", &StructLog{Err: errors.New("this failed")},
`{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memSize":0,"stack":null,"depth":0,"refund":0,"opName":"STOP","error":"this failed"}`},
{"with mem", &StructLog{Memory: make([]byte, 2), MemorySize: 2},
`{"pc":0,"op":0,"gas":"0x0","gasCost":"0x0","memory":"0x0000","memSize":2,"stack":null,"depth":0,"refund":0,"opName":"STOP"}`},
diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go
index 85877a993..16c4c5f9c 100644
--- a/eth/tracers/native/4byte.go
+++ b/eth/tracers/native/4byte.go
@@ -23,8 +23,11 @@ import (
"sync/atomic"
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "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"
)
func init() {
@@ -46,20 +49,28 @@ func init() {
// 0xc281d19e-0: 1
// }
type fourByteTracer struct {
- noopTracer
- ids map[string]int // ids aggregates the 4byte ids found
- interrupt atomic.Bool // Atomic flag to signal execution interruption
- reason error // Textual reason for the interruption
- activePrecompiles []common.Address // Updated on CaptureStart based on given rules
+ ids map[string]int // ids aggregates the 4byte ids found
+ interrupt atomic.Bool // Atomic flag to signal execution interruption
+ reason error // Textual reason for the interruption
+ chainConfig *params.ChainConfig
+ activePrecompiles []common.Address // Updated on tx start based on given rules
}
// newFourByteTracer returns a native go tracer which collects
// 4 byte-identifiers of a tx, and implements vm.EVMLogger.
-func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) {
+func newFourByteTracer(ctx *tracers.Context, _ json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
t := &fourByteTracer{
- ids: make(map[string]int),
+ ids: make(map[string]int),
+ chainConfig: chainConfig,
}
- return t, nil
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnEnter: t.OnEnter,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
}
// isPrecompiled returns whether the addr is a precompile. Logic borrowed from newJsTracer in eth/tracers/js/tracer.go
@@ -78,20 +89,14 @@ func (t *fourByteTracer) store(id []byte, size int) {
t.ids[key] += 1
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *fourByteTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+func (t *fourByteTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
// Update list of precompiles based on current block
- rules := env.ChainConfig().Rules(env.Context.BlockNumber)
+ rules := t.chainConfig.Rules(env.BlockNumber)
t.activePrecompiles = vm.ActivePrecompiles(rules)
-
- // Save the outer calldata also
- if len(input) >= 4 {
- t.store(input[0:4], len(input)-4)
- }
}
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
+func (t *fourByteTracer) OnEnter(depth int, opcode byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, _ uint64) {
// Skip if tracing was interrupted
if t.interrupt.Load() {
return
@@ -99,6 +104,7 @@ func (t *fourByteTracer) CaptureEnter(op vm.OpCode, from common.Address, to comm
if len(input) < 4 {
return
}
+ op := vm.OpCode(opcode)
// primarily we want to avoid CREATE/CREATE2/SELFDESTRUCT
if op != vm.DELEGATECALL && op != vm.STATICCALL &&
op != vm.CALL && op != vm.CALLCODE {
diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go
index 8a424095e..afe92411b 100644
--- a/eth/tracers/native/call.go
+++ b/eth/tracers/native/call.go
@@ -25,8 +25,11 @@ 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/tracing"
+ "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"
)
//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go
@@ -39,6 +42,9 @@ type callLog struct {
Address common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data hexutil.Bytes `json:"data"`
+ // Position of the log relative to subcalls within the same trace
+ // See https://github.com/ethereum/go-ethereum/pull/28389 for details
+ Position hexutil.Uint `json:"position"`
}
type callFrame struct {
@@ -55,7 +61,8 @@ type callFrame struct {
Logs []callLog `json:"logs,omitempty" rlp:"optional"`
// Placed at end on purpose. The RLP will be decoded to 0 instead of
// nil if there are non-empty elements after in the struct.
- Value *big.Int `json:"value,omitempty" rlp:"optional"`
+ Value *big.Int `json:"value,omitempty" rlp:"optional"`
+ revertedSnapshot bool
}
func (f callFrame) TypeString() string {
@@ -63,16 +70,17 @@ func (f callFrame) TypeString() string {
}
func (f callFrame) failed() bool {
- return len(f.Error) > 0
+ return len(f.Error) > 0 && f.revertedSnapshot
}
-func (f *callFrame) processOutput(output []byte, err error) {
+func (f *callFrame) processOutput(output []byte, err error, reverted bool) {
output = common.CopyBytes(output)
if err == nil {
f.Output = output
return
}
f.Error = err.Error()
+ f.revertedSnapshot = reverted
if f.Type == vm.CREATE || f.Type == vm.CREATE2 {
f.To = nil
}
@@ -98,10 +106,10 @@ type callFrameMarshaling struct {
}
type callTracer struct {
- noopTracer
callstack []callFrame
config callTracerConfig
gasLimit uint64
+ depth int
interrupt atomic.Bool // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
}
@@ -113,50 +121,37 @@ type callTracerConfig struct {
// newCallTracer returns a native go tracer which tracks
// call frames of a tx, and implements vm.EVMLogger.
-func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
- var config callTracerConfig
- if cfg != nil {
- if err := json.Unmarshal(cfg, &config); err != nil {
- return nil, err
- }
+func newCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
+ t, err := newCallTracerObject(ctx, cfg)
+ if err != nil {
+ return nil, err
}
- // First callframe contains tx context info
- // and is populated on start and end.
- return &callTracer{callstack: make([]callFrame, 1), config: config}, nil
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnLog: t.OnLog,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *callTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- toCopy := to
- t.callstack[0] = callFrame{
- Type: vm.CALL,
- From: from,
- To: &toCopy,
- Input: common.CopyBytes(input),
- Gas: t.gasLimit,
- Value: value,
- }
- if create {
- t.callstack[0].Type = vm.CREATE
+func newCallTracerObject(ctx *tracers.Context, cfg json.RawMessage) (*callTracer, error) {
+ var config callTracerConfig
+ if err := json.Unmarshal(cfg, &config); err != nil {
+ return nil, err
}
+ // First callframe contains tx context info
+ // and is populated on start and end.
+ return &callTracer{callstack: make([]callFrame, 0, 1), config: config}, nil
}
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *callTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
- t.callstack[0].processOutput(output, err)
-}
-
-// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
-func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
- // skip if the previous op caused an error
- if err != nil {
- return
- }
- // Only logs need to be captured via opcode processing
- if !t.config.WithLog {
- return
- }
- // Avoid processing nested calls when only caring about top call
+// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
+func (t *callTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, _ uint64) {
+ t.depth = depth
if t.config.OnlyTopCall && depth > 0 {
return
}
@@ -164,87 +159,95 @@ func (t *callTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
if t.interrupt.Load() {
return
}
- switch op {
- case vm.LOG0, vm.LOG1, vm.LOG2, vm.LOG3, vm.LOG4:
- size := int(op - vm.LOG0)
-
- stack := scope.Stack
- stackData := stack.Data()
-
- // Don't modify the stack
- mStart := stackData[len(stackData)-1]
- mSize := stackData[len(stackData)-2]
- topics := make([]common.Hash, size)
- for i := 0; i < size; i++ {
- topic := stackData[len(stackData)-2-(i+1)]
- topics[i] = common.Hash(topic.Bytes32())
- }
-
- data, err := tracers.GetMemoryCopyPadded(scope.Memory, int64(mStart.Uint64()), int64(mSize.Uint64()))
- if err != nil {
- // mSize was unrealistically large
- return
- }
-
- log := callLog{Address: scope.Contract.Address(), Topics: topics, Data: hexutil.Bytes(data)}
- t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, log)
- }
-}
-
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
- if t.config.OnlyTopCall {
- return
- }
- // Skip if tracing was interrupted
- if t.interrupt.Load() {
- return
- }
toCopy := to
call := callFrame{
- Type: typ,
+ Type: vm.OpCode(typ),
From: from,
To: &toCopy,
Input: common.CopyBytes(input),
Gas: gas,
Value: value,
}
+ if depth == 0 {
+ call.Gas = t.gasLimit
+ }
t.callstack = append(t.callstack, call)
}
-// CaptureExit is called when EVM exits a scope, even if the scope didn't
+// OnExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
-func (t *callTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
+func (t *callTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth == 0 {
+ t.captureEnd(output, gasUsed, err, reverted)
+ return
+ }
+
+ t.depth = depth - 1
if t.config.OnlyTopCall {
return
}
+
size := len(t.callstack)
if size <= 1 {
return
}
- // pop call
+ // Pop call.
call := t.callstack[size-1]
t.callstack = t.callstack[:size-1]
size -= 1
call.GasUsed = gasUsed
- call.processOutput(output, err)
+ call.processOutput(output, err, reverted)
+ // Nest call into parent.
t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
}
-func (t *callTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {
- t.gasLimit = gasLimit
+func (t *callTracer) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
+ if len(t.callstack) != 1 {
+ return
+ }
+ t.callstack[0].processOutput(output, err, reverted)
+}
+
+func (t *callTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ t.gasLimit = tx.Gas()
}
-func (t *callTracer) CaptureTxEnd(restGas uint64) {
- t.callstack[0].GasUsed = t.gasLimit - restGas
+func (t *callTracer) OnTxEnd(receipt *types.Receipt, err error) {
+ // Error happened during tx validation.
+ if err != nil {
+ return
+ }
+ t.callstack[0].GasUsed = receipt.GasUsed
if t.config.WithLog {
// Logs are not emitted when the call fails
clearFailedLogs(&t.callstack[0], false)
}
}
+func (t *callTracer) OnLog(log *types.Log) {
+ // Only logs need to be captured via opcode processing
+ if !t.config.WithLog {
+ return
+ }
+ // Avoid processing nested calls when only caring about top call
+ if t.config.OnlyTopCall && t.depth > 0 {
+ return
+ }
+ // Skip if tracing was interrupted
+ if t.interrupt.Load() {
+ return
+ }
+ l := callLog{
+ Address: log.Address,
+ Topics: log.Topics,
+ Data: log.Data,
+ Position: hexutil.Uint(len(t.callstack[len(t.callstack)-1].Calls)),
+ }
+ t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, l)
+}
+
// GetResult returns the json-encoded nested list of call traces, and any
// error arising from the encoding or forceful termination (via `Stop`).
func (t *callTracer) GetResult() (json.RawMessage, error) {
@@ -256,7 +259,7 @@ func (t *callTracer) GetResult() (json.RawMessage, error) {
if err != nil {
return nil, err
}
- return json.RawMessage(res), t.reason
+ return res, t.reason
}
// Stop terminates execution of the tracer at the first opportune moment.
diff --git a/eth/tracers/native/call2.go b/eth/tracers/native/call2.go
index bde8a18d2..527e083b6 100644
--- a/eth/tracers/native/call2.go
+++ b/eth/tracers/native/call2.go
@@ -19,126 +19,236 @@ package native
import (
"encoding/json"
"errors"
+ "math/big"
+ "sync/atomic"
+
+ "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/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
- "math/big"
- "strconv"
- "strings"
- "sync/atomic"
+ "github.com/ethereum/go-ethereum/params"
)
+//go:generate go run github.com/fjl/gencodec -type callFrame2 -field-override callFrame2Marshaling -out gen_callframe2_json.go
+
func init() {
tracers.DefaultDirectory.Register("callTracer2", newCallTracer2, false)
}
+type callLog2 struct {
+ Address common.Address `json:"address"`
+ Topics []common.Hash `json:"topics"`
+ Data hexutil.Bytes `json:"data"`
+ // Position of the log relative to subcalls within the same trace
+ // See https://github.com/ethereum/go-ethereum/pull/28389 for details
+ Position hexutil.Uint `json:"position"`
+}
+
type callFrame2 struct {
- Type string `json:"type"`
- Order uint64 `json:"order"`
- From string `json:"from"`
- To string `json:"to,omitempty"`
- Value string `json:"value,omitempty"`
- Gas string `json:"gas"`
- GasUsed string `json:"gasUsed"`
- Input string `json:"input"`
- Output string `json:"output,omitempty"`
- Error string `json:"error,omitempty"`
- Calls []callFrame2 `json:"calls,omitempty"`
+ Type vm.OpCode `json:"-"`
+ Order uint64 `json:"order"`
+ From common.Address `json:"from"`
+ Gas uint64 `json:"gas"`
+ GasUsed uint64 `json:"gasUsed"`
+ To *common.Address `json:"to,omitempty" rlp:"optional"`
+ Input []byte `json:"input" rlp:"optional"`
+ Output []byte `json:"output,omitempty" rlp:"optional"`
+ Error string `json:"error,omitempty" rlp:"optional"`
+ RevertReason string `json:"revertReason,omitempty"`
+ Calls []callFrame2 `json:"calls,omitempty" rlp:"optional"`
+ Logs []callLog2 `json:"logs,omitempty" rlp:"optional"`
+ // Placed at end on purpose. The RLP will be decoded to 0 instead of
+ // nil if there are non-empty elements after in the struct.
+ Value *big.Int `json:"value,omitempty" rlp:"optional"`
+ revertedSnapshot bool
}
-type callTracer2 struct {
- noopTracer
- env *vm.EVM
- callstack []callFrame2
- interrupt uint32 // Atomic flag to signal execution interruption
- reason error // Textual reason for the interruption
+func (f callFrame2) TypeString() string {
+ return f.Type.String()
}
-// newCallTracer2 returns a native go tracer which tracks
-// call frames of a tx, and implements vm.EVMLogger.
-func newCallTracer2(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
- // First callframe contains tx context info
- // and is populated on start and end.
- t := &callTracer2{callstack: make([]callFrame2, 1)}
- return t, nil
+func (f callFrame2) failed() bool {
+ return len(f.Error) > 0 && f.revertedSnapshot
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *callTracer2) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- t.env = env
- t.callstack[0] = callFrame2{
- Type: "CALL",
- From: addrToHex(from),
- To: addrToHex(to),
- Input: bytesToHex(input),
- Gas: uintToHex(gas),
- Value: bigToHex(value),
+func (f *callFrame2) processOutput(output []byte, err error, reverted bool) {
+ output = common.CopyBytes(output)
+ if err == nil {
+ f.Output = output
+ return
+ }
+ f.Error = err.Error()
+ f.revertedSnapshot = reverted
+ if f.Type == vm.CREATE || f.Type == vm.CREATE2 {
+ f.To = nil
+ }
+ if !errors.Is(err, vm.ErrExecutionReverted) || len(output) == 0 {
+ return
+ }
+ f.Output = output
+ if len(output) < 4 {
+ return
}
- if create {
- t.callstack[0].Type = "CREATE"
+ if unpacked, err := abi.UnpackRevert(output); err == nil {
+ f.RevertReason = unpacked
}
}
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *callTracer2) CaptureEnd(output []byte, gasUsed uint64, err error) {
- t.callstack[0].GasUsed = uintToHex(gasUsed)
- if err != nil {
- t.callstack[0].Error = err.Error()
- t.callstack[0].Output = bytesToHex(output)
- } else {
- t.callstack[0].Output = bytesToHex(output)
- }
+type callFrame2Marshaling struct {
+ TypeString string `json:"type"`
+ Order uint64 `json:"order"`
+ Gas hexutil.Uint64
+ GasUsed hexutil.Uint64
+ Value *hexutil.Big
+ Input hexutil.Bytes
+ Output hexutil.Bytes
}
-// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
-func (t *callTracer2) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
+type callTracer2 struct {
+ callstack []callFrame2
+ config callTracer2Config
+ gasLimit uint64
+ depth int
+ interrupt atomic.Bool // Atomic flag to signal execution interruption
+ reason error // Textual reason for the interruption
+}
+
+type callTracer2Config struct {
+ OnlyTopCall bool `json:"onlyTopCall"` // If true, call tracer won't collect any subcalls
+ WithLog bool `json:"withLog"` // If true, call tracer will collect event logs
+}
+
+// newCallTracer returns a native go tracer which tracks
+// call frames of a tx, and implements vm.EVMLogger.
+func newCallTracer2(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
+ t, err := newCallTracer2Object(ctx, cfg)
+ if err != nil {
+ return nil, err
+ }
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnLog: t.OnLog,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
}
-// CaptureFault implements the EVMLogger interface to trace an execution fault.
-func (t *callTracer2) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
+func newCallTracer2Object(ctx *tracers.Context, cfg json.RawMessage) (*callTracer2, error) {
+ var config callTracer2Config
+ if err := json.Unmarshal(cfg, &config); err != nil {
+ return nil, err
+ }
+ // First callframe contains tx context info
+ // and is populated on start and end.
+ return &callTracer2{callstack: make([]callFrame2, 0, 1), config: config}, nil
}
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *callTracer2) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
+func (t *callTracer2) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64) {
+ t.depth = depth
+ if t.config.OnlyTopCall && depth > 0 {
+ return
+ }
// Skip if tracing was interrupted
- if atomic.LoadUint32(&t.interrupt) > 0 {
- t.env.Cancel()
+ if t.interrupt.Load() {
return
}
+ toCopy := to
call := callFrame2{
- Type: typ.String(),
- Order: t.env.Context.Counter,
- From: addrToHex(from),
- To: addrToHex(to),
- Input: bytesToHex(input),
- Gas: uintToHex(gas),
- Value: bigToHex(value),
+ Type: vm.OpCode(typ),
+ Order: order,
+ From: from,
+ To: &toCopy,
+ Input: common.CopyBytes(input),
+ Gas: gas,
+ Value: value,
+ }
+ if depth == 0 {
+ call.Gas = t.gasLimit
}
t.callstack = append(t.callstack, call)
}
-// CaptureExit is called when EVM exits a scope, even if the scope didn't
+// OnExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
-func (t *callTracer2) CaptureExit(output []byte, gasUsed uint64, err error) {
+func (t *callTracer2) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth == 0 {
+ t.captureEnd(output, gasUsed, err, reverted)
+ return
+ }
+
+ t.depth = depth - 1
+ if t.config.OnlyTopCall {
+ return
+ }
+
size := len(t.callstack)
if size <= 1 {
return
}
- // pop call
+ // Pop call.
call := t.callstack[size-1]
t.callstack = t.callstack[:size-1]
size -= 1
- call.GasUsed = uintToHex(gasUsed)
- call.Output = bytesToHex(output)
+ call.GasUsed = gasUsed
+ call.processOutput(output, err, reverted)
+ // Nest call into parent.
+ t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
+}
+
+func (t *callTracer2) captureEnd(output []byte, gasUsed uint64, err error, reverted bool) {
+ if len(t.callstack) != 1 {
+ return
+ }
+ t.callstack[0].processOutput(output, err, reverted)
+}
+
+func (t *callTracer2) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ t.gasLimit = tx.Gas()
+}
+
+func (t *callTracer2) OnTxEnd(receipt *types.Receipt, err error) {
+ // Error happened during tx validation.
if err != nil {
- call.Error = err.Error()
- if call.Type == "CREATE" || call.Type == "CREATE2" {
- call.To = ""
- }
+ return
}
- t.callstack[size-1].Calls = append(t.callstack[size-1].Calls, call)
+ t.callstack[0].GasUsed = receipt.GasUsed
+ if t.config.WithLog {
+ // Logs are not emitted when the call fails
+ clearFailedLogs2(&t.callstack[0], false)
+ }
+}
+
+func (t *callTracer2) OnLog(log *types.Log) {
+ // Only logs need to be captured via opcode processing
+ if !t.config.WithLog {
+ return
+ }
+ // Avoid processing nested calls when only caring about top call
+ if t.config.OnlyTopCall && t.depth > 0 {
+ return
+ }
+ // Skip if tracing was interrupted
+ if t.interrupt.Load() {
+ return
+ }
+ l := callLog2{
+ Address: log.Address,
+ Topics: log.Topics,
+ Data: log.Data,
+ Position: hexutil.Uint(len(t.callstack[len(t.callstack)-1].Calls)),
+ }
+ t.callstack[len(t.callstack)-1].Logs = append(t.callstack[len(t.callstack)-1].Logs, l)
}
// GetResult returns the json-encoded nested list of call traces, and any
@@ -147,30 +257,29 @@ func (t *callTracer2) GetResult() (json.RawMessage, error) {
if len(t.callstack) != 1 {
return nil, errors.New("incorrect number of top-level calls")
}
+
res, err := json.Marshal(t.callstack[0])
if err != nil {
return nil, err
}
- return json.RawMessage(res), t.reason
+ return res, t.reason
}
// Stop terminates execution of the tracer at the first opportune moment.
func (t *callTracer2) Stop(err error) {
t.reason = err
- atomic.StoreUint32(&t.interrupt, 1)
+ t.interrupt.Store(true)
}
-func bigToHex(n *big.Int) string {
- if n == nil {
- return ""
+// clearFailedLogs clears the logs of a callframe and all its children
+// in case of execution failure.
+func clearFailedLogs2(cf *callFrame2, parentFailed bool) {
+ failed := cf.failed() || parentFailed
+ // Clear own logs
+ if failed {
+ cf.Logs = nil
+ }
+ for i := range cf.Calls {
+ clearFailedLogs2(&cf.Calls[i], failed)
}
- return "0x" + n.Text(16)
-}
-
-func uintToHex(n uint64) string {
- return "0x" + strconv.FormatUint(n, 16)
-}
-
-func addrToHex(a common.Address) string {
- return strings.ToLower(a.Hex())
}
diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go
index ce5493c9c..388933ccd 100644
--- a/eth/tracers/native/call_flat.go
+++ b/eth/tracers/native/call_flat.go
@@ -25,8 +25,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "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"
)
//go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go
@@ -112,7 +115,8 @@ type flatCallTracer struct {
config flatCallTracerConfig
ctx *tracers.Context // Holds tracer context data
reason error // Textual reason for the interruption
- activePrecompiles []common.Address // Updated on CaptureStart based on given rules
+ chainConfig *params.ChainConfig
+ activePrecompiles []common.Address // Updated on tx start based on given rules
}
type flatCallTracerConfig struct {
@@ -121,55 +125,39 @@ type flatCallTracerConfig struct {
}
// newFlatCallTracer returns a new flatCallTracer.
-func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
var config flatCallTracerConfig
- if cfg != nil {
- if err := json.Unmarshal(cfg, &config); err != nil {
- return nil, err
- }
+ if err := json.Unmarshal(cfg, &config); err != nil {
+ return nil, err
}
// Create inner call tracer with default configuration, don't forward
// the OnlyTopCall or WithLog to inner for now
- tracer, err := tracers.DefaultDirectory.New("callTracer", ctx, nil)
+ t, err := newCallTracerObject(ctx, json.RawMessage("{}"))
if err != nil {
return nil, err
}
- t, ok := tracer.(*callTracer)
- if !ok {
- return nil, errors.New("internal error: embedded tracer has wrong type")
- }
-
- return &flatCallTracer{tracer: t, ctx: ctx, config: config}, nil
-}
-
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *flatCallTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- t.tracer.CaptureStart(env, from, to, create, input, gas, value)
- // Update list of precompiles based on current block
- rules := env.ChainConfig().Rules(env.Context.BlockNumber)
- t.activePrecompiles = vm.ActivePrecompiles(rules)
-}
-
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *flatCallTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
- t.tracer.CaptureEnd(output, gasUsed, err)
-}
-
-// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
-func (t *flatCallTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
- t.tracer.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
-}
-// CaptureFault implements the EVMLogger interface to trace an execution fault.
-func (t *flatCallTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
- t.tracer.CaptureFault(pc, op, gas, cost, scope, depth, err)
+ ft := &flatCallTracer{tracer: t, ctx: ctx, config: config, chainConfig: chainConfig}
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: ft.OnTxStart,
+ OnTxEnd: ft.OnTxEnd,
+ OnEnter: ft.OnEnter,
+ OnExit: ft.OnExit,
+ },
+ Stop: ft.Stop,
+ GetResult: ft.GetResult,
+ }, nil
}
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
- t.tracer.CaptureEnter(typ, from, to, input, gas, value)
+// OnEnter is called when EVM enters a new scope (via call, create or selfdestruct).
+func (t *flatCallTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64) {
+ t.tracer.OnEnter(depth, typ, from, to, input, gas, value, order)
+ if depth == 0 {
+ return
+ }
// Child calls must have a value, even if it's zero.
// Practically speaking, only STATICCALL has nil value. Set it to zero.
if t.tracer.callstack[len(t.tracer.callstack)-1].Value == nil && value == nil {
@@ -177,11 +165,14 @@ func (t *flatCallTracer) CaptureEnter(typ vm.OpCode, from common.Address, to com
}
}
-// CaptureExit is called when EVM exits a scope, even if the scope didn't
+// OnExit is called when EVM exits a scope, even if the scope didn't
// execute any code.
-func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
- t.tracer.CaptureExit(output, gasUsed, err)
+func (t *flatCallTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ t.tracer.OnExit(depth, output, gasUsed, err, reverted)
+ if depth == 0 {
+ return
+ }
// Parity traces don't include CALL/STATICCALLs to precompiles.
// By default we remove them from the callstack.
if t.config.IncludePrecompiles {
@@ -201,12 +192,15 @@ func (t *flatCallTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
}
}
-func (t *flatCallTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {
- t.tracer.CaptureTxStart(gasLimit, payer)
+func (t *flatCallTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ t.tracer.OnTxStart(env, tx, from)
+ // Update list of precompiles based on current block
+ rules := t.chainConfig.Rules(env.BlockNumber)
+ t.activePrecompiles = vm.ActivePrecompiles(rules)
}
-func (t *flatCallTracer) CaptureTxEnd(restGas uint64) {
- t.tracer.CaptureTxEnd(restGas)
+func (t *flatCallTracer) OnTxEnd(receipt *types.Receipt, err error) {
+ t.tracer.OnTxEnd(receipt, err)
}
// GetResult returns an empty json object.
@@ -248,7 +242,7 @@ func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx
case vm.CREATE, vm.CREATE2:
frame = newFlatCreate(input)
case vm.SELFDESTRUCT:
- frame = newFlatSuicide(input)
+ frame = newFlatSelfdestruct(input)
case vm.CALL, vm.STATICCALL, vm.CALLCODE, vm.DELEGATECALL:
frame = newFlatCall(input)
default:
@@ -330,7 +324,7 @@ func newFlatCall(input *callFrame) *flatCallFrame {
}
}
-func newFlatSuicide(input *callFrame) *flatCallFrame {
+func newFlatSelfdestruct(input *callFrame) *flatCallFrame {
return &flatCallFrame{
Type: "suicide",
Action: flatCallAction{
diff --git a/eth/tracers/native/gen_callframe2_json.go b/eth/tracers/native/gen_callframe2_json.go
new file mode 100644
index 000000000..136b8ffbb
--- /dev/null
+++ b/eth/tracers/native/gen_callframe2_json.go
@@ -0,0 +1,113 @@
+// Code generated by github.com/fjl/gencodec. DO NOT EDIT.
+
+package native
+
+import (
+ "encoding/json"
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/vm"
+)
+
+var _ = (*callFrame2Marshaling)(nil)
+
+// MarshalJSON marshals as JSON.
+func (c callFrame2) MarshalJSON() ([]byte, error) {
+ type callFrame20 struct {
+ Type vm.OpCode `json:"-"`
+ Order uint64 `json:"order"`
+ From common.Address `json:"from"`
+ Gas hexutil.Uint64 `json:"gas"`
+ GasUsed hexutil.Uint64 `json:"gasUsed"`
+ To *common.Address `json:"to,omitempty" rlp:"optional"`
+ Input hexutil.Bytes `json:"input" rlp:"optional"`
+ Output hexutil.Bytes `json:"output,omitempty" rlp:"optional"`
+ Error string `json:"error,omitempty" rlp:"optional"`
+ RevertReason string `json:"revertReason,omitempty"`
+ Calls []callFrame2 `json:"calls,omitempty" rlp:"optional"`
+ Logs []callLog2 `json:"logs,omitempty" rlp:"optional"`
+ Value *hexutil.Big `json:"value,omitempty" rlp:"optional"`
+ TypeString string `json:"type"`
+ }
+ var enc callFrame20
+ enc.Type = c.Type
+ enc.Order = c.Order
+ enc.From = c.From
+ enc.Gas = hexutil.Uint64(c.Gas)
+ enc.GasUsed = hexutil.Uint64(c.GasUsed)
+ enc.To = c.To
+ enc.Input = c.Input
+ enc.Output = c.Output
+ enc.Error = c.Error
+ enc.RevertReason = c.RevertReason
+ enc.Calls = c.Calls
+ enc.Logs = c.Logs
+ enc.Value = (*hexutil.Big)(c.Value)
+ enc.TypeString = c.TypeString()
+ return json.Marshal(&enc)
+}
+
+// UnmarshalJSON unmarshals from JSON.
+func (c *callFrame2) UnmarshalJSON(input []byte) error {
+ type callFrame20 struct {
+ Type *vm.OpCode `json:"-"`
+ Order *uint64 `json:"order"`
+ From *common.Address `json:"from"`
+ Gas *hexutil.Uint64 `json:"gas"`
+ GasUsed *hexutil.Uint64 `json:"gasUsed"`
+ To *common.Address `json:"to,omitempty" rlp:"optional"`
+ Input *hexutil.Bytes `json:"input" rlp:"optional"`
+ Output *hexutil.Bytes `json:"output,omitempty" rlp:"optional"`
+ Error *string `json:"error,omitempty" rlp:"optional"`
+ RevertReason *string `json:"revertReason,omitempty"`
+ Calls []callFrame2 `json:"calls,omitempty" rlp:"optional"`
+ Logs []callLog2 `json:"logs,omitempty" rlp:"optional"`
+ Value *hexutil.Big `json:"value,omitempty" rlp:"optional"`
+ }
+ var dec callFrame20
+ if err := json.Unmarshal(input, &dec); err != nil {
+ return err
+ }
+ if dec.Type != nil {
+ c.Type = *dec.Type
+ }
+ if dec.Order != nil {
+ c.Order = *dec.Order
+ }
+ if dec.From != nil {
+ c.From = *dec.From
+ }
+ if dec.Gas != nil {
+ c.Gas = uint64(*dec.Gas)
+ }
+ if dec.GasUsed != nil {
+ c.GasUsed = uint64(*dec.GasUsed)
+ }
+ if dec.To != nil {
+ c.To = dec.To
+ }
+ if dec.Input != nil {
+ c.Input = *dec.Input
+ }
+ if dec.Output != nil {
+ c.Output = *dec.Output
+ }
+ if dec.Error != nil {
+ c.Error = *dec.Error
+ }
+ if dec.RevertReason != nil {
+ c.RevertReason = *dec.RevertReason
+ }
+ if dec.Calls != nil {
+ c.Calls = dec.Calls
+ }
+ if dec.Logs != nil {
+ c.Logs = dec.Logs
+ }
+ if dec.Value != nil {
+ c.Value = (*big.Int)(dec.Value)
+ }
+ return nil
+}
diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go
index f4b0cc784..2d8d54ba6 100644
--- a/eth/tracers/native/mux.go
+++ b/eth/tracers/native/mux.go
@@ -21,8 +21,10 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/params"
)
func init() {
@@ -33,21 +35,19 @@ func init() {
// runs multiple tracers in one go.
type muxTracer struct {
names []string
- tracers []tracers.Tracer
+ tracers []*tracers.Tracer
}
// newMuxTracer returns a new mux tracer.
-func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
var config map[string]json.RawMessage
- if cfg != nil {
- if err := json.Unmarshal(cfg, &config); err != nil {
- return nil, err
- }
+ if err := json.Unmarshal(cfg, &config); err != nil {
+ return nil, err
}
- objects := make([]tracers.Tracer, 0, len(config))
+ objects := make([]*tracers.Tracer, 0, len(config))
names := make([]string, 0, len(config))
for k, v := range config {
- t, err := tracers.DefaultDirectory.New(k, ctx, v)
+ t, err := tracers.DefaultDirectory.New(k, ctx, v, chainConfig)
if err != nil {
return nil, err
}
@@ -55,61 +55,120 @@ func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, er
names = append(names, k)
}
- return &muxTracer{names: names, tracers: objects}, nil
+ t := &muxTracer{names: names, tracers: objects}
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnOpcode: t.OnOpcode,
+ OnFault: t.OnFault,
+ OnGasChange: t.OnGasChange,
+ OnBalanceChange: t.OnBalanceChange,
+ OnNonceChange: t.OnNonceChange,
+ OnCodeChange: t.OnCodeChange,
+ OnStorageChange: t.OnStorageChange,
+ OnLog: t.OnLog,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
+}
+
+func (t *muxTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
+ for _, t := range t.tracers {
+ if t.OnOpcode != nil {
+ t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
+ }
+ }
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *muxTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
for _, t := range t.tracers {
- t.CaptureStart(env, from, to, create, input, gas, value)
+ if t.OnFault != nil {
+ t.OnFault(pc, op, gas, cost, scope, depth, err)
+ }
}
}
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
+func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
for _, t := range t.tracers {
- t.CaptureEnd(output, gasUsed, err)
+ if t.OnGasChange != nil {
+ t.OnGasChange(old, new, reason)
+ }
}
}
-// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
-func (t *muxTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
+func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64) {
for _, t := range t.tracers {
- t.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
+ if t.OnEnter != nil {
+ t.OnEnter(depth, typ, from, to, input, gas, value, order)
+ }
}
}
-// CaptureFault implements the EVMLogger interface to trace an execution fault.
-func (t *muxTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
+func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
for _, t := range t.tracers {
- t.CaptureFault(pc, op, gas, cost, scope, depth, err)
+ if t.OnExit != nil {
+ t.OnExit(depth, output, gasUsed, err, reverted)
+ }
}
}
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *muxTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+func (t *muxTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
for _, t := range t.tracers {
- t.CaptureEnter(typ, from, to, input, gas, value)
+ if t.OnTxStart != nil {
+ t.OnTxStart(env, tx, from)
+ }
}
}
-// CaptureExit is called when EVM exits a scope, even if the scope didn't
-// execute any code.
-func (t *muxTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
+func (t *muxTracer) OnTxEnd(receipt *types.Receipt, err error) {
for _, t := range t.tracers {
- t.CaptureExit(output, gasUsed, err)
+ if t.OnTxEnd != nil {
+ t.OnTxEnd(receipt, err)
+ }
}
}
-func (t *muxTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {
+func (t *muxTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
for _, t := range t.tracers {
- t.CaptureTxStart(gasLimit, payer)
+ if t.OnBalanceChange != nil {
+ t.OnBalanceChange(a, prev, new, reason)
+ }
}
}
-func (t *muxTracer) CaptureTxEnd(restGas uint64) {
+func (t *muxTracer) OnNonceChange(a common.Address, prev, new uint64) {
for _, t := range t.tracers {
- t.CaptureTxEnd(restGas)
+ if t.OnNonceChange != nil {
+ t.OnNonceChange(a, prev, new)
+ }
+ }
+}
+
+func (t *muxTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
+ for _, t := range t.tracers {
+ if t.OnCodeChange != nil {
+ t.OnCodeChange(a, prevCodeHash, prev, codeHash, code)
+ }
+ }
+}
+
+func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {
+ for _, t := range t.tracers {
+ if t.OnStorageChange != nil {
+ t.OnStorageChange(a, k, prev, new)
+ }
+ }
+}
+
+func (t *muxTracer) OnLog(log *types.Log) {
+ for _, t := range t.tracers {
+ if t.OnLog != nil {
+ t.OnLog(log)
+ }
}
}
diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go
index 5fb431429..e87ebbda8 100644
--- a/eth/tracers/native/noop.go
+++ b/eth/tracers/native/noop.go
@@ -21,8 +21,10 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/params"
)
func init() {
@@ -34,38 +36,58 @@ func init() {
type noopTracer struct{}
// newNoopTracer returns a new noop tracer.
-func newNoopTracer(ctx *tracers.Context, _ json.RawMessage) (tracers.Tracer, error) {
- return &noopTracer{}, nil
+func newNoopTracer(ctx *tracers.Context, _ json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
+ t := &noopTracer{}
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnEnter: t.OnEnter,
+ OnExit: t.OnExit,
+ OnOpcode: t.OnOpcode,
+ OnFault: t.OnFault,
+ OnGasChange: t.OnGasChange,
+ OnBalanceChange: t.OnBalanceChange,
+ OnNonceChange: t.OnNonceChange,
+ OnCodeChange: t.OnCodeChange,
+ OnStorageChange: t.OnStorageChange,
+ OnLog: t.OnLog,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *noopTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
+func (t *noopTracer) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
}
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *noopTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
+func (t *noopTracer) OnFault(pc uint64, op byte, gas, cost uint64, _ tracing.OpContext, depth int, err error) {
}
-// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
-func (t *noopTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
+func (t *noopTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {}
+
+func (t *noopTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, _ uint64) {
}
-// CaptureFault implements the EVMLogger interface to trace an execution fault.
-func (t *noopTracer) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, _ *vm.ScopeContext, depth int, err error) {
+func (t *noopTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
}
-// CaptureEnter is called when EVM enters a new scope (via call, create or selfdestruct).
-func (t *noopTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+func (*noopTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
}
-// CaptureExit is called when EVM exits a scope, even if the scope didn't
-// execute any code.
-func (t *noopTracer) CaptureExit(output []byte, gasUsed uint64, err error) {
+func (*noopTracer) OnTxEnd(receipt *types.Receipt, err error) {}
+
+func (*noopTracer) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
+}
+
+func (*noopTracer) OnNonceChange(a common.Address, prev, new uint64) {}
+
+func (*noopTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
}
-func (*noopTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {}
+func (*noopTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {}
-func (*noopTracer) CaptureTxEnd(restGas uint64) {}
+func (*noopTracer) OnLog(log *types.Log) {}
// GetResult returns an empty json object.
func (t *noopTracer) GetResult() (json.RawMessage, error) {
diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go
index cbd669d17..a2861bfe0 100644
--- a/eth/tracers/native/prestate.go
+++ b/eth/tracers/native/prestate.go
@@ -24,9 +24,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "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/eth/tracers/internal"
+ "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)
@@ -36,13 +40,14 @@ func init() {
tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false)
}
-type state = map[common.Address]*account
+type stateMap = map[common.Address]*account
type account struct {
Balance *big.Int `json:"balance,omitempty"`
Code []byte `json:"code,omitempty"`
Nonce uint64 `json:"nonce,omitempty"`
Storage map[common.Hash]common.Hash `json:"storage,omitempty"`
+ empty bool
}
func (a *account) exists() bool {
@@ -55,110 +60,46 @@ type accountMarshaling struct {
}
type prestateTracer struct {
- noopTracer
- env *vm.EVM
- pre state
- post state
- create bool
+ env *tracing.VMContext
+ pre stateMap
+ post stateMap
to common.Address
- gasLimit uint64 // Amount of gas bought for the whole tx
config prestateTracerConfig
interrupt atomic.Bool // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption
created map[common.Address]bool
deleted map[common.Address]bool
- payer *common.Address // Pointer to payer address in sponsored transaction, nil otherwise
}
type prestateTracerConfig struct {
DiffMode bool `json:"diffMode"` // If true, this tracer will return state modifications
}
-func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+func newPrestateTracer(ctx *tracers.Context, cfg json.RawMessage, chainConfig *params.ChainConfig) (*tracers.Tracer, error) {
var config prestateTracerConfig
- if cfg != nil {
- if err := json.Unmarshal(cfg, &config); err != nil {
- return nil, err
- }
+ if err := json.Unmarshal(cfg, &config); err != nil {
+ return nil, err
}
- return &prestateTracer{
- pre: state{},
- post: state{},
+ t := &prestateTracer{
+ pre: stateMap{},
+ post: stateMap{},
config: config,
created: make(map[common.Address]bool),
deleted: make(map[common.Address]bool),
- }, nil
-}
-
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (t *prestateTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- t.env = env
- t.create = create
- t.to = to
-
- if t.payer != nil {
- t.lookupAccount(*t.payer)
- }
- t.lookupAccount(from)
- t.lookupAccount(to)
- t.lookupAccount(env.Context.Coinbase)
- treasury := env.ChainConfig().RoninTreasuryAddress
- if treasury != nil {
- t.lookupAccount(*treasury)
- }
-
- // The recipient balance includes the value transferred.
- toBal := new(big.Int).Sub(t.pre[to].Balance, value)
- t.pre[to].Balance = toBal
-
- // The sender/payer balance is after reducing: value and gasLimit.
- // We need to re-add them to get the pre-tx balance.
- fromBal := new(big.Int).Set(t.pre[from].Balance)
- gasPrice := env.TxContext.GasPrice
- consumedGas := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(t.gasLimit))
- diffFromBal := new(big.Int).Set(value)
- if t.payer != nil {
- t.pre[*t.payer].Balance = new(big.Int).Add(t.pre[*t.payer].Balance, consumedGas)
- } else {
- diffFromBal.Add(diffFromBal, consumedGas)
- }
- // At this time, the blob fee is already subtracted from sender and added to treasury.
- // So we need to add blob fee back to sender and subtract from treasury to get the correct
- // pre-tx balance.
- if len(env.BlobHashes) > 0 {
- blobFee := new(big.Int).Mul(big.NewInt(int64(len(env.BlobHashes)*params.BlobTxBlobGasPerBlob)), env.Context.BlobBaseFee)
- diffFromBal.Add(diffFromBal, blobFee)
- if treasury != nil {
- t.pre[*treasury].Balance = new(big.Int).Sub(t.pre[*treasury].Balance, blobFee)
- }
- }
-
- fromBal.Add(fromBal, diffFromBal)
- t.pre[from].Balance = fromBal
- t.pre[from].Nonce--
-
- if create && t.config.DiffMode {
- t.created[to] = true
- }
-}
-
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *prestateTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
- if t.config.DiffMode {
- return
- }
-
- if t.create {
- // Keep existing account prior to contract creation at that address
- if s := t.pre[t.to]; s != nil && !s.exists() {
- // Exclude newly created contract.
- delete(t.pre, t.to)
- }
}
+ return &tracers.Tracer{
+ Hooks: &tracing.Hooks{
+ OnTxStart: t.OnTxStart,
+ OnTxEnd: t.OnTxEnd,
+ OnOpcode: t.OnOpcode,
+ },
+ GetResult: t.GetResult,
+ Stop: t.Stop,
+ }, nil
}
-// CaptureState implements the EVMLogger interface to trace a single step of VM execution.
-func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
+// OnOpcode implements the EVMLogger interface to trace a single step of VM execution.
+func (t *prestateTracer) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
if err != nil {
return
}
@@ -166,10 +107,10 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
if t.interrupt.Load() {
return
}
- stack := scope.Stack
- stackData := stack.Data()
+ op := vm.OpCode(opcode)
+ stackData := scope.StackData()
stackLen := len(stackData)
- caller := scope.Contract.Address()
+ caller := scope.Address()
switch {
case stackLen >= 1 && (op == vm.SLOAD || op == vm.SSTORE):
slot := common.Hash(stackData[stackLen-1].Bytes32())
@@ -191,7 +132,11 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
case stackLen >= 4 && op == vm.CREATE2:
offset := stackData[stackLen-2]
size := stackData[stackLen-3]
- init := scope.Memory.GetCopy(int64(offset.Uint64()), int64(size.Uint64()))
+ init, err := internal.GetMemoryCopyPadded(scope.MemoryData(), int64(offset.Uint64()), int64(size.Uint64()))
+ if err != nil {
+ log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "prestateTracer", "offset", offset, "size", size)
+ return
+ }
inithash := crypto.Keccak256(init)
salt := stackData[stackLen-4]
addr := crypto.CreateAddress2(caller, salt.Bytes32(), inithash)
@@ -200,16 +145,62 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
}
}
-func (t *prestateTracer) CaptureTxStart(gasLimit uint64, payer *common.Address) {
- t.gasLimit = gasLimit
- t.payer = payer
+func (t *prestateTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
+ t.env = env
+ if tx.To() == nil {
+ t.to = crypto.CreateAddress(from, env.StateDB.GetNonce(from))
+ t.created[t.to] = true
+ } else {
+ t.to = *tx.To()
+ }
+
+ t.lookupAccount(from)
+ t.lookupAccount(t.to)
+ t.lookupAccount(env.Coinbase)
}
-func (t *prestateTracer) CaptureTxEnd(restGas uint64) {
- if !t.config.DiffMode {
+func (t *prestateTracer) OnTxEnd(receipt *types.Receipt, err error) {
+ if err != nil {
return
}
+ if t.config.DiffMode {
+ t.processDiffState()
+ }
+ // the new created contracts' prestate were empty, so delete them
+ for a := range t.created {
+ // the created contract maybe exists in statedb before the creating tx
+ if s := t.pre[a]; s != nil && s.empty {
+ delete(t.pre, a)
+ }
+ }
+}
+
+// GetResult returns the json-encoded nested list of call traces, and any
+// error arising from the encoding or forceful termination (via `Stop`).
+func (t *prestateTracer) GetResult() (json.RawMessage, error) {
+ var res []byte
+ var err error
+ if t.config.DiffMode {
+ res, err = json.Marshal(struct {
+ Post stateMap `json:"post"`
+ Pre stateMap `json:"pre"`
+ }{t.post, t.pre})
+ } else {
+ res, err = json.Marshal(t.pre)
+ }
+ if err != nil {
+ return nil, err
+ }
+ return json.RawMessage(res), t.reason
+}
+// Stop terminates execution of the tracer at the first opportune moment.
+func (t *prestateTracer) Stop(err error) {
+ t.reason = err
+ t.interrupt.Store(true)
+}
+
+func (t *prestateTracer) processDiffState() {
for addr, state := range t.pre {
// The deleted account's state is pruned from `post` but kept in `pre`
if _, ok := t.deleted[addr]; ok {
@@ -259,38 +250,6 @@ func (t *prestateTracer) CaptureTxEnd(restGas uint64) {
delete(t.pre, addr)
}
}
- // the new created contracts' prestate were empty, so delete them
- for a := range t.created {
- // the created contract maybe exists in statedb before the creating tx
- if s := t.pre[a]; s != nil && !s.exists() {
- delete(t.pre, a)
- }
- }
-}
-
-// GetResult returns the json-encoded nested list of call traces, and any
-// error arising from the encoding or forceful termination (via `Stop`).
-func (t *prestateTracer) GetResult() (json.RawMessage, error) {
- var res []byte
- var err error
- if t.config.DiffMode {
- res, err = json.Marshal(struct {
- Post state `json:"post"`
- Pre state `json:"pre"`
- }{t.post, t.pre})
- } else {
- res, err = json.Marshal(t.pre)
- }
- if err != nil {
- return nil, err
- }
- return json.RawMessage(res), t.reason
-}
-
-// Stop terminates execution of the tracer at the first opportune moment.
-func (t *prestateTracer) Stop(err error) {
- t.reason = err
- t.interrupt.Store(true)
}
// lookupAccount fetches details of an account and adds it to the prestate
@@ -300,12 +259,16 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
return
}
- t.pre[addr] = &account{
+ acc := &account{
Balance: t.env.StateDB.GetBalance(addr),
Nonce: t.env.StateDB.GetNonce(addr),
Code: t.env.StateDB.GetCode(addr),
Storage: make(map[common.Hash]common.Hash),
}
+ if !acc.exists() {
+ acc.empty = true
+ }
+ t.pre[addr] = acc
}
// lookupStorage fetches the requested storage slot and adds
diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go
index fe71d58b1..1671f7fe2 100644
--- a/eth/tracers/tracers_test.go
+++ b/eth/tracers/tracers_test.go
@@ -85,12 +85,12 @@ func BenchmarkTransactionTrace(b *testing.B) {
// Create the tracer, the EVM environment and run it
tracer := logger.NewStructLogger(&logger.Config{
Debug: false,
- //DisableStorage: true,
- //EnableMemory: false,
- //EnableReturnData: false,
+ // DisableStorage: true,
+ // EnableMemory: false,
+ // EnableReturnData: false,
})
- evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer})
- msg, err := tx.AsMessage(signer, nil)
+ evm := vm.NewEVM(context, txContext, statedb, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()})
+ msg, err := core.TransactionToMessage(tx, signer, nil)
if err != nil {
b.Fatalf("failed to prepare transaction for tracing: %v", err)
}
@@ -111,41 +111,3 @@ func BenchmarkTransactionTrace(b *testing.B) {
tracer.Reset()
}
}
-
-func TestMemCopying(t *testing.T) {
- for i, tc := range []struct {
- memsize int64
- offset int64
- size int64
- wantErr string
- wantSize int
- }{
- {0, 0, 100, "", 100}, // Should pad up to 100
- {0, 100, 0, "", 0}, // No need to pad (0 size)
- {100, 50, 100, "", 100}, // Should pad 100-150
- {100, 50, 5, "", 5}, // Wanted range fully within memory
- {100, -50, 0, "offset or size must not be negative", 0}, // Errror
- {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Errror
- {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Errror
-
- } {
- mem := vm.NewMemory()
- mem.Resize(uint64(tc.memsize))
- cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size)
- if want := tc.wantErr; want != "" {
- if err == nil {
- t.Fatalf("test %d: want '%v' have no error", i, want)
- }
- if have := err.Error(); want != have {
- t.Fatalf("test %d: want '%v' have '%v'", i, want, have)
- }
- continue
- }
- if err != nil {
- t.Fatalf("test %d: unexpected error: %v", i, err)
- }
- if want, have := tc.wantSize, len(cpy); have != want {
- t.Fatalf("test %d: want %v have %v", i, want, have)
- }
- }
-}
diff --git a/ethclient/gethclient/gethclient.go b/ethclient/gethclient/gethclient.go
index e343a2257..c9360b32b 100644
--- a/ethclient/gethclient/gethclient.go
+++ b/ethclient/gethclient/gethclient.go
@@ -80,7 +80,6 @@ type StorageResult struct {
// GetProof returns the account and storage values of the specified account including the Merkle-proof.
// The block number can be nil, in which case the value is taken from the latest known block.
func (ec *Client) GetProof(ctx context.Context, account common.Address, keys []string, blockNumber *big.Int) (*AccountResult, error) {
-
type storageResult struct {
Key string `json:"key"`
Value *hexutil.Big `json:"value"`
@@ -298,9 +297,9 @@ func (o BlockOverrides) MarshalJSON() ([]byte, error) {
Difficulty *hexutil.Big `json:"difficulty,omitempty"`
Time hexutil.Uint64 `json:"time,omitempty"`
GasLimit hexutil.Uint64 `json:"gasLimit,omitempty"`
- Coinbase *common.Address `json:"coinbase,omitempty"`
- Random *common.Hash `json:"random,omitempty"`
- BaseFee *hexutil.Big `json:"baseFee,omitempty"`
+ Coinbase *common.Address `json:"feeRecipient,omitempty"`
+ Random *common.Hash `json:"prevRandao,omitempty"`
+ BaseFee *hexutil.Big `json:"baseFeePerGas,omitempty"`
}
output := override{
diff --git a/ethclient/gethclient/gethclient_test.go b/ethclient/gethclient/gethclient_test.go
index 888fa2c9a..e8ba862f0 100644
--- a/ethclient/gethclient/gethclient_test.go
+++ b/ethclient/gethclient/gethclient_test.go
@@ -382,7 +382,7 @@ func TestBlockOverridesMarshal(t *testing.T) {
bo: BlockOverrides{
Coinbase: common.HexToAddress("0x1111111111111111111111111111111111111111"),
},
- want: `{"coinbase":"0x1111111111111111111111111111111111111111"}`,
+ want: `{"feeRecipient":"0x1111111111111111111111111111111111111111"}`,
},
{
bo: BlockOverrides{
@@ -392,7 +392,7 @@ func TestBlockOverridesMarshal(t *testing.T) {
GasLimit: 4,
BaseFee: big.NewInt(5),
},
- want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFee":"0x5"}`,
+ want: `{"number":"0x1","difficulty":"0x2","time":"0x3","gasLimit":"0x4","baseFeePerGas":"0x5"}`,
},
} {
marshalled, err := json.Marshal(&tt.bo)
diff --git a/go.mod b/go.mod
index cb714569c..618d2acef 100644
--- a/go.mod
+++ b/go.mod
@@ -135,6 +135,7 @@ require (
golang.org/x/mod v0.17.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/term v0.27.0 // indirect
+ gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
rsc.io/tmplfunc v0.0.3 // indirect
diff --git a/go.sum b/go.sum
index 10786af98..8871f8dd2 100644
--- a/go.sum
+++ b/go.sum
@@ -1225,6 +1225,8 @@ gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
+gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce h1:+JknDZhAj8YMt7GC73Ei8pv4MzjDUNPHgQWJdtMAaDU=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go
index 29b7adfbe..6bdd0c186 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -20,12 +20,13 @@ import (
"context"
"errors"
"fmt"
+ "maps"
+ gomath "math"
"math/big"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/ethereum/go-ethereum/accounts"
- "github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/accounts/scwallet"
"github.com/ethereum/go-ethereum/common"
@@ -37,6 +38,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/core"
"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/vm"
"github.com/ethereum/go-ethereum/crypto"
@@ -249,7 +251,7 @@ func (s *PublicTxPoolAPI) Inspect() map[string]map[string]map[string]string {
pending, queue := s.b.TxPoolContent()
// Define a formatter to flatten a transaction into a string
- var format = func(tx *types.Transaction) string {
+ format := func(tx *types.Transaction) string {
if to := tx.To(); to != nil {
return fmt.Sprintf("%s: %v wei + %v gas × %v wei", tx.To().Hex(), tx.Value(), tx.Gas(), tx.GasPrice())
}
@@ -787,14 +789,14 @@ func (s *PublicBlockChainAPI) GetHeaderByHash(ctx context.Context, hash common.H
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.BlockByNumber(ctx, number)
if block != nil && err == nil {
- response, err := s.rpcMarshalBlock(ctx, block, true, fullTx)
- if err == nil && number == rpc.PendingBlockNumber {
+ response := s.rpcMarshalBlock(ctx, block, true, fullTx)
+ if number == rpc.PendingBlockNumber {
// Pending blocks need to nil out a few fields
for _, field := range []string{"hash", "nonce", "miner"} {
response[field] = nil
}
}
- return response, err
+ return response, nil
}
return nil, err
}
@@ -804,7 +806,7 @@ func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, number rpc.B
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, hash common.Hash, fullTx bool) (map[string]interface{}, error) {
block, err := s.b.BlockByHash(ctx, hash)
if block != nil {
- return s.rpcMarshalBlock(ctx, block, true, fullTx)
+ return s.rpcMarshalBlock(ctx, block, true, fullTx), nil
}
return nil, err
}
@@ -820,7 +822,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockNumberAndIndex(ctx context.Context,
return nil, nil
}
block = types.NewBlockWithHeader(uncles[index])
- return s.rpcMarshalBlock(ctx, block, false, false)
+ return s.rpcMarshalBlock(ctx, block, false, false), nil
}
return nil, err
}
@@ -836,7 +838,7 @@ func (s *PublicBlockChainAPI) GetUncleByBlockHashAndIndex(ctx context.Context, b
return nil, nil
}
block = types.NewBlockWithHeader(uncles[index])
- return s.rpcMarshalBlock(ctx, block, false, false)
+ return s.rpcMarshalBlock(ctx, block, false, false), nil
}
return nil, err
}
@@ -916,22 +918,56 @@ func (s *PublicBlockChainAPI) GetBlockReceipts(ctx context.Context, blockNrOrHas
// if statDiff is set, all diff will be applied first and then execute the call
// message.
type OverrideAccount struct {
- Nonce *hexutil.Uint64 `json:"nonce"`
- Code *hexutil.Bytes `json:"code"`
- Balance **hexutil.Big `json:"balance"`
- State *map[common.Hash]common.Hash `json:"state"`
- StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
+ Nonce *hexutil.Uint64 `json:"nonce"`
+ Code *hexutil.Bytes `json:"code"`
+ Balance **hexutil.Big `json:"balance"`
+ State *map[common.Hash]common.Hash `json:"state"`
+ StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
+ MovePrecompileTo *common.Address `json:"movePrecompileToAddress"`
}
// StateOverride is the collection of overridden accounts.
type StateOverride map[common.Address]OverrideAccount
+func (diff *StateOverride) has(address common.Address) bool {
+ _, ok := (*diff)[address]
+ return ok
+}
+
// Apply overrides the fields of specified accounts into the given state.
-func (diff *StateOverride) Apply(state *state.StateDB) error {
+func (diff *StateOverride) Apply(state *state.StateDB, precompiles vm.PrecompiledContracts) error {
if diff == nil {
return nil
}
+ // Tracks destinations of precompiles that were moved.
+ dirtyAddrs := make(map[common.Address]struct{})
+
for addr, account := range *diff {
+ // If a precompile was moved to this address already, it can't be overridden.
+ if _, ok := dirtyAddrs[addr]; ok {
+ return fmt.Errorf("account %s has already been overridden by a precompile", addr.Hex())
+ }
+ p, isPrecompile := precompiles[addr]
+ // The MoveTo feature makes it possible to move a precompile
+ // code to another address. If the target address is another precompile
+ // the code for the latter is lost for this session.
+ // Note the destination account is not cleared upon move.
+ if account.MovePrecompileTo != nil {
+ if !isPrecompile {
+ return fmt.Errorf("account %s is not a precompile", addr.Hex())
+ }
+ // Refuse to move a precompile to an address that has been
+ // or will be overridden.
+ if diff.has(*account.MovePrecompileTo) {
+ return fmt.Errorf("account %s is already overridden", account.MovePrecompileTo.Hex())
+ }
+ precompiles[*account.MovePrecompileTo] = p
+ dirtyAddrs[*account.MovePrecompileTo] = struct{}{}
+ }
+ if isPrecompile {
+ delete(precompiles, addr)
+ }
+
// Override account nonce.
if account.Nonce != nil {
state.SetNonce(addr, uint64(*account.Nonce))
@@ -942,7 +978,7 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
}
// Override account balance.
if account.Balance != nil {
- state.SetBalance(addr, (*big.Int)(*account.Balance))
+ state.SetBalance(addr, (*big.Int)(*account.Balance), tracing.BalanceChangeUnspecified)
}
if account.State != nil && account.StateDiff != nil {
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
@@ -963,13 +999,13 @@ func (diff *StateOverride) Apply(state *state.StateDB) error {
// BlockOverrides is a set of header fields to override.
type BlockOverrides struct {
- Number *hexutil.Big
- Difficulty *hexutil.Big
- Time *hexutil.Uint64
- GasLimit *hexutil.Uint64
- Coinbase *common.Address
- Random *common.Hash
- BaseFee *hexutil.Big
+ Number *hexutil.Big
+ Difficulty *hexutil.Big // No-op if we're simulating post-merge calls.
+ Time *hexutil.Uint64
+ GasLimit *hexutil.Uint64
+ FeeRecipient *common.Address
+ PrevRandao *common.Hash
+ BaseFeePerGas *hexutil.Big
}
// Apply overrides the given header fields into the given block context.
@@ -989,12 +1025,41 @@ func (diff *BlockOverrides) Apply(blockCtx *vm.BlockContext) {
if diff.GasLimit != nil {
blockCtx.GasLimit = uint64(*diff.GasLimit)
}
- if diff.Coinbase != nil {
- blockCtx.Coinbase = *diff.Coinbase
+ if diff.FeeRecipient != nil {
+ blockCtx.Coinbase = *diff.FeeRecipient
+ }
+ if diff.BaseFeePerGas != nil {
+ blockCtx.BaseFee = diff.BaseFeePerGas.ToInt()
+ }
+}
+
+func (diff *BlockOverrides) MakeHeader(header *types.Header) *types.Header {
+ if diff == nil {
+ return header
+ }
+ h := types.CopyHeader(header)
+ if diff.Number != nil {
+ h.Number = diff.Number.ToInt()
+ }
+ if diff.Difficulty != nil {
+ h.Difficulty = diff.Difficulty.ToInt()
+ }
+ if diff.Time != nil {
+ h.Time = uint64(*diff.Time)
+ }
+ if diff.GasLimit != nil {
+ h.GasLimit = uint64(*diff.GasLimit)
+ }
+ if diff.FeeRecipient != nil {
+ h.Coinbase = *diff.FeeRecipient
+ }
+ if diff.PrevRandao != nil {
+ h.MixDigest = *diff.PrevRandao
}
- if diff.BaseFee != nil {
- blockCtx.BaseFee = diff.BaseFee.ToInt()
+ if diff.BaseFeePerGas != nil {
+ h.BaseFee = diff.BaseFeePerGas.ToInt()
}
+ return h
}
// ChainContextBackend provides methods required to implement ChainContext.
@@ -1040,7 +1105,13 @@ func doCall(
timeout time.Duration,
globalGasCap uint64,
) (*core.ExecutionResult, error) {
- if err := overrides.Apply(state); err != nil {
+ blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
+ if blockOverrides != nil {
+ blockOverrides.Apply(&blockCtx)
+ }
+ rules := b.ChainConfig().Rules(blockCtx.BlockNumber)
+ precompiles := maps.Clone(vm.ActivePrecompiledContracts(rules))
+ if err := overrides.Apply(state, precompiles); err != nil {
return nil, err
}
// Setup context so it may be cancelled the call has completed
@@ -1054,20 +1125,82 @@ func doCall(
// Make sure the context is cancelled when the call has completed
// this makes sure resources are cleaned up.
defer cancel()
-
+ gp := new(core.GasPool)
+ if globalGasCap == 0 {
+ gp.AddGas(math.MaxUint64)
+ } else {
+ gp.AddGas(globalGasCap)
+ }
+
+ return applyMessage(
+ ctx,
+ b,
+ args,
+ state,
+ header,
+ timeout,
+ gp,
+ globalGasCap,
+ &blockCtx,
+ &vm.Config{NoBaseFee: true},
+ precompiles,
+ true,
+ )
+}
+
+func applyMessage(
+ ctx context.Context,
+ b Backend,
+ args TransactionArgs,
+ state *state.StateDB,
+ header *types.Header,
+ timeout time.Duration,
+ gp *core.GasPool,
+ globalGasCap uint64,
+ blockContext *vm.BlockContext,
+ vmConfig *vm.Config,
+ precompiles vm.PrecompiledContracts,
+ skipChecks bool,
+) (*core.ExecutionResult, error) {
// Get a new instance of the EVM.
- msg, err := args.ToMessage(globalGasCap, header.BaseFee)
+ if err := args.CallDefaults(gp.Gas(), blockContext.BaseFee, b.ChainConfig().ChainID); err != nil {
+ return nil, err
+ }
+ msg := args.ToMessage(globalGasCap, header.BaseFee, skipChecks)
+ // Lower the basefee to 0 to avoid breaking EVM
+ // invariants (basefee < feecap).
+ if msg.GasPrice.Sign() == 0 {
+ blockContext.BaseFee = new(big.Int)
+ }
+ if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
+ blockContext.BlobBaseFee = new(big.Int)
+ }
+ evm, vmError, err := b.GetEVM(ctx, msg, state, header, vmConfig, blockContext)
if err != nil {
return nil, err
}
- blockCtx := core.NewEVMBlockContext(header, NewChainContext(ctx, b), nil)
- if blockOverrides != nil {
- blockOverrides.Apply(&blockCtx)
+ if precompiles != nil {
+ evm.SetPrecompiles(precompiles)
}
- evm, vmError, err := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx)
+
+ res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp)
if err != nil {
return nil, err
}
+
+ if err := vmError(); err != nil {
+ return nil, err
+ }
+ return res, nil
+}
+
+func applyMessageWithEVM(
+ ctx context.Context,
+ evm *vm.EVM,
+ msg *core.Message,
+ timeout time.Duration,
+ gp *core.GasPool,
+) (*core.ExecutionResult, error) {
// Wait for the context to be done and cancel the evm. Even if the
// EVM has finished, cancelling may be done (repeatedly)
go func() {
@@ -1076,18 +1209,13 @@ func doCall(
}()
// Execute the message.
- gp := new(core.GasPool).AddGas(math.MaxUint64)
result, err := core.ApplyMessage(evm, msg, gp)
- if err := vmError(); err != nil {
- return nil, err
- }
-
// If the timer caused an abort, return an appropriate error message
if evm.Cancelled() {
return nil, fmt.Errorf("execution aborted (timeout = %v)", timeout)
}
if err != nil {
- return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.Gas())
+ return result, fmt.Errorf("err: %w (supplied gas %d)", err, msg.GasLimit)
}
return result, nil
}
@@ -1112,37 +1240,6 @@ func DoCall(
return doCall(ctx, b, args, state, header, overrides, blockOverrides, timeout, globalGasCap)
}
-func newRevertError(revert []byte) *revertError {
- err := vm.ErrExecutionReverted
-
- reason, errUnpack := abi.UnpackRevert(revert)
- if errUnpack == nil {
- err = fmt.Errorf("%w: %v", vm.ErrExecutionReverted, reason)
- }
- return &revertError{
- error: err,
- reason: hexutil.Encode(revert),
- }
-}
-
-// revertError is an API error that encompassas an EVM revertal with JSON error
-// code and a binary data blob.
-type revertError struct {
- error
- reason string // revert reason hex encoded
-}
-
-// ErrorCode returns the JSON error code for a revertal.
-// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
-func (e *revertError) ErrorCode() int {
- return 3
-}
-
-// ErrorData returns the hex encoded revert reason.
-func (e *revertError) ErrorData() interface{} {
- return e.reason
-}
-
// Call executes the given transaction on the state for the given block number.
//
// Additionally, the caller can specify a batch of contract for fields overriding.
@@ -1161,6 +1258,46 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args TransactionArgs, bl
return result.Return(), result.Err
}
+// SimulateV1 executes series of transactions on top of a base state.
+// The transactions are packed into blocks. For each block, block header
+// fields can be overridden. The state can also be overridden prior to
+// execution of each block.
+//
+// Note, this function doesn't make any changes in the state/blockchain and is
+// useful to execute and retrieve values.
+func (api *PublicBlockChainAPI) SimulateV1(ctx context.Context, opts simOpts, blockNrOrHash *rpc.BlockNumberOrHash) ([]*simBlockResult, error) {
+ if len(opts.BlockStateCalls) == 0 {
+ return nil, &invalidParamsError{message: "empty input"}
+ } else if len(opts.BlockStateCalls) > maxSimulateBlocks {
+ return nil, &clientLimitExceededError{message: "too many blocks"}
+ }
+ if blockNrOrHash == nil {
+ n := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
+ blockNrOrHash = &n
+ }
+ state, base, err := api.b.StateAndHeaderByNumberOrHash(ctx, *blockNrOrHash)
+ if state == nil || err != nil {
+ return nil, err
+ }
+ gasCap := api.b.RPCGasCap()
+ if gasCap == 0 {
+ gasCap = gomath.MaxUint64
+ }
+ sim := &simulator{
+ b: api.b,
+ state: state,
+ base: base,
+ chainConfig: api.b.ChainConfig(),
+ gasCap: api.b.RPCGasCap(),
+ // Each tx and all the series of txes shouldn't consume more gas than cap
+ gp: new(core.GasPool).AddGas(gasCap),
+ traceTransfers: opts.TraceTransfers,
+ validate: opts.Validation,
+ fullTx: opts.ReturnFullTransactions,
+ }
+ return sim.execute(ctx, opts.BlockStateCalls)
+}
+
// DoEstimateGas returns the lowest possible gas limit that allows the transaction to run
// successfully at block `blockNrOrHash`. It returns error if the transaction would revert, or if
// there are unexpected failures. The gas limit is capped by both `args.Gas` (if non-nil &
@@ -1171,7 +1308,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
if state == nil || err != nil {
return 0, err
}
- if err = overrides.Apply(state); err != nil {
+ if err = overrides.Apply(state, nil); err != nil {
return 0, err
}
// Construct the gas estimator option from the user input
@@ -1183,10 +1320,7 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
ErrorRatio: estimateGasErrorRatio,
}
// Run the gas estimation andwrap any revertals into a custom return
- call, err := args.ToMessage(gasCap, header.BaseFee)
- if err != nil {
- return 0, err
- }
+ call := args.ToMessage(gasCap, header.BaseFee, true)
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
if err != nil {
if len(revert) > 0 {
@@ -1310,26 +1444,23 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} {
// RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
// transaction hashes.
-func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) (map[string]interface{}, error) {
+func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *params.ChainConfig) map[string]interface{} {
fields := RPCMarshalHeader(block.Header())
fields["size"] = hexutil.Uint64(block.Size())
if inclTx {
- formatTx := func(tx *types.Transaction) (interface{}, error) {
- return tx.Hash(), nil
+ formatTx := func(idx int, tx *types.Transaction) interface{} {
+ return tx.Hash()
}
if fullTx {
- formatTx = func(tx *types.Transaction) (interface{}, error) {
- return newRPCTransactionFromBlockHash(block, tx.Hash(), config), nil
+ formatTx = func(idx int, tx *types.Transaction) interface{} {
+ return newRPCTransactionFromBlockIndex(block, uint64(idx), config)
}
}
txs := block.Transactions()
transactions := make([]interface{}, len(txs))
- var err error
for i, tx := range txs {
- if transactions[i], err = formatTx(tx); err != nil {
- return nil, err
- }
+ transactions[i] = formatTx(i, tx)
}
fields["transactions"] = transactions
}
@@ -1339,8 +1470,7 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param
uncleHashes[i] = uncle.Hash()
}
fields["uncles"] = uncleHashes
-
- return fields, nil
+ return fields
}
// rpcMarshalHeader uses the generalized output filler, then adds the total difficulty field, which requires
@@ -1353,15 +1483,12 @@ func (s *PublicBlockChainAPI) rpcMarshalHeader(ctx context.Context, header *type
// rpcMarshalBlock uses the generalized output filler, then adds the total difficulty field, which requires
// a `PublicBlockchainAPI`.
-func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
- fields, err := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig())
- if err != nil {
- return nil, err
- }
+func (s *PublicBlockChainAPI) rpcMarshalBlock(ctx context.Context, b *types.Block, inclTx bool, fullTx bool) map[string]interface{} {
+ fields := RPCMarshalBlock(b, inclTx, fullTx, s.b.ChainConfig())
if inclTx {
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(ctx, b.Hash()))
}
- return fields, err
+ return fields
}
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
@@ -1650,29 +1777,27 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
statedb := db.Copy()
// Set the accesslist to the last al
args.AccessList = &accessList
- msg, err := args.ToMessage(b.RPCGasCap(), header.BaseFee)
- if err != nil {
- return nil, 0, nil, err
- }
+ msg := args.ToMessage(b.RPCGasCap(), header.BaseFee, true)
// Apply the transaction with the access list tracer
tracer := logger.NewAccessListTracer(accessList, addressesToExclude)
- config := vm.Config{Tracer: tracer, Debug: true, NoBaseFee: true}
+ config := vm.Config{Tracer: tracer.Hooks(), Debug: true, NoBaseFee: true}
vmenv, _, err := b.GetEVM(ctx, msg, statedb, header, &config, nil)
+ if err != nil {
+ return nil, 0, nil, err
+ }
+
// Lower the basefee to 0 to avoid breaking EVM
// invariants (basefee < feecap).
- if msg.GasPrice().Sign() == 0 {
+ if msg.GasPrice.Sign() == 0 {
vmenv.Context.BaseFee = new(big.Int)
}
- if msg.BlobGasFeeCap() != nil && msg.BlobGasFeeCap().BitLen() == 0 {
+ if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
vmenv.Context.BlobBaseFee = new(big.Int)
}
- if err != nil {
- return nil, 0, nil, err
- }
- res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.Gas()))
+ res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
if err != nil {
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.toTransaction().Hash(), err)
}
@@ -2120,11 +2245,11 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs Transact
matchTx := sendArgs.toTransaction()
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
- var price = matchTx.GasPrice()
+ price := matchTx.GasPrice()
if gasPrice != nil {
price = gasPrice.ToInt()
}
- var gas = matchTx.Gas()
+ gas := matchTx.Gas()
if gasLimit != nil {
gas = uint64(*gasLimit)
}
diff --git a/internal/ethapi/api_test.go b/internal/ethapi/api_test.go
index a940d547a..938c9ca40 100644
--- a/internal/ethapi/api_test.go
+++ b/internal/ethapi/api_test.go
@@ -26,6 +26,7 @@ import (
"fmt"
"math/big"
"reflect"
+ "strings"
"testing"
"time"
@@ -34,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
@@ -566,7 +568,7 @@ func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return big.NewInt(1)
}
-func (b testBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error, error) {
+func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error, error) {
vmError := func() error { return nil }
if vmConfig == nil {
vmConfig = b.chain.GetVMConfig()
@@ -815,7 +817,7 @@ func TestCall(t *testing.T) {
Balance: big.NewInt(params.Ether),
Nonce: 1,
Storage: map[common.Hash]common.Hash{
- common.Hash{}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"),
+ {}: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000001"),
},
},
},
@@ -1030,6 +1032,1338 @@ func TestCall(t *testing.T) {
}
}
+func TestSimulateV1(t *testing.T) {
+ t.Parallel()
+
+ var (
+ accounts = newAccounts(3)
+ fixedAccount = newTestAccount()
+ genBlocks = 10
+ signer = types.HomesteadSigner{}
+ cac = common.HexToAddress("0x0000000000000000000000000000000000000cac")
+ bab = common.HexToAddress("0x0000000000000000000000000000000000000bab")
+ coinbase = "0x000000000000000000000000000000000000ffff"
+ genesis = &core.Genesis{
+ Config: params.TestChainConfig,
+ Alloc: types.GenesisAlloc{
+ accounts[0].addr: {Balance: big.NewInt(params.Ether)},
+ accounts[1].addr: {Balance: big.NewInt(params.Ether)},
+ accounts[2].addr: {Balance: big.NewInt(params.Ether)},
+ // Yul:
+ // object "Test" {
+ // code {
+ // let dad := 0x0000000000000000000000000000000000000dad
+ // selfdestruct(dad)
+ // }
+ // }
+ cac: {Balance: big.NewInt(params.Ether), Code: common.Hex2Bytes("610dad80ff")},
+ bab: {
+ Balance: big.NewInt(1),
+ // object "Test" {
+ // code {
+ // let value1 := sload(1)
+ // let value2 := sload(2)
+ //
+ // // Shift value1 by 128 bits to the left by multiplying it with 2^128
+ // value1 := mul(value1, 0x100000000000000000000000000000000)
+ //
+ // // Concatenate value1 and value2
+ // let concatenatedValue := add(value1, value2)
+ //
+ // // Store the result in memory and return it
+ // mstore(0, concatenatedValue)
+ // return(0, 0x20)
+ // }
+ // }
+ Code: common.FromHex("0x600154600254700100000000000000000000000000000000820291508082018060005260206000f3"),
+ Storage: map[common.Hash]common.Hash{
+ common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(10)),
+ common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(12)),
+ },
+ },
+ },
+ }
+ sha256Address = common.BytesToAddress([]byte{0x02})
+ )
+
+ // Enable Venoki hardfork to enable basefee
+ genesis.Config.VenokiBlock = big.NewInt(0)
+
+ api := NewPublicBlockChainAPI(newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) {
+ b.SetCoinbase(common.HexToAddress(coinbase))
+ // Transfer from account[0] to account[1]
+ // value: 1000 wei
+ // fee: 0 wei
+ 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)
+ }))
+
+ var (
+ randomAccounts = newAccounts(4)
+ latest = rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
+ includeTransfers = true
+ validation = true
+ )
+ type log struct {
+ Address common.Address `json:"address"`
+ Topics []common.Hash `json:"topics"`
+ Data hexutil.Bytes `json:"data"`
+ BlockNumber hexutil.Uint64 `json:"blockNumber"`
+ // Skip txHash
+ // TxHash common.Hash `json:"transactionHash" gencodec:"required"`
+ TxIndex hexutil.Uint `json:"transactionIndex"`
+ // BlockHash common.Hash `json:"blockHash"`
+ Index hexutil.Uint `json:"logIndex"`
+ }
+ type callErr struct {
+ Message string
+ Code int
+ }
+ type callRes struct {
+ ReturnValue string `json:"returnData"`
+ Error callErr
+ Logs []log
+ GasUsed string
+ Status string
+ }
+ type blockRes struct {
+ Number string
+ // Hash string
+ // Ignore timestamp
+ GasLimit string
+ GasUsed string
+ Miner string
+ BaseFeePerGas string
+ Calls []callRes
+ }
+ testSuite := []struct {
+ name string
+ blocks []simBlock
+ tag rpc.BlockNumberOrHash
+ includeTransfers *bool
+ validation *bool
+ expectErr error
+ want []blockRes
+ skip bool
+ }{
+ // State build-up over calls:
+ // First value transfer OK after state
+ // Second one should succeed because of first transfer.
+ {
+ name: "simple",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(1000))},
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[1].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ }, {
+ From: &randomAccounts[1].addr,
+ To: &randomAccounts[2].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ }, {
+ To: &randomAccounts[3].addr,
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xf618",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ {
+ // State build-up over blocks.
+ name: "simple-multi-block",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(2000))},
+ },
+ Calls: []TransactionArgs{
+ {
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[1].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ }, {
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[3].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ },
+ },
+ }, {
+ StateOverrides: &StateOverride{
+ randomAccounts[3].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
+ },
+ Calls: []TransactionArgs{
+ {
+ From: &randomAccounts[1].addr,
+ To: &randomAccounts[2].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ },
+ },
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xa410",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xc",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x5208",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ {
+ // insufficient funds
+ name: "insufficient-funds",
+ tag: latest,
+ blocks: []simBlock{{
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[1].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ }},
+ }},
+ want: nil,
+ expectErr: &invalidTxError{Message: fmt.Sprintf("err: insufficient funds for gas * price + value: address %s have 0 want 1000 (supplied gas 4712388)", randomAccounts[0].addr.String()), Code: errCodeInsufficientFunds},
+ },
+ {
+ // EVM error
+ name: "evm-error",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: OverrideAccount{Code: hex2Bytes("f3")},
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr,
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x47e7c4",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ Error: callErr{Message: "stack underflow (0 <=> 2)", Code: errCodeVMError},
+ GasUsed: "0x47e7c4",
+ Logs: []log{},
+ Status: "0x0",
+ }},
+ }},
+ },
+ {
+ // Block overrides should work, each call is simulated on a different block number
+ name: "block-overrides",
+ tag: latest,
+ blocks: []simBlock{{
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(big.NewInt(11)),
+ FeeRecipient: &cac,
+ },
+ Calls: []TransactionArgs{
+ {
+ From: &accounts[0].addr,
+ Input: &hexutil.Bytes{
+ 0x43, // NUMBER
+ 0x60, 0x00, 0x52, // MSTORE offset 0
+ 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN
+ },
+ },
+ },
+ }, {
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(big.NewInt(12)),
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[1].addr,
+ Input: &hexutil.Bytes{
+ 0x43, // NUMBER
+ 0x60, 0x00, 0x52, // MSTORE offset 0
+ 0x60, 0x20, 0x60, 0x00, 0xf3,
+ },
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xe891",
+ Miner: strings.ToLower(cac.String()),
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000b",
+ GasUsed: "0xe891",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xc",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xe891",
+ Miner: strings.ToLower(cac.String()),
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x000000000000000000000000000000000000000000000000000000000000000c",
+ GasUsed: "0xe891",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Block numbers must be in order.
+ {
+ name: "block-number-order",
+ tag: latest,
+ blocks: []simBlock{{
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(big.NewInt(12)),
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[1].addr,
+ Input: &hexutil.Bytes{
+ 0x43, // NUMBER
+ 0x60, 0x00, 0x52, // MSTORE offset 0
+ 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN
+ },
+ }},
+ }, {
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(big.NewInt(11)),
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ Input: &hexutil.Bytes{
+ 0x43, // NUMBER
+ 0x60, 0x00, 0x52, // MSTORE offset 0
+ 0x60, 0x20, 0x60, 0x00, 0xf3, // RETURN
+ },
+ }},
+ }},
+ want: []blockRes{},
+ expectErr: &invalidBlockNumberError{message: "block numbers must be in order: 11 <= 12"},
+ },
+ // Test on solidity storage example. Set value in one call, read in next.
+ {
+ name: "storage-contract",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: OverrideAccount{
+ Code: hex2Bytes("608060405234801561001057600080fd5b50600436106100365760003560e01c80632e64cec11461003b5780636057361d14610059575b600080fd5b610043610075565b60405161005091906100d9565b60405180910390f35b610073600480360381019061006e919061009d565b61007e565b005b60008054905090565b8060008190555050565b60008135905061009781610103565b92915050565b6000602082840312156100b3576100b26100fe565b5b60006100c184828501610088565b91505092915050565b6100d3816100f4565b82525050565b60006020820190506100ee60008301846100ca565b92915050565b6000819050919050565b600080fd5b61010c816100f4565b811461011757600080fd5b5056fea2646970667358221220404e37f487a89a932dca5e77faaf6ca2de3b991f93d230604b1b8daaef64766264736f6c63430008070033"),
+ },
+ },
+ Calls: []TransactionArgs{
+ {
+ // Set value to 5
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr,
+ Input: hex2Bytes("6057361d0000000000000000000000000000000000000000000000000000000000000005"),
+ }, {
+ // Read value
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr,
+ Input: hex2Bytes("2e64cec1"),
+ },
+ },
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x10683",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0xaacc",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000005",
+ GasUsed: "0x5bb7",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Test logs output.
+ {
+ name: "logs",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: OverrideAccount{
+ // Yul code:
+ // object "Test" {
+ // code {
+ // let hash:u256 := 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
+ // log1(0, 0, hash)
+ // return (0, 0)
+ // }
+ // }
+ Code: hex2Bytes("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80600080a1600080f3"),
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr,
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x5508",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ Logs: []log{{
+ Address: randomAccounts[2].addr,
+ Topics: []common.Hash{common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")},
+ BlockNumber: hexutil.Uint64(11),
+ Data: hexutil.Bytes{},
+ }},
+ GasUsed: "0x5508",
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Test ecrecover override
+ {
+ name: "ecrecover-override",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: OverrideAccount{
+ // Yul code that returns ecrecover(0, 0, 0, 0).
+ // object "Test" {
+ // code {
+ // // Free memory pointer
+ // let free_ptr := mload(0x40)
+ //
+ // // Initialize inputs with zeros
+ // mstore(free_ptr, 0) // Hash
+ // mstore(add(free_ptr, 0x20), 0) // v
+ // mstore(add(free_ptr, 0x40), 0) // r
+ // mstore(add(free_ptr, 0x60), 0) // s
+ //
+ // // Call ecrecover precompile (at address 1) with all 0 inputs
+ // let success := staticcall(gas(), 1, free_ptr, 0x80, free_ptr, 0x20)
+ //
+ // // Check if the call was successful
+ // if eq(success, 0) {
+ // revert(0, 0)
+ // }
+ //
+ // // Return the recovered address
+ // return(free_ptr, 0x14)
+ // }
+ // }
+ Code: hex2Bytes("6040516000815260006020820152600060408201526000606082015260208160808360015afa60008103603157600080fd5b601482f3"),
+ },
+ common.BytesToAddress([]byte{0x01}): OverrideAccount{
+ // Yul code that returns the address of the caller.
+ // object "Test" {
+ // code {
+ // let c := caller()
+ // mstore(0, c)
+ // return(0xc, 0x14)
+ // }
+ // }
+ Code: hex2Bytes("33806000526014600cf3"),
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr,
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x52f6",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ // Caller is in this case the contract that invokes ecrecover.
+ ReturnValue: strings.ToLower(randomAccounts[2].addr.String()),
+ GasUsed: "0x52f6",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Test moving the sha256 precompile.
+ {
+ name: "precompile-move",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ sha256Address: OverrideAccount{
+ // Yul code that returns the calldata.
+ // object "Test" {
+ // code {
+ // let size := calldatasize() // Get the size of the calldata
+ //
+ // // Allocate memory to store the calldata
+ // let memPtr := msize()
+ //
+ // // Copy calldata to memory
+ // calldatacopy(memPtr, 0, size)
+ //
+ // // Return the calldata from memory
+ // return(memPtr, size)
+ // }
+ // }
+ Code: hex2Bytes("365981600082378181f3"),
+ MovePrecompileTo: &randomAccounts[2].addr,
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[2].addr,
+ Input: hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"),
+ }, {
+ From: &randomAccounts[0].addr,
+ To: &sha256Address,
+ Input: hex2Bytes("0000000000000000000000000000000000000000000000000000000000000001"),
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xa6cc",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0xec4916dd28fc4c10d78e287ca5d9cc51ee1ae73cbfde08c6b37324cbfaac8bc5",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x0000000000000000000000000000000000000000000000000000000000000001",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Test ether transfers.
+ {
+ name: "transfer-logs",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[0].addr: OverrideAccount{
+ Balance: newRPCBalance(big.NewInt(100)),
+ // Yul code that transfers 100 wei to address passed in calldata:
+ // object "Test" {
+ // code {
+ // let recipient := shr(96, calldataload(0))
+ // let value := 100
+ // let success := call(gas(), recipient, value, 0, 0, 0, 0)
+ // if eq(success, 0) {
+ // revert(0, 0)
+ // }
+ // }
+ // }
+ Code: hex2Bytes("60003560601c606460008060008084865af160008103601d57600080fd5b505050"),
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[0].addr,
+ Value: (*hexutil.Big)(big.NewInt(50)),
+ Input: hex2Bytes(strings.TrimPrefix(fixedAccount.addr.String(), "0x")),
+ }},
+ }},
+ includeTransfers: &includeTransfers,
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xd984",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0xd984",
+ Logs: []log{{
+ Address: transferAddress,
+ Topics: []common.Hash{
+ transferTopic,
+ addressToHash(accounts[0].addr),
+ addressToHash(randomAccounts[0].addr),
+ },
+ Data: hexutil.Bytes(common.BigToHash(big.NewInt(50)).Bytes()),
+ BlockNumber: hexutil.Uint64(11),
+ }, {
+ Address: transferAddress,
+ Topics: []common.Hash{
+ transferTopic,
+ addressToHash(randomAccounts[0].addr),
+ addressToHash(fixedAccount.addr),
+ },
+ Data: hexutil.Bytes(common.BigToHash(big.NewInt(100)).Bytes()),
+ BlockNumber: hexutil.Uint64(11),
+ Index: hexutil.Uint(1),
+ }},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Tests selfdestructed contract.
+ {
+ name: "selfdestruct",
+ tag: latest,
+ blocks: []simBlock{{
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &cac,
+ }, {
+ From: &accounts[0].addr,
+ // Check that cac is selfdestructed and balance transferred to dad.
+ // object "Test" {
+ // code {
+ // let cac := 0x0000000000000000000000000000000000000cac
+ // let dad := 0x0000000000000000000000000000000000000dad
+ // if gt(balance(cac), 0) {
+ // revert(0, 0)
+ // }
+ // if eq(extcodesize(cac), 0) { // After EIP-6780, code not be deleted
+ // revert(0, 0)
+ // }
+ // if eq(balance(dad), 0) {
+ // revert(0, 0)
+ // }
+ // }
+ // }
+ Input: hex2Bytes("610cac610dad905f8131116025575f903b146021575f903114601d57005b5f80fd5b5f80fd5b5f80fd"),
+ }},
+ }, {
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ Input: hex2Bytes("610cac610dad905f8131116025575f903b146021575f903114601d57005b5f80fd5b5f80fd5b5f80fd"),
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x1b7ee",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0xd166",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0xe688",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xc",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xe688",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0xe688",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Enable validation checks.
+ {
+ name: "validation-checks",
+ tag: latest,
+ blocks: []simBlock{{
+ Calls: []TransactionArgs{{
+ From: &accounts[2].addr,
+ To: &cac,
+ Nonce: newUint64(2),
+ MaxFeePerGas: newInt(1000000000),
+ }},
+ }},
+ validation: &validation,
+ want: nil,
+ expectErr: &invalidTxError{Message: fmt.Sprintf("err: nonce too high: address %s, tx: 2 state: 0 (supplied gas 4712388)", accounts[2].addr), Code: errCodeNonceTooHigh},
+ },
+ // Contract sends tx in validation mode.
+ {
+ name: "validation-checks-from-contract",
+ tag: latest,
+ skip: true, // This require eip-7702 enabled to pass
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: OverrideAccount{
+ Balance: newRPCBalance(big.NewInt(4712388000000000)),
+ Code: hex2Bytes("00"),
+ Nonce: newUint64(1),
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[2].addr,
+ To: &cac,
+ Nonce: newUint64(1),
+ MaxFeePerGas: newInt(1000000000),
+ MaxPriorityFeePerGas: newInt(1),
+ }},
+ }},
+ validation: &validation,
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xd166",
+ Miner: coinbase,
+ BaseFeePerGas: "0x3b9aca00",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0xd166",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Successful validation
+ {
+ name: "validation-checks-success",
+ tag: latest,
+ blocks: []simBlock{{
+ BlockOverrides: &BlockOverrides{
+ BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)),
+ },
+ StateOverrides: &StateOverride{
+ randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(10000000))},
+ },
+ Calls: []TransactionArgs{{
+ From: &randomAccounts[0].addr,
+ To: &randomAccounts[1].addr,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ MaxFeePerGas: (*hexutil.Big)(big.NewInt(2)),
+ }},
+ }},
+ validation: &validation,
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x5208",
+ Miner: coinbase,
+ BaseFeePerGas: "0x1",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0x5208",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ // Clear storage.
+ {
+ name: "clear-storage",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: {
+ Code: newBytes(genesis.Alloc[bab].Code),
+ StateDiff: &map[common.Hash]common.Hash{
+ common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(2)),
+ common.BigToHash(big.NewInt(2)): common.BigToHash(big.NewInt(3)),
+ },
+ },
+ bab: {
+ State: &map[common.Hash]common.Hash{
+ common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(1)),
+ },
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ }, {
+ From: &accounts[0].addr,
+ To: &bab,
+ }},
+ }, {
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: {
+ State: &map[common.Hash]common.Hash{
+ common.BigToHash(big.NewInt(1)): common.BigToHash(big.NewInt(5)),
+ },
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xc542",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x0000000000000000000000000000000200000000000000000000000000000003",
+ GasUsed: "0x62a1",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x0000000000000000000000000000000100000000000000000000000000000000",
+ GasUsed: "0x62a1",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xc",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x62a1",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x0000000000000000000000000000000500000000000000000000000000000000",
+ GasUsed: "0x62a1",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ {
+ name: "blockhash-opcode",
+ tag: latest,
+ blocks: []simBlock{{
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(big.NewInt(12)),
+ },
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: {
+ Code: hex2Bytes("600035804060008103601057600080fd5b5050"),
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // Phantom block after base.
+ Input: uint256ToBytes(uint256.NewInt(11)),
+ }, {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // Canonical block.
+ Input: uint256ToBytes(uint256.NewInt(8)),
+ }, {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // base block.
+ Input: uint256ToBytes(uint256.NewInt(10)),
+ }},
+ }, {
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(big.NewInt(16)),
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // blocks[0]
+ Input: uint256ToBytes(uint256.NewInt(12)),
+ }, {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // Phantom after blocks[0]
+ Input: uint256ToBytes(uint256.NewInt(13)),
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x0",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{},
+ }, {
+ Number: "0xc",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xfa32",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xd",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x0",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{},
+ }, {
+ Number: "0xe",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x0",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{},
+ }, {
+ Number: "0xf",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x0",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{},
+ }, {
+ Number: "0x10",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xa6cc",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x",
+ GasUsed: "0x5366",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ {
+ name: "basefee-non-validation",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: {
+ // Yul code:
+ // object "Test" {
+ // code {
+ // // Get the gas price from the transaction
+ // let gasPrice := gasprice()
+ //
+ // // Get the base fee from the block
+ // let baseFee := basefee()
+ //
+ // // Store gasPrice and baseFee in memory
+ // mstore(0x0, gasPrice)
+ // mstore(0x20, baseFee)
+ //
+ // // Return the data
+ // return(0x0, 0x40)
+ // }
+ // }
+ Code: hex2Bytes("3a489060005260205260406000f3"),
+ },
+ },
+ Calls: []TransactionArgs{
+ {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // 0 gas price
+ }, {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // non-zero gas price
+ MaxPriorityFeePerGas: newInt(1),
+ MaxFeePerGas: newInt(2),
+ },
+ },
+ }, {
+ BlockOverrides: &BlockOverrides{
+ BaseFeePerGas: (*hexutil.Big)(big.NewInt(1)),
+ },
+ Calls: []TransactionArgs{
+ {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // 0 gas price
+ }, {
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ // non-zero gas price
+ MaxPriorityFeePerGas: newInt(1),
+ MaxFeePerGas: newInt(2),
+ },
+ },
+ }, {
+ // Base fee should be 0 to zero even if it was set in previous block.
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ }},
+ }},
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xa44e",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ GasUsed: "0x5227",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000",
+ GasUsed: "0x5227",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xc",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0xa44e",
+ Miner: coinbase,
+ BaseFeePerGas: "0x1",
+ Calls: []callRes{{
+ ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
+ GasUsed: "0x5227",
+ Logs: []log{},
+ Status: "0x1",
+ }, {
+ ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001",
+ GasUsed: "0x5227",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }, {
+ Number: "0xd",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x5227",
+ Miner: coinbase,
+ BaseFeePerGas: "0x0",
+ Calls: []callRes{{
+ ReturnValue: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ GasUsed: "0x5227",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ {
+ name: "basefee-validation-mode",
+ tag: latest,
+ blocks: []simBlock{{
+ StateOverrides: &StateOverride{
+ randomAccounts[2].addr: {
+ // Yul code:
+ // object "Test" {
+ // code {
+ // // Get the gas price from the transaction
+ // let gasPrice := gasprice()
+ //
+ // // Get the base fee from the block
+ // let baseFee := basefee()
+ //
+ // // Store gasPrice and baseFee in memory
+ // mstore(0x0, gasPrice)
+ // mstore(0x20, baseFee)
+ //
+ // // Return the data
+ // return(0x0, 0x40)
+ // }
+ // }
+ Code: hex2Bytes("3a489060005260205260406000f3"),
+ },
+ },
+ Calls: []TransactionArgs{{
+ From: &accounts[0].addr,
+ To: &randomAccounts[2].addr,
+ MaxFeePerGas: newInt(1000000000),
+ MaxPriorityFeePerGas: newInt(1),
+ }},
+ }},
+ validation: &validation,
+ want: []blockRes{{
+ Number: "0xb",
+ GasLimit: "0x47e7c4",
+ GasUsed: "0x5227",
+ Miner: coinbase,
+ BaseFeePerGas: "0x3b9aca00",
+ Calls: []callRes{{
+ ReturnValue: "0x000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000003b9aca00",
+ GasUsed: "0x5227",
+ Logs: []log{},
+ Status: "0x1",
+ }},
+ }},
+ },
+ }
+
+ for _, tc := range testSuite {
+ if tc.skip {
+ continue
+ }
+
+ t.Run(tc.name, func(t *testing.T) {
+ opts := simOpts{BlockStateCalls: tc.blocks}
+ if tc.includeTransfers != nil && *tc.includeTransfers {
+ opts.TraceTransfers = true
+ }
+ if tc.validation != nil && *tc.validation {
+ opts.Validation = true
+ }
+ result, err := api.SimulateV1(context.Background(), opts, &tc.tag)
+ if tc.expectErr != nil {
+ if err == nil {
+ t.Fatalf("test %s: want error %v, have nothing", tc.name, tc.expectErr)
+ }
+ if !errors.Is(err, tc.expectErr) {
+ // Second try
+ if !reflect.DeepEqual(err, tc.expectErr) {
+ t.Errorf("test %s: error mismatch, want %v, have %v", tc.name, tc.expectErr, err)
+ }
+ }
+ return
+ }
+ if err != nil {
+ t.Fatalf("test %s: want no error, have %v", tc.name, err)
+ }
+ // Turn result into res-struct
+ var have []blockRes
+ resBytes, _ := json.Marshal(result)
+ if err := json.Unmarshal(resBytes, &have); err != nil {
+ t.Fatalf("failed to unmarshal result: %v", err)
+ }
+ if !reflect.DeepEqual(have, tc.want) {
+ t.Log(string(resBytes))
+ t.Errorf("test %s, result mismatch, have\n%v\n, want\n%v\n", tc.name, have, tc.want)
+ }
+ })
+ }
+}
+
+func TestSimulateV1ChainLinkage(t *testing.T) {
+ var (
+ acc = newTestAccount()
+ sender = acc.addr
+ contractAddr = common.Address{0xaa, 0xaa}
+ recipient = common.Address{0xbb, 0xbb}
+ gspec = &core.Genesis{
+ Config: params.TestChainConfig,
+ Alloc: types.GenesisAlloc{
+ sender: {Balance: big.NewInt(params.Ether)},
+ contractAddr: {Code: common.Hex2Bytes("5f35405f8114600f575f5260205ff35b5f80fd")},
+ },
+ }
+ signer = types.LatestSigner(params.TestChainConfig)
+ )
+ backend := newTestBackend(t, 1, gspec, ethash.NewFaker(), func(i int, b *core.BlockGen) {
+ tx := types.MustSignNewTx(acc.key, signer, &types.LegacyTx{
+ Nonce: uint64(i),
+ GasPrice: b.BaseFee(),
+ Gas: params.TxGas,
+ To: &recipient,
+ Value: big.NewInt(500),
+ })
+ b.AddTx(tx)
+ })
+
+ ctx := context.Background()
+ stateDB, baseHeader, err := backend.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber))
+ if err != nil {
+ t.Fatalf("failed to get state and header: %v", err)
+ }
+
+ sim := &simulator{
+ b: backend,
+ state: stateDB,
+ base: baseHeader,
+ chainConfig: backend.ChainConfig(),
+ gp: new(core.GasPool).AddGas(math.MaxUint64),
+ traceTransfers: false,
+ validate: false,
+ fullTx: false,
+ }
+
+ var (
+ call1 = TransactionArgs{
+ From: &sender,
+ To: &recipient,
+ Value: (*hexutil.Big)(big.NewInt(1000)),
+ }
+ call2 = TransactionArgs{
+ From: &sender,
+ To: &recipient,
+ Value: (*hexutil.Big)(big.NewInt(2000)),
+ }
+ call3a = TransactionArgs{
+ From: &sender,
+ To: &contractAddr,
+ Input: uint256ToBytes(uint256.NewInt(baseHeader.Number.Uint64() + 1)),
+ Gas: newUint64(1000000),
+ }
+ call3b = TransactionArgs{
+ From: &sender,
+ To: &contractAddr,
+ Input: uint256ToBytes(uint256.NewInt(baseHeader.Number.Uint64() + 2)),
+ Gas: newUint64(1000000),
+ }
+ blocks = []simBlock{
+ {Calls: []TransactionArgs{call1}},
+ {Calls: []TransactionArgs{call2}},
+ {Calls: []TransactionArgs{call3a, call3b}},
+ }
+ )
+
+ results, err := sim.execute(ctx, blocks)
+ if err != nil {
+ t.Fatalf("simulation execution failed: %v", err)
+ }
+ require.Equal(t, 3, len(results), "expected 3 simulated blocks")
+
+ // Check linkages of simulated blocks:
+ // Verify that block2's parent hash equals block1's hash.
+ block1 := results[0].Block
+ block2 := results[1].Block
+ block3 := results[2].Block
+ require.Equal(t, block1.ParentHash(), baseHeader.Hash(), "parent hash of block1 should equal hash of base block")
+ require.Equal(t, block1.Hash(), block2.Header().ParentHash, "parent hash of block2 should equal hash of block1")
+ require.Equal(t, block2.Hash(), block3.Header().ParentHash, "parent hash of block3 should equal hash of block2")
+
+ // In block3, two calls were executed to our contract.
+ // The first call in block3 should return the blockhash for block1 (i.e. block1.Hash()),
+ // whereas the second call should return the blockhash for block2 (i.e. block2.Hash()).
+ require.Equal(t, block1.Hash().Bytes(), []byte(results[2].Calls[0].ReturnValue), "returned blockhash for block1 does not match")
+ require.Equal(t, block2.Hash().Bytes(), []byte(results[2].Calls[1].ReturnValue), "returned blockhash for block2 does not match")
+}
+
+func TestSimulateV1TxSender(t *testing.T) {
+ var (
+ sender = common.Address{0xaa, 0xaa}
+ sender2 = common.Address{0xaa, 0xab}
+ sender3 = common.Address{0xaa, 0xac}
+ recipient = common.Address{0xbb, 0xbb}
+ gspec = &core.Genesis{
+ Config: params.TestChainConfig,
+ Alloc: types.GenesisAlloc{
+ sender: {Balance: big.NewInt(params.Ether)},
+ sender2: {Balance: big.NewInt(params.Ether)},
+ sender3: {Balance: big.NewInt(params.Ether)},
+ },
+ }
+ ctx = context.Background()
+ )
+ backend := newTestBackend(t, 0, gspec, ethash.NewFaker(), func(i int, b *core.BlockGen) {})
+ stateDB, baseHeader, err := backend.StateAndHeaderByNumberOrHash(ctx, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber))
+ if err != nil {
+ t.Fatalf("failed to get state and header: %v", err)
+ }
+
+ sim := &simulator{
+ b: backend,
+ state: stateDB,
+ base: baseHeader,
+ chainConfig: backend.ChainConfig(),
+ gp: new(core.GasPool).AddGas(math.MaxUint64),
+ traceTransfers: false,
+ validate: false,
+ fullTx: true,
+ }
+
+ results, err := sim.execute(ctx, []simBlock{
+ {Calls: []TransactionArgs{
+ {From: &sender, To: &recipient, Value: (*hexutil.Big)(big.NewInt(1000))},
+ {From: &sender2, To: &recipient, Value: (*hexutil.Big)(big.NewInt(2000))},
+ {From: &sender3, To: &recipient, Value: (*hexutil.Big)(big.NewInt(3000))},
+ }},
+ {Calls: []TransactionArgs{
+ {From: &sender2, To: &recipient, Value: (*hexutil.Big)(big.NewInt(4000))},
+ }},
+ })
+ if err != nil {
+ t.Fatalf("simulation execution failed: %v", err)
+ }
+ require.Len(t, results, 2, "expected 2 simulated blocks")
+ require.Len(t, results[0].Block.Transactions(), 3, "expected 3 transaction in simulated block")
+ require.Len(t, results[1].Block.Transactions(), 1, "expected 1 transaction in 2nd simulated block")
+ enc, err := json.Marshal(results)
+ if err != nil {
+ t.Fatalf("failed to marshal results: %v", err)
+ }
+ type resultType struct {
+ Transactions []struct {
+ From common.Address `json:"from"`
+ }
+ }
+ var summary []resultType
+ if err := json.Unmarshal(enc, &summary); err != nil {
+ t.Fatalf("failed to unmarshal results: %v", err)
+ }
+ require.Len(t, summary, 2, "expected 2 simulated blocks")
+ require.Len(t, summary[0].Transactions, 3, "expected 3 transaction in simulated block")
+ require.Equal(t, sender, summary[0].Transactions[0].From, "sender address mismatch")
+ require.Equal(t, sender2, summary[0].Transactions[1].From, "sender address mismatch")
+ require.Equal(t, sender3, summary[0].Transactions[2].From, "sender address mismatch")
+ require.Len(t, summary[1].Transactions, 1, "expected 1 transaction in simulated block")
+ require.Equal(t, sender2, summary[1].Transactions[0].From, "sender address mismatch")
+}
+
type Account struct {
key *ecdsa.PrivateKey
addr common.Address
@@ -1045,11 +2379,24 @@ func newAccounts(n int) (accounts []Account) {
return accounts
}
+func newTestAccount() Account {
+ // testKey is a private key to use for funding a tester account.
+ key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
+ // testAddr is the Ethereum address of the tester account.
+ addr := crypto.PubkeyToAddress(key.PublicKey)
+ return Account{key: key, addr: addr}
+}
+
func newRPCBalance(balance *big.Int) **hexutil.Big {
rpcBalance := (*hexutil.Big)(balance)
return &rpcBalance
}
+func newUint64(v uint64) *hexutil.Uint64 {
+ rpcUint64 := hexutil.Uint64(v)
+ return &rpcUint64
+}
+
func hex2Bytes(str string) *hexutil.Bytes {
rpcBytes := hexutil.Bytes(common.Hex2Bytes(str))
return &rpcBytes
@@ -1401,3 +2748,18 @@ func newRPCBytes(bytes []byte) *hexutil.Bytes {
rpcBytes := hexutil.Bytes(bytes)
return &rpcBytes
}
+
+func uint256ToBytes(v *uint256.Int) *hexutil.Bytes {
+ b := v.Bytes32()
+ r := hexutil.Bytes(b[:])
+ return &r
+}
+
+func addressToHash(a common.Address) common.Hash {
+ return common.BytesToHash(a.Bytes())
+}
+
+func newBytes(b []byte) *hexutil.Bytes {
+ rpcBytes := hexutil.Bytes(b)
+ return &rpcBytes
+}
diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go
index 161f8f5e9..abaeae36b 100644
--- a/internal/ethapi/backend.go
+++ b/internal/ethapi/backend.go
@@ -68,7 +68,7 @@ type Backend interface {
StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error)
GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error)
GetTd(ctx context.Context, hash common.Hash) *big.Int
- GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error)
+ GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error)
SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription
@@ -112,36 +112,43 @@ func GetAPIs(apiBackend Backend) []rpc.API {
Version: "1.0",
Service: NewPublicEthereumAPI(apiBackend),
Public: true,
- }, {
+ },
+ {
Namespace: "eth",
Version: "1.0",
Service: NewPublicBlockChainAPI(apiBackend),
Public: true,
- }, {
+ },
+ {
Namespace: "eth",
Version: "1.0",
Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock),
Public: true,
- }, {
+ },
+ {
Namespace: "txpool",
Version: "1.0",
Service: NewPublicTxPoolAPI(apiBackend),
Public: true,
- }, {
+ },
+ {
Namespace: "debug",
Version: "1.0",
Service: NewPublicDebugAPI(apiBackend),
Public: true,
- }, {
+ },
+ {
Namespace: "debug",
Version: "1.0",
Service: NewPrivateDebugAPI(apiBackend),
- }, {
+ },
+ {
Namespace: "eth",
Version: "1.0",
Service: NewPublicAccountAPI(apiBackend.AccountManager()),
Public: true,
- }, {
+ },
+ {
Namespace: "personal",
Version: "1.0",
Service: NewPrivateAccountAPI(apiBackend, nonceLock),
diff --git a/internal/ethapi/errors.go b/internal/ethapi/errors.go
new file mode 100644
index 000000000..ae3806123
--- /dev/null
+++ b/internal/ethapi/errors.go
@@ -0,0 +1,170 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package ethapi
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/accounts/abi"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/vm"
+)
+
+// revertError is an API error that encompasses an EVM revert with JSON error
+// code and a binary data blob.
+type revertError struct {
+ error
+ reason string // revert reason hex encoded
+}
+
+// ErrorCode returns the JSON error code for a revert.
+// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
+func (e *revertError) ErrorCode() int {
+ return 3
+}
+
+// ErrorData returns the hex encoded revert reason.
+func (e *revertError) ErrorData() interface{} {
+ return e.reason
+}
+
+// newRevertError creates a revertError instance with the provided revert data.
+func newRevertError(revert []byte) *revertError {
+ err := vm.ErrExecutionReverted
+
+ reason, errUnpack := abi.UnpackRevert(revert)
+ if errUnpack == nil {
+ err = fmt.Errorf("%w: %v", vm.ErrExecutionReverted, reason)
+ }
+ return &revertError{
+ error: err,
+ reason: hexutil.Encode(revert),
+ }
+}
+
+// TxIndexingError is an API error that indicates the transaction indexing is not
+// fully finished yet with JSON error code and a binary data blob.
+type TxIndexingError struct{}
+
+// NewTxIndexingError creates a TxIndexingError instance.
+func NewTxIndexingError() *TxIndexingError { return &TxIndexingError{} }
+
+// Error implement error interface, returning the error message.
+func (e *TxIndexingError) Error() string {
+ return "transaction indexing is in progress"
+}
+
+// ErrorCode returns the JSON error code for a revert.
+// See: https://github.com/ethereum/wiki/wiki/JSON-RPC-Error-Codes-Improvement-Proposal
+func (e *TxIndexingError) ErrorCode() int {
+ return -32000 // to be decided
+}
+
+// ErrorData returns the hex encoded revert reason.
+func (e *TxIndexingError) ErrorData() interface{} { return "transaction indexing is in progress" }
+
+type callError struct {
+ Message string `json:"message"`
+ Code int `json:"code"`
+ Data string `json:"data,omitempty"`
+}
+
+type invalidTxError struct {
+ Message string `json:"message"`
+ Code int `json:"code"`
+}
+
+func (e *invalidTxError) Error() string { return e.Message }
+func (e *invalidTxError) ErrorCode() int { return e.Code }
+
+const (
+ errCodeNonceTooHigh = -38011
+ errCodeNonceTooLow = -38010
+ errCodeIntrinsicGas = -38013
+ errCodeInsufficientFunds = -38014
+ errCodeBlockGasLimitReached = -38015
+ errCodeBlockNumberInvalid = -38020
+ errCodeBlockTimestampInvalid = -38021
+ errCodeSenderIsNotEOA = -38024
+ errCodeMaxInitCodeSizeExceeded = -38025
+ errCodeClientLimitExceeded = -38026
+ errCodeInternalError = -32603
+ errCodeInvalidParams = -32602
+ errCodeReverted = -32000
+ errCodeVMError = -32015
+)
+
+func txValidationError(err error) *invalidTxError {
+ if err == nil {
+ return nil
+ }
+ switch {
+ case errors.Is(err, core.ErrNonceTooHigh):
+ return &invalidTxError{Message: err.Error(), Code: errCodeNonceTooHigh}
+ case errors.Is(err, core.ErrNonceTooLow):
+ return &invalidTxError{Message: err.Error(), Code: errCodeNonceTooLow}
+ case errors.Is(err, core.ErrSenderNoEOA):
+ return &invalidTxError{Message: err.Error(), Code: errCodeSenderIsNotEOA}
+ case errors.Is(err, core.ErrFeeCapVeryHigh):
+ return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
+ case errors.Is(err, core.ErrTipVeryHigh):
+ return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
+ case errors.Is(err, core.ErrTipAboveFeeCap):
+ return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
+ case errors.Is(err, core.ErrFeeCapTooLow):
+ return &invalidTxError{Message: err.Error(), Code: errCodeInvalidParams}
+ case errors.Is(err, core.ErrInsufficientFunds):
+ return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds}
+ case errors.Is(err, core.ErrIntrinsicGas):
+ return &invalidTxError{Message: err.Error(), Code: errCodeIntrinsicGas}
+ case errors.Is(err, core.ErrInsufficientFundsForTransfer):
+ return &invalidTxError{Message: err.Error(), Code: errCodeInsufficientFunds}
+ case errors.Is(err, core.ErrMaxInitCodeSizeExceeded):
+ return &invalidTxError{Message: err.Error(), Code: errCodeMaxInitCodeSizeExceeded}
+ }
+ return &invalidTxError{
+ Message: err.Error(),
+ Code: errCodeInternalError,
+ }
+}
+
+type invalidParamsError struct{ message string }
+
+func (e *invalidParamsError) Error() string { return e.message }
+func (e *invalidParamsError) ErrorCode() int { return errCodeInvalidParams }
+
+type clientLimitExceededError struct{ message string }
+
+func (e *clientLimitExceededError) Error() string { return e.message }
+func (e *clientLimitExceededError) ErrorCode() int { return errCodeClientLimitExceeded }
+
+type invalidBlockNumberError struct{ message string }
+
+func (e *invalidBlockNumberError) Error() string { return e.message }
+func (e *invalidBlockNumberError) ErrorCode() int { return errCodeBlockNumberInvalid }
+
+type invalidBlockTimestampError struct{ message string }
+
+func (e *invalidBlockTimestampError) Error() string { return e.message }
+func (e *invalidBlockTimestampError) ErrorCode() int { return errCodeBlockTimestampInvalid }
+
+type blockGasLimitReachedError struct{ message string }
+
+func (e *blockGasLimitReachedError) Error() string { return e.message }
+func (e *blockGasLimitReachedError) ErrorCode() int { return errCodeBlockGasLimitReached }
diff --git a/internal/ethapi/logtracer.go b/internal/ethapi/logtracer.go
new file mode 100644
index 000000000..b03146c09
--- /dev/null
+++ b/internal/ethapi/logtracer.go
@@ -0,0 +1,151 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package ethapi
+
+import (
+ "math/big"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
+ "github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/core/vm"
+)
+
+var (
+ // keccak256("Transfer(address,address,uint256)")
+ transferTopic = common.HexToHash("ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef")
+ // ERC-7528
+ transferAddress = common.HexToAddress("0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE")
+)
+
+// tracer is a simple tracer that records all logs and
+// ether transfers. Transfers are recorded as if they
+// were logs. Transfer events include:
+// - tx value
+// - call value
+// - self destructs
+//
+// The log format for a transfer is:
+// - address: 0x0000000000000000000000000000000000000000
+// - data: Value
+// - topics:
+// - Transfer(address,address,uint256)
+// - Sender address
+// - Recipient address
+type tracer struct {
+ // logs keeps logs for all open call frames.
+ // This lets us clear logs for failed calls.
+ logs [][]*types.Log
+ count int
+ traceTransfers bool
+ blockNumber uint64
+ blockHash common.Hash
+ txHash common.Hash
+ txIdx uint
+}
+
+func newTracer(traceTransfers bool, blockNumber uint64, blockHash, txHash common.Hash, txIndex uint) *tracer {
+ return &tracer{
+ traceTransfers: traceTransfers,
+ blockNumber: blockNumber,
+ blockHash: blockHash,
+ txHash: txHash,
+ txIdx: txIndex,
+ }
+}
+
+func (t *tracer) Hooks() *tracing.Hooks {
+ return &tracing.Hooks{
+ OnEnter: t.onEnter,
+ OnExit: t.onExit,
+ OnLog: t.onLog,
+ }
+}
+
+func (t *tracer) onEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int, order uint64) {
+ t.logs = append(t.logs, make([]*types.Log, 0))
+ if vm.OpCode(typ) != vm.DELEGATECALL && value != nil && value.Cmp(common.Big0) > 0 {
+ t.captureTransfer(from, to, value)
+ }
+}
+
+func (t *tracer) onExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ if depth == 0 {
+ t.onEnd(reverted)
+ return
+ }
+ size := len(t.logs)
+ if size <= 1 {
+ return
+ }
+ // pop call
+ call := t.logs[size-1]
+ t.logs = t.logs[:size-1]
+ size--
+
+ // Clear logs if call failed.
+ if !reverted {
+ t.logs[size-1] = append(t.logs[size-1], call...)
+ }
+}
+
+func (t *tracer) onEnd(reverted bool) {
+ if reverted {
+ t.logs[0] = nil
+ }
+}
+
+func (t *tracer) onLog(log *types.Log) {
+ t.captureLog(log.Address, log.Topics, log.Data)
+}
+
+func (t *tracer) captureLog(address common.Address, topics []common.Hash, data []byte) {
+ t.logs[len(t.logs)-1] = append(t.logs[len(t.logs)-1], &types.Log{
+ Address: address,
+ Topics: topics,
+ Data: data,
+ BlockNumber: t.blockNumber,
+ BlockHash: t.blockHash,
+ TxHash: t.txHash,
+ TxIndex: t.txIdx,
+ Index: uint(t.count),
+ })
+ t.count++
+}
+
+func (t *tracer) captureTransfer(from, to common.Address, value *big.Int) {
+ if !t.traceTransfers {
+ return
+ }
+ topics := []common.Hash{
+ transferTopic,
+ common.BytesToHash(from.Bytes()),
+ common.BytesToHash(to.Bytes()),
+ }
+ t.captureLog(transferAddress, topics, common.BigToHash(value).Bytes())
+}
+
+// reset prepares the tracer for the next transaction.
+func (t *tracer) reset(txHash common.Hash, txIdx uint) {
+ t.logs = nil
+ t.txHash = txHash
+ t.txIdx = txIdx
+}
+
+func (t *tracer) Logs() []*types.Log {
+ return t.logs[0]
+}
diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go
new file mode 100644
index 000000000..adc22d34c
--- /dev/null
+++ b/internal/ethapi/simulate.go
@@ -0,0 +1,500 @@
+// Copyright 2023 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package ethapi
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "math/big"
+ "time"
+
+ "github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/consensus"
+ "github.com/ethereum/go-ethereum/consensus/misc/eip1559"
+ "github.com/ethereum/go-ethereum/consensus/misc/eip4844"
+ "github.com/ethereum/go-ethereum/core"
+ "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/ethdb"
+ "github.com/ethereum/go-ethereum/params"
+ "github.com/ethereum/go-ethereum/rpc"
+ "github.com/ethereum/go-ethereum/trie"
+)
+
+const (
+ // maxSimulateBlocks is the maximum number of blocks that can be simulated
+ // in a single request.
+ maxSimulateBlocks = 256
+
+ // timestampIncrement is the default increment between block timestamps.
+ timestampIncrement = 3
+)
+
+// simBlock is a batch of calls to be simulated sequentially.
+type simBlock struct {
+ BlockOverrides *BlockOverrides
+ StateOverrides *StateOverride
+ Calls []TransactionArgs
+}
+
+// simCallResult is the result of a simulated call.
+type simCallResult struct {
+ ReturnValue hexutil.Bytes `json:"returnData"`
+ Logs []*types.Log `json:"logs"`
+ GasUsed hexutil.Uint64 `json:"gasUsed"`
+ Status hexutil.Uint64 `json:"status"`
+ Error *callError `json:"error,omitempty"`
+}
+
+func (r *simCallResult) MarshalJSON() ([]byte, error) {
+ type callResultAlias simCallResult
+ // Marshal logs to be an empty array instead of nil when empty
+ if r.Logs == nil {
+ r.Logs = []*types.Log{}
+ }
+ return json.Marshal((*callResultAlias)(r))
+}
+
+// simBlockResult is the result of a simulated block.
+type simBlockResult struct {
+ fullTx bool
+ chainConfig *params.ChainConfig
+ Block *types.Block
+ Calls []simCallResult
+ // senders is a map of transaction hashes to their senders.
+ senders map[common.Hash]common.Address
+}
+
+func (r *simBlockResult) MarshalJSON() ([]byte, error) {
+ blockData := RPCMarshalBlock(r.Block, true, r.fullTx, r.chainConfig)
+ blockData["calls"] = r.Calls
+
+ // Set tx sender if user requested full tx objects.
+ if r.fullTx {
+ if raw, ok := blockData["transactions"].([]any); ok {
+ for _, tx := range raw {
+ if tx, ok := tx.(*RPCTransaction); ok {
+ tx.From = r.senders[tx.Hash]
+ } else {
+ return nil, errors.New("simulated transaction result has invalid type")
+ }
+ }
+ }
+ }
+
+ return json.Marshal(blockData)
+}
+
+// simOpts are the inputs to eth_simulateV1.
+type simOpts struct {
+ BlockStateCalls []simBlock
+ TraceTransfers bool
+ Validation bool
+ ReturnFullTransactions bool
+}
+
+// simChainHeadReader implements ChainHeaderReader which is needed as input for FinalizeAndAssemble.
+type simChainHeadReader struct {
+ context.Context
+ Backend
+}
+
+func (m *simChainHeadReader) Config() *params.ChainConfig {
+ return m.Backend.ChainConfig()
+}
+
+func (m *simChainHeadReader) CurrentHeader() *types.Header {
+ return m.Backend.CurrentHeader()
+}
+
+func (m *simChainHeadReader) GetHeader(hash common.Hash, number uint64) *types.Header {
+ header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number))
+ if err != nil || header == nil {
+ return nil
+ }
+ if header.Hash() != hash {
+ return nil
+ }
+ return header
+}
+
+func (m *simChainHeadReader) GetHeaderByNumber(number uint64) *types.Header {
+ header, err := m.Backend.HeaderByNumber(m.Context, rpc.BlockNumber(number))
+ if err != nil {
+ return nil
+ }
+ return header
+}
+
+func (m *simChainHeadReader) GetHeaderByHash(hash common.Hash) *types.Header {
+ header, err := m.Backend.HeaderByHash(m.Context, hash)
+ if err != nil {
+ return nil
+ }
+ return header
+}
+
+func (m *simChainHeadReader) OpEvents() []*vm.PublishEvent {
+ return nil
+}
+
+func (m *simChainHeadReader) DB() ethdb.Database {
+ return m.Backend.ChainDb()
+}
+
+func (m *simChainHeadReader) StateCache() state.Database {
+ return nil
+}
+
+// simulator is a stateful object that simulates a series of blocks.
+// it is not safe for concurrent use.
+type simulator struct {
+ b Backend
+ state *state.StateDB
+ base *types.Header
+ chainConfig *params.ChainConfig
+ gp *core.GasPool
+ gasCap uint64 // gas cap for the simulation to prevent DoS
+ traceTransfers bool
+ validate bool
+ fullTx bool
+}
+
+// execute runs the simulation of a series of blocks.
+func (sim *simulator) execute(ctx context.Context, blocks []simBlock) ([]*simBlockResult, error) {
+ if err := ctx.Err(); err != nil {
+ return nil, err
+ }
+ var (
+ cancel context.CancelFunc
+ timeout = sim.b.RPCEVMTimeout()
+ )
+ if timeout > 0 {
+ ctx, cancel = context.WithTimeout(ctx, timeout)
+ } else {
+ ctx, cancel = context.WithCancel(ctx)
+ }
+ // Make sure the context is cancelled when the call has completed
+ // this makes sure resources are cleaned up.
+ defer cancel()
+
+ var err error
+ blocks, err = sim.sanitizeChain(blocks)
+ if err != nil {
+ return nil, err
+ }
+ // Prepare block headers with preliminary fields for the response.
+ headers, err := sim.makeHeaders(blocks)
+ if err != nil {
+ return nil, err
+ }
+ var (
+ results = make([]*simBlockResult, len(blocks))
+ parent = sim.base
+ )
+ for bi, block := range blocks {
+ result, callResults, senders, err := sim.processBlock(ctx, &block, headers[bi], parent, headers[:bi], timeout)
+ if err != nil {
+ return nil, err
+ }
+ headers[bi] = result.Header()
+ results[bi] = &simBlockResult{fullTx: sim.fullTx, chainConfig: sim.chainConfig, Block: result, Calls: callResults, senders: senders}
+ parent = result.Header()
+ }
+ return results, nil
+}
+
+func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, parent *types.Header, headers []*types.Header, timeout time.Duration) (*types.Block, []simCallResult, map[common.Hash]common.Address, error) {
+ // Set header fields that depend only on parent block.
+ // Parent hash is needed for evm.GetHashFn to work.
+ header.ParentHash = parent.Hash()
+ if sim.chainConfig.IsLondon(header.Number) {
+ // In non-validation mode base fee is set to 0 if it is not overridden.
+ // This is because it creates an edge case in EVM where gasPrice < baseFee.
+ // Base fee could have been overridden.
+ if header.BaseFee == nil {
+ if sim.validate {
+ header.BaseFee = eip1559.CalcBaseFee(sim.chainConfig, parent)
+ } else {
+ header.BaseFee = big.NewInt(0)
+ }
+ }
+ }
+ if sim.chainConfig.IsCancun(header.Number) {
+ var excess uint64
+ if sim.chainConfig.IsCancun(parent.Number) && parent.ExcessBlobGas != nil && parent.BlobGasUsed != nil {
+ excess = eip4844.CalcExcessBlobGas(*parent.ExcessBlobGas, *parent.BlobGasUsed)
+ }
+ header.ExcessBlobGas = &excess
+ }
+ blockContext := core.NewEVMBlockContext(header, sim.newSimulatedChainContext(ctx, headers), nil)
+
+ precompiles := sim.activePrecompiles(sim.base)
+ // State overrides are applied prior to execution of a block
+ if err := block.StateOverrides.Apply(sim.state, precompiles); err != nil {
+ return nil, nil, nil, err
+ }
+ var (
+ gasUsed, blobGasUsed uint64
+ txes = make([]*types.Transaction, len(block.Calls))
+ callResults = make([]simCallResult, len(block.Calls))
+ receipts = make([]*types.Receipt, len(block.Calls))
+ // Block hash will be repaired after execution.
+ tracer = newTracer(sim.traceTransfers, blockContext.BlockNumber.Uint64(), common.Hash{}, common.Hash{}, 0)
+ vmConfig = &vm.Config{
+ NoBaseFee: !sim.validate,
+ Tracer: tracer.Hooks(),
+ }
+ // senders is a map of transaction hashes to their senders.
+ // Transaction objects contain only the signature, and we lose track
+ // of the sender when translating the arguments into a transaction object.
+ senders = make(map[common.Hash]common.Address)
+ )
+ tracingStateDB := vm.StateDB(sim.state)
+ if hooks := tracer.Hooks(); hooks != nil {
+ sim.state.SetLogger(hooks)
+ // TODO(kuro): enable this when merge https://github.com/ethereum/go-ethereum/pull/30569
+ // tracingStateDB = state.NewHookedState(sim.state, hooks)
+ }
+
+ evm := vm.NewEVM(blockContext, vm.TxContext{GasPrice: big.NewInt(0)}, tracingStateDB, sim.chainConfig, *vmConfig)
+ // It is possible to override precompiles with EVM bytecode, or
+ // move them to another address.
+ if precompiles != nil {
+ evm.SetPrecompiles(precompiles)
+ }
+ if sim.chainConfig.IsKotaro(header.Number) {
+ core.ProcessParentBlockHash(header.ParentHash, evm)
+ }
+
+ for i, call := range block.Calls {
+ if err := ctx.Err(); err != nil {
+ return nil, nil, nil, err
+ }
+ if err := sim.sanitizeCall(&call, sim.state, header, blockContext, &gasUsed); err != nil {
+ return nil, nil, nil, err
+ }
+ var (
+ tx = call.ToTransaction()
+ txHash = tx.Hash()
+ )
+ txes[i] = tx
+ senders[txHash] = call.from()
+ tracer.reset(txHash, uint(i))
+ sim.state.SetTxContext(txHash, i)
+ msg := call.ToMessage(sim.base.GasLimit, header.BaseFee, !sim.validate)
+
+ evm.TxContext = core.NewEVMTxContext(msg)
+ result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
+ if err != nil {
+ txErr := txValidationError(err)
+ return nil, nil, nil, txErr
+ }
+ // Update the state with pending changes.
+ var root []byte
+ if sim.chainConfig.IsByzantium(blockContext.BlockNumber) {
+ tracingStateDB.Finalise(true)
+ } else {
+ root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(blockContext.BlockNumber)).Bytes()
+ }
+ gasUsed += result.UsedGas
+ receipts[i] = core.MakeReceipt(evm, result, sim.state, blockContext.BlockNumber, common.Hash{}, tx, gasUsed, root)
+ blobGasUsed += receipts[i].BlobGasUsed
+ logs := tracer.Logs()
+ callRes := simCallResult{ReturnValue: result.Return(), Logs: logs, GasUsed: hexutil.Uint64(result.UsedGas)}
+ if result.Failed() {
+ callRes.Status = hexutil.Uint64(types.ReceiptStatusFailed)
+ if errors.Is(result.Err, vm.ErrExecutionReverted) {
+ // If the result contains a revert reason, try to unpack it.
+ revertErr := newRevertError(result.Revert())
+ callRes.Error = &callError{Message: revertErr.Error(), Code: errCodeReverted, Data: revertErr.ErrorData().(string)}
+ } else {
+ callRes.Error = &callError{Message: result.Err.Error(), Code: errCodeVMError}
+ }
+ } else {
+ callRes.Status = hexutil.Uint64(types.ReceiptStatusSuccessful)
+ }
+ callResults[i] = callRes
+ }
+ header.Root = sim.state.IntermediateRoot(sim.chainConfig.IsEIP158(header.Number))
+ header.GasUsed = gasUsed
+ if sim.chainConfig.IsCancun(header.Number) {
+ header.BlobGasUsed = &blobGasUsed
+ }
+
+ b := types.NewBlock(header, txes, nil, receipts, trie.NewStackTrie(nil))
+ repairLogs(callResults, b.Hash())
+ return b, callResults, senders, nil
+}
+
+// repairLogs updates the block hash in the logs present in the result of
+// a simulated block. This is needed as during execution when logs are collected
+// the block hash is not known.
+func repairLogs(calls []simCallResult, hash common.Hash) {
+ for i := range calls {
+ for j := range calls[i].Logs {
+ calls[i].Logs[j].BlockHash = hash
+ }
+ }
+}
+
+func (sim *simulator) sanitizeCall(call *TransactionArgs, state vm.StateDB, header *types.Header, blockContext vm.BlockContext, gasUsed *uint64) error {
+ if call.Nonce == nil {
+ nonce := state.GetNonce(call.from())
+ call.Nonce = (*hexutil.Uint64)(&nonce)
+ }
+ // Let the call run wild unless explicitly specified.
+ if call.Gas == nil {
+ remaining := blockContext.GasLimit - *gasUsed
+ call.Gas = (*hexutil.Uint64)(&remaining)
+ }
+ if *gasUsed+uint64(*call.Gas) > blockContext.GasLimit {
+ return &blockGasLimitReachedError{fmt.Sprintf("block gas limit reached: %d >= %d", gasUsed, blockContext.GasLimit)}
+ }
+ if err := call.CallDefaults(sim.gp.Gas(), header.BaseFee, sim.chainConfig.ChainID); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (sim *simulator) activePrecompiles(base *types.Header) vm.PrecompiledContracts {
+ return vm.ActivePrecompiledContracts(sim.chainConfig.Rules(base.Number))
+}
+
+// sanitizeChain checks the chain integrity. Specifically it checks that
+// block numbers and timestamp are strictly increasing, setting default values
+// when necessary. Gaps in block numbers are filled with empty blocks.
+// Note: It modifies the block's override object.
+func (sim *simulator) sanitizeChain(blocks []simBlock) ([]simBlock, error) {
+ var (
+ res = make([]simBlock, 0, len(blocks))
+ base = sim.base
+ prevNumber = base.Number
+ prevTimestamp = base.Time
+ )
+ for _, block := range blocks {
+ if block.BlockOverrides == nil {
+ block.BlockOverrides = new(BlockOverrides)
+ }
+ if block.BlockOverrides.Number == nil {
+ n := new(big.Int).Add(prevNumber, big.NewInt(1))
+ block.BlockOverrides.Number = (*hexutil.Big)(n)
+ }
+ diff := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), prevNumber)
+ if diff.Cmp(common.Big0) <= 0 {
+ return nil, &invalidBlockNumberError{fmt.Sprintf("block numbers must be in order: %d <= %d", block.BlockOverrides.Number.ToInt().Uint64(), prevNumber)}
+ }
+ if total := new(big.Int).Sub(block.BlockOverrides.Number.ToInt(), base.Number); total.Cmp(big.NewInt(maxSimulateBlocks)) > 0 {
+ return nil, &clientLimitExceededError{message: "too many blocks"}
+ }
+ if diff.Cmp(big.NewInt(1)) > 0 {
+ // Fill the gap with empty blocks.
+ gap := new(big.Int).Sub(diff, big.NewInt(1))
+ // Assign block number to the empty blocks.
+ for i := uint64(0); i < gap.Uint64(); i++ {
+ n := new(big.Int).Add(prevNumber, big.NewInt(int64(i+1)))
+ t := prevTimestamp + timestampIncrement
+ b := simBlock{
+ BlockOverrides: &BlockOverrides{
+ Number: (*hexutil.Big)(n),
+ Time: (*hexutil.Uint64)(&t),
+ },
+ }
+ prevTimestamp = t
+ res = append(res, b)
+ }
+ }
+ // Only append block after filling a potential gap.
+ prevNumber = block.BlockOverrides.Number.ToInt()
+ var t uint64
+ if block.BlockOverrides.Time == nil {
+ t = prevTimestamp + timestampIncrement
+ block.BlockOverrides.Time = (*hexutil.Uint64)(&t)
+ } else {
+ t = uint64(*block.BlockOverrides.Time)
+ if t <= prevTimestamp {
+ return nil, &invalidBlockTimestampError{fmt.Sprintf("block timestamps must be in order: %d <= %d", t, prevTimestamp)}
+ }
+ }
+ prevTimestamp = t
+ res = append(res, block)
+ }
+ return res, nil
+}
+
+// makeHeaders makes header object with preliminary fields based on a simulated block.
+// Some fields have to be filled post-execution.
+// It assumes blocks are in order and numbers have been validated.
+func (sim *simulator) makeHeaders(blocks []simBlock) ([]*types.Header, error) {
+ var (
+ res = make([]*types.Header, len(blocks))
+ base = sim.base
+ header = base
+ )
+ for bi, block := range blocks {
+ if block.BlockOverrides == nil || block.BlockOverrides.Number == nil {
+ return nil, errors.New("empty block number")
+ }
+ overrides := block.BlockOverrides
+
+ header = overrides.MakeHeader(&types.Header{
+ UncleHash: types.EmptyUncleHash,
+ ReceiptHash: types.EmptyReceiptsHash,
+ TxHash: types.EmptyTxsHash,
+ Coinbase: header.Coinbase,
+ Difficulty: header.Difficulty,
+ GasLimit: header.GasLimit,
+ })
+ res[bi] = header
+ }
+ return res, nil
+}
+
+func (sim *simulator) newSimulatedChainContext(ctx context.Context, headers []*types.Header) *ChainContext {
+ return NewChainContext(ctx, &simBackend{base: sim.base, b: sim.b, headers: headers})
+}
+
+type simBackend struct {
+ b ChainContextBackend
+ base *types.Header
+ headers []*types.Header
+}
+
+func (b *simBackend) Engine() consensus.Engine {
+ return b.b.Engine()
+}
+
+func (b *simBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
+ if uint64(number) == b.base.Number.Uint64() {
+ return b.base, nil
+ }
+ if uint64(number) < b.base.Number.Uint64() {
+ // Resolve canonical header.
+ return b.b.HeaderByNumber(ctx, number)
+ }
+ // Simulated block.
+ for _, header := range b.headers {
+ if header.Number.Uint64() == uint64(number) {
+ return header, nil
+ }
+ }
+ return nil, errors.New("header not found")
+}
diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go
new file mode 100644
index 000000000..4fe20b570
--- /dev/null
+++ b/internal/ethapi/simulate_test.go
@@ -0,0 +1,120 @@
+// Copyright 2024 The go-ethereum Authors
+// This file is part of the go-ethereum library.
+//
+// The go-ethereum library is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// The go-ethereum library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with the go-ethereum library. If not, see .
+
+package ethapi
+
+import (
+ "math/big"
+ "testing"
+
+ "github.com/ethereum/go-ethereum/common/hexutil"
+ "github.com/ethereum/go-ethereum/core/types"
+)
+
+func TestSimulateSanitizeBlockOrder(t *testing.T) {
+ type result struct {
+ number uint64
+ timestamp uint64
+ }
+ for i, tc := range []struct {
+ baseNumber int
+ baseTimestamp uint64
+ blocks []simBlock
+ expected []result
+ err string
+ }{
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{}, {}, {}},
+ expected: []result{{number: 11, timestamp: 53}, {number: 12, timestamp: 56}, {number: 13, timestamp: 59}},
+ },
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}},
+ expected: []result{{number: 11, timestamp: 53}, {number: 12, timestamp: 56}, {number: 13, timestamp: 70}, {number: 14, timestamp: 73}},
+ },
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &BlockOverrides{Number: newInt(14)}}, {}},
+ expected: []result{{number: 11, timestamp: 53}, {number: 12, timestamp: 56}, {number: 13, timestamp: 59}, {number: 14, timestamp: 62}, {number: 15, timestamp: 65}},
+ },
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12)}}},
+ err: "block numbers must be in order: 12 <= 13",
+ },
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(56)}}},
+ err: "block timestamps must be in order: 56 <= 56",
+ },
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(12), Time: newUint64(55)}}},
+ err: "block timestamps must be in order: 55 <= 60",
+ },
+ {
+ baseNumber: 10,
+ baseTimestamp: 50,
+ blocks: []simBlock{{BlockOverrides: &BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &BlockOverrides{Number: newInt(13), Time: newUint64(63)}}},
+ err: "block timestamps must be in order: 63 <= 63",
+ },
+ } {
+ sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}}
+ res, err := sim.sanitizeChain(tc.blocks)
+ if err != nil {
+ if err.Error() == tc.err {
+ continue
+ } else {
+ t.Fatalf("testcase %d: error mismatch. Want '%s', have '%s'", i, tc.err, err.Error())
+ }
+ }
+ if err == nil && tc.err != "" {
+ t.Fatalf("testcase %d: expected err", i)
+ }
+ if len(res) != len(tc.expected) {
+ t.Errorf("testcase %d: mismatch number of blocks. Want %d, have %d", i, len(tc.expected), len(res))
+ }
+ for bi, b := range res {
+ if b.BlockOverrides == nil {
+ t.Fatalf("testcase %d: block overrides nil", i)
+ }
+ if b.BlockOverrides.Number == nil {
+ t.Fatalf("testcase %d: block number not set", i)
+ }
+ if b.BlockOverrides.Time == nil {
+ t.Fatalf("testcase %d: block time not set", i)
+ }
+ if uint64(*b.BlockOverrides.Time) != tc.expected[bi].timestamp {
+ t.Errorf("testcase %d: block timestamp mismatch. Want %d, have %d", i, tc.expected[bi].timestamp, uint64(*b.BlockOverrides.Time))
+ }
+ have := b.BlockOverrides.Number.ToInt().Uint64()
+ if have != tc.expected[bi].number {
+ t.Errorf("testcase %d: block number mismatch. Want %d, have %d", i, tc.expected[bi].number, have)
+ }
+ }
+ }
+}
+
+func newInt(n int64) *hexutil.Big {
+ return (*hexutil.Big)(big.NewInt(n))
+}
diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go
index 2798c5621..21a8f5b3e 100644
--- a/internal/ethapi/transaction_args.go
+++ b/internal/ethapi/transaction_args.go
@@ -28,6 +28,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
+ "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/kzg4844"
"github.com/ethereum/go-ethereum/log"
@@ -233,11 +234,7 @@ func (args *TransactionArgs) setDefaults(ctx context.Context, b Backend) error {
// ToMessage converts the transaction arguments to the Message type used by the
// core evm. This method is used in calls and traces that do not require a real
// live transaction.
-func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (types.Message, error) {
- // Reject invalid combinations of pre- and post-1559 fee styles
- if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
- return types.Message{}, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
- }
+func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int, skipEoACheck bool) *core.Message {
// Set sender address or use zero address if none specified.
addr := args.from()
@@ -300,8 +297,27 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (t
if args.BlobHashes != nil && args.BlobFeeCap == nil {
args.BlobFeeCap = new(hexutil.Big)
}
- msg := types.NewMessage(addr, args.To, 0, value, gas, gasPrice, gasFeeCap, gasTipCap, data, accessList, true, (*big.Int)(args.BlobFeeCap), args.BlobHashes, args.AuthorizationList)
- return msg, nil
+ var nonce uint64
+ if args.Nonce != nil {
+ nonce = uint64(*args.Nonce)
+ }
+ msg := core.NewMessage(
+ addr,
+ args.To,
+ nonce,
+ value,
+ gas,
+ gasPrice,
+ gasFeeCap,
+ gasTipCap,
+ data,
+ accessList,
+ skipEoACheck,
+ (*big.Int)(args.BlobFeeCap),
+ args.BlobHashes,
+ args.AuthorizationList,
+ )
+ return msg
}
// toTransaction converts the arguments to a transaction.
@@ -475,6 +491,59 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context) error {
return nil
}
+// CallDefaults sanitizes the transaction arguments, often filling in zero values,
+// for the purpose of eth_call class of RPC methods.
+func (args *TransactionArgs) CallDefaults(globalGasCap uint64, baseFee *big.Int, chainID *big.Int) error {
+ // Reject invalid combinations of pre- and post-1559 fee styles
+ if args.GasPrice != nil && (args.MaxFeePerGas != nil || args.MaxPriorityFeePerGas != nil) {
+ return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
+ }
+ if args.ChainID == nil {
+ args.ChainID = (*hexutil.Big)(chainID)
+ } else {
+ if have := (*big.Int)(args.ChainID); have.Cmp(chainID) != 0 {
+ return fmt.Errorf("chainId does not match node's (have=%v, want=%v)", have, chainID)
+ }
+ }
+ if args.Gas == nil {
+ gas := globalGasCap
+ if gas == 0 {
+ gas = uint64(math.MaxUint64 / 2)
+ }
+ args.Gas = (*hexutil.Uint64)(&gas)
+ } else {
+ if globalGasCap > 0 && globalGasCap < uint64(*args.Gas) {
+ log.Warn("Caller gas above allowance, capping", "requested", args.Gas, "cap", globalGasCap)
+ args.Gas = (*hexutil.Uint64)(&globalGasCap)
+ }
+ }
+ if args.Nonce == nil {
+ args.Nonce = new(hexutil.Uint64)
+ }
+ if args.Value == nil {
+ args.Value = new(hexutil.Big)
+ }
+ if baseFee == nil {
+ // If there's no basefee, then it must be a non-1559 execution
+ if args.GasPrice == nil {
+ args.GasPrice = new(hexutil.Big)
+ }
+ } else {
+ // A basefee is provided, necessitating 1559-type execution
+ if args.MaxFeePerGas == nil {
+ args.MaxFeePerGas = new(hexutil.Big)
+ }
+ if args.MaxPriorityFeePerGas == nil {
+ args.MaxPriorityFeePerGas = new(hexutil.Big)
+ }
+ }
+ if args.BlobFeeCap == nil && args.BlobHashes != nil {
+ args.BlobFeeCap = new(hexutil.Big)
+ }
+
+ return nil
+}
+
// IsEIP4844 returns an indicator if the args contains EIP4844 fields.
func (args *TransactionArgs) IsEIP4844() bool {
return args.BlobHashes != nil || args.BlobFeeCap != nil
diff --git a/les/api_backend.go b/les/api_backend.go
index cff38c8ab..9bd9e61ae 100644
--- a/les/api_backend.go
+++ b/les/api_backend.go
@@ -197,7 +197,7 @@ func (b *LesApiBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil
}
-func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) {
+func (b *LesApiBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error, error) {
if vmConfig == nil {
vmConfig = new(vm.Config)
}
@@ -365,6 +365,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)
}
diff --git a/les/odr_test.go b/les/odr_test.go
index 50a66f5c5..b15034f30 100644
--- a/les/odr_test.go
+++ b/les/odr_test.go
@@ -31,6 +31,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
@@ -116,12 +117,6 @@ func TestOdrContractCallLes2(t *testing.T) { testOdr(t, 2, 2, true, odrContractC
func TestOdrContractCallLes3(t *testing.T) { testOdr(t, 3, 2, true, odrContractCall) }
func TestOdrContractCallLes4(t *testing.T) { testOdr(t, 4, 2, true, odrContractCall) }
-type callmsg struct {
- types.Message
-}
-
-func (callmsg) CheckNonce() bool { return false }
-
func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
@@ -134,15 +129,30 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
if err == nil {
from := statedb.GetOrNewStateObject(bankAddr)
- from.SetBalance(math.MaxBig256)
-
- msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true, nil, nil, nil)}
+ from.SetBalance(math.MaxBig256, tracing.BalanceChangeUnspecified)
+
+ msg := core.NewMessage(
+ from.Address(),
+ &testContractAddr,
+ 0,
+ new(big.Int),
+ 100000,
+ big.NewInt(params.InitialBaseFee),
+ big.NewInt(params.InitialBaseFee),
+ new(big.Int),
+ data,
+ nil,
+ true,
+ nil,
+ nil,
+ nil,
+ )
context := core.NewEVMBlockContext(header, bc, nil)
txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, txContext, statedb, config, vm.Config{NoBaseFee: true})
- //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
+ // vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
gp := new(core.GasPool).AddGas(math.MaxUint64)
result, _ := core.ApplyMessage(vmenv, msg, gp)
res = append(res, result.Return()...)
@@ -150,8 +160,23 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai
} else {
header := lc.GetHeaderByHash(bhash)
state := light.NewState(ctx, header, lc.Odr())
- state.SetBalance(bankAddr, math.MaxBig256)
- msg := callmsg{types.NewMessage(bankAddr, &testContractAddr, 0, new(big.Int), 100000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true, nil, nil, nil)}
+ state.SetBalance(bankAddr, math.MaxBig256, tracing.BalanceChangeUnspecified)
+ msg := core.NewMessage(
+ bankAddr,
+ &testContractAddr,
+ 0,
+ new(big.Int),
+ 100000,
+ big.NewInt(params.InitialBaseFee),
+ big.NewInt(params.InitialBaseFee),
+ new(big.Int),
+ data,
+ nil,
+ true,
+ nil,
+ nil,
+ nil,
+ )
context := core.NewEVMBlockContext(header, lc, nil)
txContext := core.NewEVMTxContext(msg)
vmenv := vm.NewEVM(context, txContext, state, config, vm.Config{NoBaseFee: true})
@@ -341,7 +366,7 @@ func testGetTxStatusFromUnindexedPeers(t *testing.T, protocol int) {
return nil
}
- var testspecs = []struct {
+ testspecs := []struct {
peers int
txLookups []uint64
txs []common.Hash
diff --git a/les/state_accessor.go b/les/state_accessor.go
index 66ab79b76..f046f4550 100644
--- a/les/state_accessor.go
+++ b/les/state_accessor.go
@@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
+
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/consensus/consortium"
@@ -40,7 +41,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")
@@ -61,12 +62,12 @@ func (leth *LightEthereum) stateAtTransaction(ctx context.Context, block *types.
signer := types.MakeSigner(leth.blockchain.Config(), block.Number())
for idx, tx := range block.Transactions() {
// Assemble the transaction call message and return if the requested offset
- msg, _ := tx.AsMessage(signer, block.BaseFee())
+ msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
txContext := core.NewEVMTxContext(msg)
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{})
diff --git a/light/odr_test.go b/light/odr_test.go
index 915054e7a..46bf92c81 100644
--- a/light/odr_test.go
+++ b/light/odr_test.go
@@ -30,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
"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/vm"
"github.com/ethereum/go-ethereum/crypto"
@@ -163,12 +164,6 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
func TestOdrContractCallLes2(t *testing.T) { testChainOdr(t, 1, odrContractCall) }
-type callmsg struct {
- types.Message
-}
-
-func (callmsg) CheckNonce() bool { return false }
-
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) ([]byte, error) {
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
config := params.TestChainConfig
@@ -193,8 +188,23 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
}
// Perform read-only call.
- st.SetBalance(testBankAddress, math.MaxBig256)
- msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, big.NewInt(params.InitialBaseFee), big.NewInt(params.InitialBaseFee), new(big.Int), data, nil, true, nil, nil, nil)}
+ st.SetBalance(testBankAddress, math.MaxBig256, tracing.BalanceChangeUnspecified)
+ msg := core.NewMessage(
+ testBankAddress,
+ &testContractAddr,
+ 0,
+ new(big.Int),
+ 1000000,
+ big.NewInt(params.InitialBaseFee),
+ big.NewInt(params.InitialBaseFee),
+ new(big.Int),
+ data,
+ nil,
+ true,
+ nil,
+ nil,
+ nil,
+ )
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(header, chain, nil)
vmenv := vm.NewEVM(context, txContext, st, config, vm.Config{NoBaseFee: true})
diff --git a/miner/worker.go b/miner/worker.go
index daaf4a12d..52d08fc87 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -858,7 +858,7 @@ func (w *worker) updateSnapshot() {
w.snapshotState = w.current.state.Copy()
}
-func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address, receiptProcessor core.ReceiptProcessor) ([]*types.Log, error) {
+func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Address) ([]*types.Log, error) {
txType := tx.Type()
if txType == types.BlobTxType {
if tx.BlobTxSidecar() == nil {
@@ -881,7 +881,6 @@ func (w *worker) commitTransaction(tx *types.Transaction, coinbase common.Addres
tx,
&w.current.header.GasUsed,
*w.chain.GetVMConfig(),
- receiptProcessor,
)
if err != nil {
w.current.state.RevertToSnapshot(snap)
@@ -951,9 +950,6 @@ func (w *worker) commitTransactions(plainTxs, blobTxs *TransactionsByPriceAndNon
timer = time.NewTimer(duration)
}
- bloomProcessor := core.NewAsyncReceiptBloomGenerator(plainTxs.Size() + blobTxs.Size())
- defer bloomProcessor.Close()
-
Loop:
for {
if timer != nil {
@@ -1061,7 +1057,7 @@ Loop:
// Start executing the transaction
w.current.state.SetTxContext(tx.Hash(), w.current.tcount)
- logs, err := w.commitTransaction(tx, coinbase, bloomProcessor)
+ logs, err := w.commitTransaction(tx, coinbase)
switch {
case errors.Is(err, core.ErrGasLimitReached):
// Pop the current out-of-gas transaction without shifting in the next from the account
diff --git a/miner/worker_test.go b/miner/worker_test.go
index c33840365..9789dc648 100644
--- a/miner/worker_test.go
+++ b/miner/worker_test.go
@@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
"github.com/ethereum/go-ethereum/core/types"
@@ -713,8 +714,8 @@ func TestCommitBlobTransaction(t *testing.T) {
blobTxsByPrice := NewTransactionsByPriceAndNonce(signer, blobTxs, common.Big0)
w.current = newCurrent(t, signer, w.chain)
- w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
- w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
+ w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
+ w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
// Case 1: Not Cancun, blob transactions are not committed but plain transactions are committed
// normally without error
@@ -731,8 +732,8 @@ func TestCommitBlobTransaction(t *testing.T) {
// Case 2: Higher blob transaction tip is prioritized
w.current = newCurrent(t, signer, w.chain)
- w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
- w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
+ w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
+ w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
w.current.header.BlobGasUsed = new(uint64)
chainConfig.CancunBlock = common.Big0
@@ -795,8 +796,8 @@ func TestCommitBlobTransaction(t *testing.T) {
// Case 3: Choose the blob transaction that does not make the blob gas used exceed the limit
w.current = newCurrent(t, signer, w.chain)
- w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
- w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
+ w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
+ w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
w.current.header.BlobGasUsed = new(uint64)
*w.current.header.BlobGasUsed = 3 * params.BlobTxBlobGasPerBlob
@@ -820,7 +821,7 @@ func TestCommitBlobTransaction(t *testing.T) {
// Case 4: Blob sidecars should be discarded when commit blob transactions
w.current = newCurrent(t, signer, w.chain)
- w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
+ w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
w.current.header.BlobGasUsed = new(uint64)
chainConfig.CancunBlock = common.Big0
w.chainConfig = chainConfig
@@ -847,8 +848,8 @@ func TestCommitBlobTransaction(t *testing.T) {
// Case 5: correctly handle evicted pending transaction
w.current = newCurrent(t, signer, w.chain)
- w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
- w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil))
+ w.current.state.AddBalance(senderAddress1, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
+ w.current.state.AddBalance(senderAddress2, new(big.Int).Exp(big.NewInt(10), big.NewInt(20), nil), tracing.BalanceIncreaseSelfdestruct)
w.current.header.BlobGasUsed = new(uint64)
chainConfig.CancunBlock = common.Big0
w.chainConfig = chainConfig
diff --git a/signer/core/api.go b/signer/core/api.go
index fb68018a6..620b964ca 100644
--- a/signer/core/api.go
+++ b/signer/core/api.go
@@ -227,7 +227,7 @@ type (
}
// SignTxResponse result from SignTxRequest
SignTxResponse struct {
- //The UI may make changes to the TX
+ // The UI may make changes to the TX
Transaction apitypes.SendTxArgs `json:"transaction"`
Approved bool `json:"approved"`
}
@@ -289,6 +289,7 @@ func NewSignerAPI(am *accounts.Manager, chainID int64, noUSB bool, ui UIClientAP
}
return signer
}
+
func (api *SignerAPI) openTrezor(url accounts.URL) {
resp, err := api.UI.OnInputRequired(UserInputRequest{
Prompt: "Pin required to open Trezor wallet\n" +
@@ -317,7 +318,6 @@ func (api *SignerAPI) openTrezor(url accounts.URL) {
log.Warn("failed to open wallet", "wallet", url, "err", err)
return
}
-
}
// startUSBListener starts a listener for USB events, for hardware wallet interaction
@@ -352,7 +352,7 @@ func (api *SignerAPI) derivationLoop(events chan accounts.WalletEvent) {
case accounts.WalletOpened:
status, _ := event.Wallet.Status()
log.Info("New wallet appeared", "url", event.Wallet.URL(), "status", status)
- var derive = func(limit int, next func() accounts.DerivationPath) {
+ derive := func(limit int, next func() accounts.DerivationPath) {
// Derive first N accounts, hardcoded for now
for i := 0; i < limit; i++ {
path := next()
@@ -386,7 +386,7 @@ func (api *SignerAPI) derivationLoop(events chan accounts.WalletEvent) {
// List returns the set of wallet this signer manages. Each wallet can contain
// multiple accounts.
func (api *SignerAPI) List(ctx context.Context) ([]common.Address, error) {
- var accs = make([]accounts.Account, 0)
+ accs := make([]accounts.Account, 0)
// accs is initialized as empty list, not nil. We use 'nil' to signal
// rejection, as opposed to an empty list.
for _, wallet := range api.am.Wallets() {
@@ -433,7 +433,8 @@ func (api *SignerAPI) newAccount() (common.Address, error) {
resp, err := api.UI.OnInputRequired(UserInputRequest{
"New account password",
fmt.Sprintf("Please enter a password for the new account to be created (attempt %d of 3)", i),
- true})
+ true,
+ })
if err != nil {
log.Warn("error obtaining password", "attempt", i, "error", err)
continue
@@ -457,7 +458,7 @@ func (api *SignerAPI) newAccount() (common.Address, error) {
// it also returns 'true' if the transaction was modified, to make it possible to configure the signer not to allow
// UI-modifications to requests
func logDiff(original *SignTxRequest, new *SignTxResponse) bool {
- var intPtrModified = func(a, b *hexutil.Big) bool {
+ intPtrModified := func(a, b *hexutil.Big) bool {
aBig := (*big.Int)(a)
bBig := (*big.Int)(b)
if aBig != nil && bBig != nil {
@@ -586,7 +587,7 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args apitypes.SendTxA
return nil, err
}
// Convert fields into a real transaction
- var unsignedTx = result.Transaction.ToTransaction()
+ unsignedTx := result.Transaction.ToTransaction()
// Get the password for the transaction
pw, err := api.lookupOrQueryPassword(acc.Address, "Account password",
fmt.Sprintf("Please enter the password for account %s", acc.Address.String()))
@@ -610,7 +611,6 @@ func (api *SignerAPI) SignTransaction(ctx context.Context, args apitypes.SendTxA
api.UI.OnApprovedTx(response)
// ...and to the external caller
return &response, nil
-
}
func (api *SignerAPI) SignGnosisSafeTx(ctx context.Context, signerAddress common.MixedcaseAddress, gnosisTx GnosisSafeTx, methodSelector *string) (*GnosisSafeTx, error) {
diff --git a/signer/rules/rules_test.go b/signer/rules/rules_test.go
index d506ef2db..e987c576d 100644
--- a/signer/rules/rules_test.go
+++ b/signer/rules/rules_test.go
@@ -78,6 +78,7 @@ type alwaysDenyUI struct{}
func (alwaysDenyUI) OnInputRequired(info core.UserInputRequest) (core.UserInputResponse, error) {
return core.UserInputResponse{}, nil
}
+
func (alwaysDenyUI) RegisterUIServer(api *core.UIServerAPI) {
}
@@ -152,7 +153,6 @@ func TestListRequest(t *testing.T) {
}
func TestSignTxRequest(t *testing.T) {
-
js := `
function ApproveTx(r){
console.log("transaction.from", r.transaction.from);
@@ -174,7 +174,6 @@ func TestSignTxRequest(t *testing.T) {
return
}
from, err := mixAddr("0000000000000000000000000000000000001337")
-
if err != nil {
t.Error(err)
return
@@ -183,7 +182,8 @@ func TestSignTxRequest(t *testing.T) {
resp, err := r.ApproveTx(&core.SignTxRequest{
Transaction: apitypes.SendTxArgs{
From: *from,
- To: to},
+ To: to,
+ },
Callinfo: nil,
Meta: core.Metadata{Remote: "remoteip", Local: "localip", Scheme: "inproc"},
})
@@ -243,9 +243,8 @@ func (d *dummyUI) OnApprovedTx(tx ethapi.SignTransactionResult) {
func (d *dummyUI) OnSignerStartup(info core.StartupInfo) {
}
-//TestForwarding tests that the rule-engine correctly dispatches requests to the next caller
+// TestForwarding tests that the rule-engine correctly dispatches requests to the next caller
func TestForwarding(t *testing.T) {
-
js := ""
ui := &dummyUI{make([]string, 0)}
jsBackend := storage.NewEphemeralStorage()
@@ -263,16 +262,13 @@ func TestForwarding(t *testing.T) {
r.ShowError("test")
r.ShowInfo("test")
- //This one is not forwarded
+ // This one is not forwarded
r.OnApprovedTx(ethapi.SignTransactionResult{})
expCalls := 6
if len(ui.calls) != expCalls {
-
t.Errorf("Expected %d forwarded calls, got %d: %s", expCalls, len(ui.calls), strings.Join(ui.calls, ","))
-
}
-
}
func TestMissingFunc(t *testing.T) {
@@ -296,10 +292,9 @@ func TestMissingFunc(t *testing.T) {
t.Errorf("Expected missing method to cause non-approval")
}
t.Logf("Err %v", err)
-
}
-func TestStorage(t *testing.T) {
+func TestStorage(t *testing.T) {
js := `
function testStorage(){
storage.put("mykey", "myvalue")
@@ -334,7 +329,6 @@ func TestStorage(t *testing.T) {
}
v, err := r.execute("testStorage", nil)
-
if err != nil {
t.Errorf("Unexpected error %v", err)
}
@@ -348,7 +342,6 @@ func TestStorage(t *testing.T) {
t.Errorf("Unexpected data, expected '%v', got '%v'", exp, retval)
}
t.Logf("Err %v", err)
-
}
const ExampleTxWindow = `
@@ -544,11 +537,10 @@ func (d *dontCallMe) OnApprovedTx(tx ethapi.SignTransactionResult) {
d.t.Fatalf("Did not expect next-handler to be called")
}
-//TestContextIsCleared tests that the rule-engine does not retain variables over several requests.
+// TestContextIsCleared tests that the rule-engine does not retain variables over several requests.
// if it does, that would be bad since developers may rely on that to store data,
// instead of using the disk-based data storage
func TestContextIsCleared(t *testing.T) {
-
js := `
function ApproveTx(){
if (typeof foobar == 'undefined') {
@@ -580,7 +572,6 @@ func TestContextIsCleared(t *testing.T) {
}
func TestSignData(t *testing.T) {
-
js := `function ApproveListing(){
return "Approve"
}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index e33982764..e069255c9 100644
--- a/tests/state_test_util.go
+++ b/tests/state_test_util.go
@@ -33,6 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/state/snapshot"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
@@ -257,7 +258,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
// - the block body is verified against the header in block_validator.go:ValidateBody
// Here, we just do this shortcut smaller fix, since state tests do not
// utilize those codepaths
- if len(msg.BlobHashes())*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
+ if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
return nil, nil, nil, common.Hash{}, errors.New("blob gas exceeds maximum")
}
}
@@ -287,6 +288,15 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas)
}
evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
+
+ if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil {
+ tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)
+ if evm.Config.Tracer.OnTxEnd != nil {
+ defer func() {
+ evm.Config.Tracer.OnTxEnd(nil, err)
+ }()
+ }
+ }
// Execute the message.
snapshot := statedb.Snapshot()
gaspool := new(core.GasPool)
@@ -300,7 +310,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
// - the coinbase suicided, or
// - there are only 'bad' transactions, which aren't executed. In those cases,
// the coinbase gets no txfee, so isn't created, and thus needs to be touched
- statedb.AddBalance(block.Coinbase(), new(big.Int))
+ statedb.AddBalance(block.Coinbase(), new(big.Int), tracing.BalanceChangeUnspecified)
// Commit block
statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
// And _now_ get the state root
@@ -325,7 +335,7 @@ func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bo
for addr, a := range accounts {
statedb.SetCode(addr, a.Code)
statedb.SetNonce(addr, a.Nonce)
- statedb.SetBalance(addr, a.Balance)
+ statedb.SetBalance(addr, a.Balance, tracing.BalanceChangeUnspecified)
for k, v := range a.Storage {
statedb.SetState(addr, k, v)
}
@@ -353,7 +363,8 @@ func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis {
}
}
-func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Message, error) {
+func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Message, error) {
+ // Derive sender from private key if present.
var from common.Address
// If 'sender' field is present, use that
if tx.Sender != nil {
@@ -438,8 +449,10 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Messa
}
}
- msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice,
- tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false, tx.BlobGasFeeCap, tx.BlobVersionedHashes, authList)
+ msg := core.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice,
+ tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false,
+ tx.BlobGasFeeCap, tx.BlobVersionedHashes, authList,
+ )
return msg, nil
}