diff --git a/cmd/evm/blockrunner.go b/cmd/evm/blockrunner.go
index c5d836e0ea61..0275c019bc61 100644
--- a/cmd/evm/blockrunner.go
+++ b/cmd/evm/blockrunner.go
@@ -26,7 +26,7 @@ import (
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/rawdb"
- "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/tests"
"github.com/urfave/cli/v2"
@@ -51,7 +51,7 @@ func blockTestCmd(ctx *cli.Context) error {
return errors.New("path-to-test argument required")
}
- var tracer vm.EVMLogger
+ var tracer *tracing.Hooks
// Configure the EVM logger
if ctx.Bool(MachineFlag.Name) {
tracer = logger.NewJSONLogger(&logger.Config{
diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go
index 0735a05d6ac2..3c09229e1c5c 100644
--- a/cmd/evm/internal/t8ntool/execution.go
+++ b/cmd/evm/internal/t8ntool/execution.go
@@ -17,7 +17,9 @@
package t8ntool
import (
+ "encoding/json"
"fmt"
+ "io"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -28,9 +30,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"
@@ -119,7 +123,7 @@ type rejectedTx struct {
// Apply applies a set of transactions to a pre-state
func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
txIt txIterator, miningReward int64,
- getTracerFn func(txIndex int, txHash common.Hash) (vm.EVMLogger, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
+ getTracerFn func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error)) (*state.StateDB, *ExecutionResult, []byte, error) {
// Capture errors for BLOCKHASH operation, if we haven't been supplied the
// required blockhashes
var hashError error
@@ -222,11 +226,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
continue
}
}
- tracer, err := getTracerFn(txIndex, tx.Hash())
+ tracer, traceOutput, err := getTracerFn(txIndex, tx.Hash())
if err != nil {
return nil, nil, nil, err
}
- vmConfig.Tracer = tracer
+ if tracer != nil {
+ vmConfig.Tracer = tracer.Hooks
+ }
statedb.SetTxContext(tx.Hash(), txIndex)
var (
@@ -236,6 +242,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
)
evm := vm.NewEVM(vmContext, txContext, statedb, chainConfig, vmConfig)
+ if tracer != nil && tracer.OnTxStart != nil {
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
+ }
// (ret []byte, usedGas uint64, failed bool, err error)
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
if err != nil {
@@ -243,6 +252,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
gaspool.SetGas(prevGas)
+ if tracer != nil {
+ if tracer.OnTxEnd != nil {
+ tracer.OnTxEnd(nil, err)
+ }
+ if err := writeTraceResult(tracer, traceOutput); err != nil {
+ log.Warn("Error writing tracer output", "err", err)
+ }
+ }
continue
}
includedTxs = append(includedTxs, tx)
@@ -285,6 +302,12 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
//receipt.BlockNumber
receipt.TransactionIndex = uint(txIndex)
receipts = append(receipts, receipt)
+ if tracer != nil {
+ if tracer.Hooks.OnTxEnd != nil {
+ tracer.Hooks.OnTxEnd(receipt, nil)
+ }
+ writeTraceResult(tracer, traceOutput)
+ }
}
txIndex++
@@ -310,15 +333,15 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
reward.Sub(reward, new(big.Int).SetUint64(ommer.Delta))
reward.Mul(reward, blockReward)
reward.Div(reward, big.NewInt(8))
- statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward))
+ statedb.AddBalance(ommer.Address, uint256.MustFromBig(reward), tracing.BalanceIncreaseRewardMineUncle)
}
- statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward))
+ statedb.AddBalance(pre.Env.Coinbase, uint256.MustFromBig(minerReward), tracing.BalanceIncreaseRewardMineBlock)
}
// Apply withdrawals
for _, w := range pre.Env.Withdrawals {
// Amount is in gwei, turn into wei
amount := new(big.Int).Mul(new(big.Int).SetUint64(w.Amount), big.NewInt(params.GWei))
- statedb.AddBalance(w.Address, uint256.MustFromBig(amount))
+ statedb.AddBalance(w.Address, uint256.MustFromBig(amount), tracing.BalanceIncreaseWithdrawal)
}
// Commit block
root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber))
@@ -361,7 +384,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, uint256.MustFromBig(a.Balance))
+ statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceIncreaseGenesisBalance)
for k, v := range a.Storage {
statedb.SetState(addr, k, v)
}
@@ -398,3 +421,16 @@ func calcDifficulty(config *params.ChainConfig, number, currentTime, parentTime
}
return ethash.CalcDifficulty(config, currentTime, parent)
}
+
+func writeTraceResult(tracer *tracers.Tracer, f io.WriteCloser) error {
+ defer f.Close()
+ result, err := tracer.GetResult()
+ if err != nil || result == nil {
+ return err
+ }
+ err = json.NewEncoder(f).Encode(result)
+ if err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/cmd/evm/internal/t8ntool/tracewriter.go b/cmd/evm/internal/t8ntool/tracewriter.go
deleted file mode 100644
index e4efad112f74..000000000000
--- a/cmd/evm/internal/t8ntool/tracewriter.go
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2020 The go-ethereum Authors
-// This file is part of go-ethereum.
-//
-// go-ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// go-ethereum 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 General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with go-ethereum. If not, see .
-
-package t8ntool
-
-import (
- "encoding/json"
- "io"
- "math/big"
-
- "github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/eth/tracers"
- "github.com/ethereum/go-ethereum/log"
-)
-
-// traceWriter is an vm.EVMLogger which also holds an inner logger/tracer.
-// When the TxEnd event happens, the inner tracer result is written to the file, and
-// the file is closed.
-type traceWriter struct {
- inner vm.EVMLogger
- f io.WriteCloser
-}
-
-// Compile-time interface check
-var _ = vm.EVMLogger((*traceWriter)(nil))
-
-func (t *traceWriter) CaptureTxEnd(restGas uint64) {
- t.inner.CaptureTxEnd(restGas)
- defer t.f.Close()
-
- if tracer, ok := t.inner.(tracers.Tracer); ok {
- result, err := tracer.GetResult()
- if err != nil {
- log.Warn("Error in tracer", "err", err)
- return
- }
- err = json.NewEncoder(t.f).Encode(result)
- if err != nil {
- log.Warn("Error writing tracer output", "err", err)
- return
- }
- }
-}
-
-func (t *traceWriter) CaptureTxStart(gasLimit uint64) { t.inner.CaptureTxStart(gasLimit) }
-func (t *traceWriter) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
- t.inner.CaptureStart(env, from, to, create, input, gas, value)
-}
-
-func (t *traceWriter) CaptureEnd(output []byte, gasUsed uint64, err error) {
- t.inner.CaptureEnd(output, gasUsed, err)
-}
-
-func (t *traceWriter) CaptureEnter(typ vm.OpCode, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
- t.inner.CaptureEnter(typ, from, to, input, gas, value)
-}
-
-func (t *traceWriter) CaptureExit(output []byte, gasUsed uint64, err error) {
- t.inner.CaptureExit(output, gasUsed, err)
-}
-
-func (t *traceWriter) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, rData []byte, depth int, err error) {
- t.inner.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
-}
-func (t *traceWriter) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope *vm.ScopeContext, depth int, err error) {
- t.inner.CaptureFault(pc, op, gas, cost, scope, depth, err)
-}
diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go
index a9489d069a70..5aa554e13359 100644
--- a/cmd/evm/internal/t8ntool/transition.go
+++ b/cmd/evm/internal/t8ntool/transition.go
@@ -20,6 +20,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "io"
"math/big"
"os"
"path/filepath"
@@ -80,7 +81,7 @@ type input struct {
}
func Transition(ctx *cli.Context) error {
- var getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) { return nil, nil }
+ var getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) { return nil, nil, nil }
baseDir, err := createBasedir(ctx)
if err != nil {
@@ -95,28 +96,35 @@ func Transition(ctx *cli.Context) error {
EnableReturnData: ctx.Bool(TraceEnableReturnDataFlag.Name),
Debug: true,
}
- getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) {
+ 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))
}
- return &traceWriter{logger.NewJSONLogger(logConfig, traceFile), traceFile}, 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
}
} else if ctx.IsSet(TraceTracerFlag.Name) {
var config json.RawMessage
if ctx.IsSet(TraceTracerConfigFlag.Name) {
config = []byte(ctx.String(TraceTracerConfigFlag.Name))
}
- getTracer = func(txIndex int, txHash common.Hash) (vm.EVMLogger, error) {
+ getTracer = func(txIndex int, txHash common.Hash) (*tracers.Tracer, io.WriteCloser, error) {
traceFile, err := os.Create(filepath.Join(baseDir, fmt.Sprintf("trace-%d-%v.json", 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))
}
tracer, err := tracers.DefaultDirectory.New(ctx.String(TraceTracerFlag.Name), nil, config)
if err != nil {
- return nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err))
+ return nil, nil, NewError(ErrorConfig, fmt.Errorf("failed instantiating tracer: %w", err))
}
- return &traceWriter{tracer, traceFile}, nil
+ return tracer, traceFile, nil
}
}
// We need to load three things: alloc, env and transactions. May be either in
diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go
index b8e8b542b7e5..7f6f5f6be0fd 100644
--- a/cmd/evm/runner.go
+++ b/cmd/evm/runner.go
@@ -33,6 +33,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/vm"
"github.com/ethereum/go-ethereum/core/vm/runtime"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
@@ -116,7 +117,7 @@ func runCmd(ctx *cli.Context) error {
}
var (
- tracer vm.EVMLogger
+ tracer *tracing.Hooks
debugLogger *logger.StructLogger
statedb *state.StateDB
chainConfig *params.ChainConfig
@@ -130,7 +131,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 aaf2b00f879d..fc2bf8223f30 100644
--- a/cmd/evm/staterunner.go
+++ b/cmd/evm/staterunner.go
@@ -63,7 +63,7 @@ func stateTestCmd(ctx *cli.Context) error {
cfg.Tracer = logger.NewJSONLogger(config, os.Stderr)
case ctx.Bool(DebugFlag.Name):
- cfg.Tracer = logger.NewStructLogger(config)
+ cfg.Tracer = logger.NewStructLogger(config).Hooks()
}
// Load the test content from the input file
if len(ctx.Args().First()) != 0 {
diff --git a/cmd/evm/t8n_test.go b/cmd/evm/t8n_test.go
index ad36540de56c..7e0bc36cbe40 100644
--- a/cmd/evm/t8n_test.go
+++ b/cmd/evm/t8n_test.go
@@ -17,9 +17,12 @@
package main
import (
+ "bufio"
"encoding/json"
"fmt"
+ "io"
"os"
+ "path/filepath"
"reflect"
"strings"
"testing"
@@ -321,6 +324,107 @@ func TestT8n(t *testing.T) {
}
}
+func lineIterator(path string) func() (string, error) {
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return func() (string, error) { return err.Error(), err }
+ }
+ scanner := bufio.NewScanner(strings.NewReader(string(data)))
+ return func() (string, error) {
+ if scanner.Scan() {
+ return scanner.Text(), nil
+ }
+ if err := scanner.Err(); err != nil {
+ return "", err
+ }
+ return "", io.EOF // scanner gobbles io.EOF, but we want it
+ }
+}
+
+// TestT8nTracing is a test that checks the tracing-output from t8n.
+func TestT8nTracing(t *testing.T) {
+ t.Parallel()
+ tt := new(testT8n)
+ tt.TestCmd = cmdtest.NewTestCmd(t, tt)
+ for i, tc := range []struct {
+ base string
+ input t8nInput
+ expExitCode int
+ extraArgs []string
+ expectedTraces []string
+ }{
+ {
+ base: "./testdata/31",
+ input: t8nInput{
+ "alloc.json", "txs.json", "env.json", "Cancun", "",
+ },
+ extraArgs: []string{"--trace"},
+ expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl"},
+ },
+ {
+ base: "./testdata/31",
+ input: t8nInput{
+ "alloc.json", "txs.json", "env.json", "Cancun", "",
+ },
+ extraArgs: []string{"--trace.tracer", `
+{
+ result: function(){
+ return "hello world"
+ },
+ fault: function(){}
+}`},
+ expectedTraces: []string{"trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json"},
+ },
+ } {
+ args := []string{"t8n"}
+ args = append(args, tc.input.get(tc.base)...)
+ // Place the output somewhere we can find it
+ outdir := t.TempDir()
+ args = append(args, "--output.basedir", outdir)
+ args = append(args, tc.extraArgs...)
+
+ var qArgs []string // quoted args for debugging purposes
+ for _, arg := range args {
+ if len(arg) == 0 {
+ qArgs = append(qArgs, `""`)
+ } else {
+ qArgs = append(qArgs, arg)
+ }
+ }
+ tt.Logf("args: %v\n", strings.Join(qArgs, " "))
+ tt.Run("evm-test", args...)
+ t.Log(string(tt.Output()))
+
+ // Compare the expected traces
+ for _, traceFile := range tc.expectedTraces {
+ haveFn := lineIterator(filepath.Join(outdir, traceFile))
+ wantFn := lineIterator(filepath.Join(tc.base, traceFile))
+
+ for line := 0; ; line++ {
+ want, wErr := wantFn()
+ have, hErr := haveFn()
+ if want != have {
+ t.Fatalf("test %d, trace %v, line %d\nwant: %v\nhave: %v\n",
+ i, traceFile, line, want, have)
+ }
+ if wErr != nil && hErr != nil {
+ break
+ }
+ if wErr != nil {
+ t.Fatal(wErr)
+ }
+ if hErr != nil {
+ t.Fatal(hErr)
+ }
+ t.Logf("%v\n", want)
+ }
+ }
+ if have, want := tt.ExitStatus(), tc.expExitCode; have != want {
+ t.Fatalf("test %d: wrong exit code, have %d, want %d", i, have, want)
+ }
+ }
+}
+
type t9nInput struct {
inTxs string
stFork string
diff --git a/cmd/evm/testdata/31/README.md b/cmd/evm/testdata/31/README.md
new file mode 100644
index 000000000000..305e4f52da07
--- /dev/null
+++ b/cmd/evm/testdata/31/README.md
@@ -0,0 +1 @@
+This test does some EVM execution, and can be used to test the tracers and trace-outputs.
diff --git a/cmd/evm/testdata/31/alloc.json b/cmd/evm/testdata/31/alloc.json
new file mode 100644
index 000000000000..bad5481c4a31
--- /dev/null
+++ b/cmd/evm/testdata/31/alloc.json
@@ -0,0 +1,16 @@
+{
+ "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b" : {
+ "balance" : "0x016345785d8a0000",
+ "code" : "0x",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ },
+ "0x1111111111111111111111111111111111111111" : {
+ "balance" : "0x1",
+ "code" : "0x604060406040604000",
+ "nonce" : "0x00",
+ "storage" : {
+ }
+ }
+}
\ No newline at end of file
diff --git a/cmd/evm/testdata/31/env.json b/cmd/evm/testdata/31/env.json
new file mode 100644
index 000000000000..09b5f12d8834
--- /dev/null
+++ b/cmd/evm/testdata/31/env.json
@@ -0,0 +1,20 @@
+{
+ "currentCoinbase" : "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
+ "currentNumber" : "0x01",
+ "currentTimestamp" : "0x03e8",
+ "currentGasLimit" : "0x1000000000",
+ "previousHash" : "0xe4e2a30b340bec696242b67584264f878600dce98354ae0b6328740fd4ff18da",
+ "currentDataGasUsed" : "0x2000",
+ "parentTimestamp" : "0x00",
+ "parentDifficulty" : "0x00",
+ "parentUncleHash" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "parentBeaconBlockRoot" : "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
+ "currentRandom" : "0x0000000000000000000000000000000000000000000000000000000000020000",
+ "withdrawals" : [
+ ],
+ "parentBaseFee" : "0x08",
+ "parentGasUsed" : "0x00",
+ "parentGasLimit" : "0x1000000000",
+ "parentExcessBlobGas" : "0x1000",
+ "parentBlobGasUsed" : "0x2000"
+}
\ No newline at end of file
diff --git a/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json
new file mode 100644
index 000000000000..cd4bc1ab64cc
--- /dev/null
+++ b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.json
@@ -0,0 +1 @@
+"hello world"
diff --git a/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl
new file mode 100644
index 000000000000..26e5c7ee4ef5
--- /dev/null
+++ b/cmd/evm/testdata/31/trace-0-0x88f5fbd1524731a81e49f637aa847543268a5aaf2a6b32a69d2c6d978c45dcfb.jsonl
@@ -0,0 +1,6 @@
+{"pc":0,"op":96,"gas":"0x13498","gasCost":"0x3","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"PUSH1"}
+{"pc":2,"op":96,"gas":"0x13495","gasCost":"0x3","memSize":0,"stack":["0x40"],"depth":1,"refund":0,"opName":"PUSH1"}
+{"pc":4,"op":96,"gas":"0x13492","gasCost":"0x3","memSize":0,"stack":["0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"}
+{"pc":6,"op":96,"gas":"0x1348f","gasCost":"0x3","memSize":0,"stack":["0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"PUSH1"}
+{"pc":8,"op":0,"gas":"0x1348c","gasCost":"0x0","memSize":0,"stack":["0x40","0x40","0x40","0x40"],"depth":1,"refund":0,"opName":"STOP"}
+{"output":"","gasUsed":"0xc"}
diff --git a/cmd/evm/testdata/31/txs.json b/cmd/evm/testdata/31/txs.json
new file mode 100644
index 000000000000..473c1526f40b
--- /dev/null
+++ b/cmd/evm/testdata/31/txs.json
@@ -0,0 +1,14 @@
+[
+ {
+ "gas": "0x186a0",
+ "gasPrice": "0x600",
+ "input": "0x",
+ "nonce": "0x0",
+ "to": "0x1111111111111111111111111111111111111111",
+ "value": "0x1",
+ "v" : "0x0",
+ "r" : "0x0",
+ "s" : "0x0",
+ "secretKey" : "0x45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8"
+ }
+]
diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go
index 17aab678768d..dc45661eaecb 100644
--- a/cmd/geth/chaincmd.go
+++ b/cmd/geth/chaincmd.go
@@ -99,6 +99,8 @@ if one is set. Otherwise it prints the genesis from the datadir.`,
utils.MetricsInfluxDBBucketFlag,
utils.MetricsInfluxDBOrganizationFlag,
utils.TxLookupLimitFlag,
+ utils.VMTraceFlag,
+ utils.VMTraceConfigFlag,
utils.TransactionHistoryFlag,
utils.StateHistoryFlag,
}, utils.DatabaseFlags),
diff --git a/cmd/geth/config.go b/cmd/geth/config.go
index cf4cdef76ce1..23a2d01e73f7 100644
--- a/cmd/geth/config.go
+++ b/cmd/geth/config.go
@@ -178,6 +178,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
v := ctx.Uint64(utils.OverrideVerkle.Name)
cfg.Eth.OverrideVerkle = &v
}
+
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
// Create gauge with geth system and build information
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index d79d23e22687..8ec70aedf93e 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -42,6 +42,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"
@@ -136,6 +137,8 @@ var (
utils.DeveloperGasLimitFlag,
utils.DeveloperPeriodFlag,
utils.VMEnableDebugFlag,
+ utils.VMTraceFlag,
+ utils.VMTraceConfigFlag,
utils.NetworkIdFlag,
utils.EthStatsURLFlag,
utils.NoCompactionFlag,
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index b38f33b8dd7f..7d78c7b31f49 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -21,6 +21,7 @@ import (
"context"
"crypto/ecdsa"
"encoding/hex"
+ "encoding/json"
"errors"
"fmt"
"math"
@@ -538,7 +539,16 @@ 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)",
+ Category: flags.VMCategory,
+ }
// API options.
RPCGlobalGasCapFlag = &cli.Uint64Flag{
Name: "rpc.gascap",
@@ -1889,6 +1899,18 @@ 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 != "" {
+ var config string
+ if ctx.IsSet(VMTraceConfigFlag.Name) {
+ config = ctx.String(VMTraceConfigFlag.Name)
+ }
+
+ cfg.VMTrace = name
+ cfg.VMTraceConfig = config
+ }
+ }
}
// SetDNSDiscoveryDefaults configures DNS discovery with the given URL if
@@ -2167,12 +2189,25 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
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 != "" {
+ var config json.RawMessage
+ if ctx.IsSet(VMTraceConfigFlag.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
+ }
+ }
// Disable transaction indexing/unindexing by default.
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil)
if err != nil {
Fatalf("Can't create BlockChain: %v", err)
}
+
return chain, chainDb
}
diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go
index 9ffed438a877..4e3fbeb09a7c 100644
--- a/consensus/beacon/consensus.go
+++ b/consensus/beacon/consensus.go
@@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"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/rpc"
@@ -358,7 +359,7 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
// Convert amount from gwei to wei.
amount := new(uint256.Int).SetUint64(w.Amount)
amount = amount.Mul(amount, uint256.NewInt(params.GWei))
- state.AddBalance(w.Address, amount)
+ state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal)
}
// No block reward which is issued by consensus layer instead.
}
diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go
index 5299afa610d0..cc19d12a56ae 100644
--- a/consensus/ethash/consensus.go
+++ b/consensus/ethash/consensus.go
@@ -29,6 +29,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"
@@ -570,7 +571,7 @@ var (
// AccumulateRewards credits the coinbase of the given block with the mining
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
-func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
+func accumulateRewards(config *params.ChainConfig, stateDB *state.StateDB, header *types.Header, uncles []*types.Header) {
// Select the correct block reward based on chain progression
blockReward := FrontierBlockReward
if config.IsByzantium(header.Number) {
@@ -589,10 +590,10 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header
r.Sub(r, hNum)
r.Mul(r, blockReward)
r.Div(r, u256_8)
- state.AddBalance(uncle.Coinbase, r)
+ stateDB.AddBalance(uncle.Coinbase, r, tracing.BalanceIncreaseRewardMineUncle)
r.Div(blockReward, u256_32)
reward.Add(reward, r)
}
- state.AddBalance(header.Coinbase, reward)
+ stateDB.AddBalance(header.Coinbase, reward, tracing.BalanceIncreaseRewardMineBlock)
}
diff --git a/consensus/misc/dao.go b/consensus/misc/dao.go
index e21a44f63de3..45669d0bcec8 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"
"github.com/holiman/uint256"
@@ -81,7 +82,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(uint256.Int))
+ statedb.AddBalance(params.DAORefundContract, statedb.GetBalance(addr), tracing.BalanceIncreaseDaoContract)
+ statedb.SetBalance(addr, new(uint256.Int), tracing.BalanceDecreaseDaoAccount)
}
}
diff --git a/core/blockchain.go b/core/blockchain.go
index 1b41d777329e..12fdcf72456c 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -37,6 +37,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"
@@ -253,6 +254,7 @@ type BlockChain struct {
processor Processor // Block transaction processor interface
forker *ForkChoice
vmConfig vm.Config
+ logger *tracing.Hooks
}
// NewBlockChain returns a fully initialised block chain using information
@@ -295,6 +297,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
txLookupCache: lru.NewCache[common.Hash, txLookup](txLookupCacheLimit),
engine: engine,
vmConfig: vmConfig,
+ logger: vmConfig.Tracer,
}
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
bc.forker = NewForkChoice(bc, shouldPreserve)
@@ -421,6 +424,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
@@ -452,6 +474,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
}
+
// Start tx indexer if it's enabled.
if txLookupLimit != nil {
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
@@ -1783,6 +1806,14 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
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(),
+ Safe: bc.CurrentSafeBlock(),
+ })
+ }
// 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.
@@ -1800,6 +1831,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
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")
@@ -1813,7 +1845,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps)
go func(start time.Time, followup *types.Block, throwaway *state.StateDB) {
- 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 followupInterrupt.Load() {
@@ -1823,68 +1858,15 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
}
}
- // Process block using the parent state as reference point
- pstart := time.Now()
- receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
- if err != nil {
- bc.reportBlock(block, receipts, err)
- followupInterrupt.Store(true)
- return it.index, err
- }
- ptime := time.Since(pstart)
-
- vstart := time.Now()
- if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
- bc.reportBlock(block, receipts, err)
- followupInterrupt.Store(true)
- return it.index, err
- }
- vtime := time.Since(vstart)
- proctime := time.Since(start) // processing + validation
-
- // Update the metrics touched during block processing and validation
- accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
- storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
- snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
- snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
- accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
- storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
- accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
- storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
- triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
- trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
- trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
- trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
- blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
- blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
-
- // Write the block to the chain and get the status.
- var (
- wstart = time.Now()
- status WriteStatus
- )
- if !setHead {
- // Don't set the head, only insert the block
- err = bc.writeBlockWithState(block, receipts, statedb)
- } else {
- status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
- }
+ // The traced section of block import.
+ res, err := bc.processBlock(block, statedb, start, setHead)
followupInterrupt.Store(true)
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) // Trie database commits are complete, we can mark them
-
- blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
- blockInsertTimer.UpdateSince(start)
-
// Report the import stats before returning the various results
stats.processed++
- stats.usedGas += usedGas
+ stats.usedGas += res.usedGas
var snapDiffItems, snapBufItems common.StorageSize
if bc.snaps != nil {
@@ -1896,11 +1878,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
if !setHead {
// After merge we expect few side chains. Simply count
// all blocks the CL gives us for GC processing time
- bc.gcproc += proctime
-
+ bc.gcproc += res.procTime
return it.index, nil // Direct block insertion of a single block
}
- 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(),
@@ -1910,7 +1891,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
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(),
@@ -1931,6 +1912,91 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
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, setHead bool) (_ *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(),
+ Safe: bc.CurrentSafeBlock(),
+ })
+ }
+ if bc.logger != nil && bc.logger.OnBlockEnd != nil {
+ defer func() {
+ bc.logger.OnBlockEnd(blockEndErr)
+ }()
+ }
+
+ // Process block using the parent state as reference point
+ pstart := time.Now()
+ receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
+ if err != nil {
+ bc.reportBlock(block, receipts, err)
+ return nil, err
+ }
+ ptime := time.Since(pstart)
+
+ vstart := time.Now()
+ if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
+ bc.reportBlock(block, receipts, err)
+ return nil, err
+ }
+ vtime := time.Since(vstart)
+ proctime := time.Since(start) // processing + validation
+
+ // Update the metrics touched during block processing and validation
+ accountReadTimer.Update(statedb.AccountReads) // Account reads are complete(in processing)
+ storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete(in processing)
+ snapshotAccountReadTimer.Update(statedb.SnapshotAccountReads) // Account reads are complete(in processing)
+ snapshotStorageReadTimer.Update(statedb.SnapshotStorageReads) // Storage reads are complete(in processing)
+ accountUpdateTimer.Update(statedb.AccountUpdates) // Account updates are complete(in validation)
+ storageUpdateTimer.Update(statedb.StorageUpdates) // Storage updates are complete(in validation)
+ accountHashTimer.Update(statedb.AccountHashes) // Account hashes are complete(in validation)
+ storageHashTimer.Update(statedb.StorageHashes) // Storage hashes are complete(in validation)
+ triehash := statedb.AccountHashes + statedb.StorageHashes // The time spent on tries hashing
+ trieUpdate := statedb.AccountUpdates + statedb.StorageUpdates // The time spent on tries update
+ trieRead := statedb.SnapshotAccountReads + statedb.AccountReads // The time spent on account read
+ trieRead += statedb.SnapshotStorageReads + statedb.StorageReads // The time spent on storage read
+ blockExecutionTimer.Update(ptime - trieRead) // The time spent on EVM processing
+ blockValidationTimer.Update(vtime - (triehash + trieUpdate)) // The time spent on block validation
+
+ // Write the block to the chain and get the status.
+ var (
+ wstart = time.Now()
+ status WriteStatus
+ )
+ if !setHead {
+ // Don't set the head, only insert the block
+ err = bc.writeBlockWithState(block, receipts, statedb)
+ } else {
+ status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
+ }
+ if err != nil {
+ 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) // Trie database commits are complete, we can mark them
+
+ blockWriteTimer.Update(time.Since(wstart) - statedb.AccountCommits - statedb.StorageCommits - statedb.SnapshotCommits - statedb.TrieDBCommits)
+ blockInsertTimer.UpdateSince(start)
+
+ 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 4fa759129c9a..f837397a1dd2 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -4287,7 +4287,7 @@ func TestEIP3651(t *testing.T) {
b.AddTx(tx)
})
- chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{Tracer: logger.NewMarkdownLogger(&logger.Config{}, os.Stderr)}, nil, nil)
+ chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, 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/evm.go b/core/evm.go
index 73f6d7bc20a0..4c12e2aa02c4 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"
"github.com/holiman/uint256"
@@ -136,6 +137,6 @@ func CanTransfer(db vm.StateDB, addr common.Address, amount *uint256.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 *uint256.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 3f1fde8dfca4..ee0e322f8013 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -29,6 +29,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"
@@ -133,7 +134,7 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
}
for addr, account := range *ga {
if account.Balance != nil {
- statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
+ statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance)
}
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
@@ -154,7 +155,9 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
}
for addr, account := range *ga {
if account.Balance != nil {
- statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
+ // This is not actually logged via tracer because OnGenesisBlock
+ // already captures the allocations.
+ statedb.AddBalance(addr, uint256.MustFromBig(account.Balance), tracing.BalanceIncreaseGenesisBalance)
}
statedb.SetCode(addr, account.Code)
statedb.SetNonce(addr, account.Nonce)
@@ -181,6 +184,39 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
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()
+ case params.HoleskyGenesisHash:
+ genesis = DefaultHoleskyGenesisBlock()
+ }
+ if genesis != nil {
+ return genesis.Alloc, nil
+ }
+
+ return nil, nil
+}
+
// field type overrides for gencodec
type genesisSpecMarshaling struct {
Nonce math.HexOrDecimal64
@@ -252,6 +288,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
} else {
log.Info("Writing custom genesis block")
}
+
applyOverrides(genesis.Config)
block, err := genesis.Commit(db, triedb)
if err != nil {
diff --git a/core/state/dump.go b/core/state/dump.go
index 55abb50f1c5a..c9aad4f8e234 100644
--- a/core/state/dump.go
+++ b/core/state/dump.go
@@ -57,7 +57,6 @@ type DumpAccount struct {
Storage map[common.Hash]string `json:"storage,omitempty"`
Address *common.Address `json:"address,omitempty"` // Address only present in iterative (line-by-line) mode
AddressHash hexutil.Bytes `json:"key,omitempty"` // If we don't have address, we can output the key
-
}
// Dump represents the full dump in a collected format, as one large map.
diff --git a/core/state/state_object.go b/core/state/state_object.go
index 6dea68465baa..910f4963411d 100644
--- a/core/state/state_object.go
+++ b/core/state/state_object.go
@@ -23,6 +23,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/rlp"
@@ -240,6 +241,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)
}
@@ -399,7 +403,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 *uint256.Int) {
+func (s *stateObject) AddBalance(amount *uint256.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.IsZero() {
@@ -408,23 +412,26 @@ func (s *stateObject) AddBalance(amount *uint256.Int) {
}
return
}
- s.SetBalance(new(uint256.Int).Add(s.Balance(), amount))
+ s.SetBalance(new(uint256.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 *uint256.Int) {
+func (s *stateObject) SubBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) {
if amount.IsZero() {
return
}
- s.SetBalance(new(uint256.Int).Sub(s.Balance(), amount))
+ s.SetBalance(new(uint256.Int).Sub(s.Balance(), amount), reason)
}
-func (s *stateObject) SetBalance(amount *uint256.Int) {
+func (s *stateObject) SetBalance(amount *uint256.Int, reason tracing.BalanceChangeReason) {
s.db.journal.append(balanceChange{
account: &s.address,
prev: new(uint256.Int).Set(s.data.Balance),
})
+ if s.db.logger != nil && s.db.logger.OnBalanceChange != nil {
+ s.db.logger.OnBalanceChange(s.address, s.Balance().ToBig(), amount.ToBig(), reason)
+ }
s.setBalance(amount)
}
@@ -502,6 +509,9 @@ func (s *stateObject) SetCode(codeHash common.Hash, code []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)
}
@@ -516,6 +526,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 9be610f962d5..c6e6db906e8c 100644
--- a/core/state/state_test.go
+++ b/core/state/state_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"
@@ -49,11 +50,11 @@ func TestDump(t *testing.T) {
// generate a few entries
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
- obj1.AddBalance(uint256.NewInt(22))
+ obj1.AddBalance(uint256.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(uint256.NewInt(44))
+ obj3.SetBalance(uint256.NewInt(44), tracing.BalanceChangeUnspecified)
// write some of them to the trie
s.state.updateStateObject(obj1)
@@ -106,13 +107,13 @@ func TestIterativeDump(t *testing.T) {
// generate a few entries
obj1 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x01}))
- obj1.AddBalance(uint256.NewInt(22))
+ obj1.AddBalance(uint256.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(uint256.NewInt(44))
+ obj3.SetBalance(uint256.NewInt(44), tracing.BalanceChangeUnspecified)
obj4 := s.state.getOrNewStateObject(common.BytesToAddress([]byte{0x00}))
- obj4.AddBalance(uint256.NewInt(1337))
+ obj4.AddBalance(uint256.NewInt(1337), tracing.BalanceChangeUnspecified)
// write some of them to the trie
s.state.updateStateObject(obj1)
@@ -208,7 +209,7 @@ func TestSnapshot2(t *testing.T) {
// db, trie are already non-empty values
so0 := state.getStateObject(stateobjaddr0)
- so0.SetBalance(uint256.NewInt(42))
+ so0.SetBalance(uint256.NewInt(42), tracing.BalanceChangeUnspecified)
so0.SetNonce(43)
so0.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e'}), []byte{'c', 'a', 'f', 'e'})
so0.selfDestructed = false
@@ -220,7 +221,7 @@ func TestSnapshot2(t *testing.T) {
// and one with deleted == true
so1 := state.getStateObject(stateobjaddr1)
- so1.SetBalance(uint256.NewInt(52))
+ so1.SetBalance(uint256.NewInt(52), tracing.BalanceChangeUnspecified)
so1.SetNonce(53)
so1.SetCode(crypto.Keccak256Hash([]byte{'c', 'a', 'f', 'e', '2'}), []byte{'c', 'a', 'f', 'e', '2'})
so1.selfDestructed = true
diff --git a/core/state/statedb.go b/core/state/statedb.go
index f90b30f3994e..24914927c29b 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -19,12 +19,14 @@ package state
import (
"fmt"
+ "math/big"
"sort"
"time"
"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"
@@ -56,6 +58,7 @@ type StateDB struct {
prefetcher *triePrefetcher
trie Trie
hasher crypto.KeccakState
+ logger *tracing.Hooks
snaps *snapshot.Tree // Nil if snapshot is not available
snap snapshot.Snapshot // Nil if snapshot is not available
@@ -165,6 +168,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.
@@ -205,6 +213,9 @@ func (s *StateDB) AddLog(log *types.Log) {
log.TxHash = s.thash
log.TxIndex = uint(s.txIndex)
log.Index = s.logSize
+ if s.logger != nil && s.logger.OnLog != nil {
+ s.logger.OnLog(log)
+ }
s.logs[s.thash] = append(s.logs[s.thash], log)
s.logSize++
}
@@ -366,25 +377,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 *uint256.Int) {
+func (s *StateDB) AddBalance(addr common.Address, amount *uint256.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 *uint256.Int) {
+func (s *StateDB) SubBalance(addr common.Address, amount *uint256.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 *uint256.Int) {
+func (s *StateDB) SetBalance(addr common.Address, amount *uint256.Int, reason tracing.BalanceChangeReason) {
stateObject := s.getOrNewStateObject(addr)
if stateObject != nil {
- stateObject.SetBalance(amount)
+ stateObject.SetBalance(amount, reason)
}
}
@@ -440,13 +451,20 @@ func (s *StateDB) SelfDestruct(addr common.Address) {
if stateObject == nil {
return
}
+ var (
+ prev = new(uint256.Int).Set(stateObject.Balance())
+ n = new(uint256.Int)
+ )
s.journal.append(selfDestructChange{
account: &addr,
prev: stateObject.selfDestructed,
- prevbalance: new(uint256.Int).Set(stateObject.Balance()),
+ prevbalance: prev,
})
+ if s.logger != nil && s.logger.OnBalanceChange != nil && prev.Sign() > 0 {
+ s.logger.OnBalanceChange(addr, prev.ToBig(), n.ToBig(), tracing.BalanceDecreaseSelfdestruct)
+ }
stateObject.markSelfdestructed()
- stateObject.data.Balance = new(uint256.Int)
+ stateObject.data.Balance = n
}
func (s *StateDB) Selfdestruct6780(addr common.Address) {
@@ -823,6 +841,10 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
if obj.selfDestructed || (deleteEmptyObjects && obj.empty()) {
obj.deleted = true
+ // 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.ToBig(), 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 b416bcf1f312..65cf278108f5 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/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/rlp"
@@ -61,7 +62,7 @@ func newStateTestAction(addr common.Address, r *rand.Rand, index int) testAction
{
name: "SetBalance",
fn: func(a testAction, s *StateDB) {
- s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])))
+ s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])), tracing.BalanceChangeUnspecified)
},
args: make([]int64, 1),
},
diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go
index 3649b0ac589b..bc8c63447963 100644
--- a/core/state/statedb_test.go
+++ b/core/state/statedb_test.go
@@ -32,6 +32,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/rlp"
@@ -56,7 +57,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, uint256.NewInt(uint64(11*i)))
+ state.AddBalance(addr, uint256.NewInt(uint64(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}))
@@ -91,7 +92,7 @@ func TestIntermediateLeaks(t *testing.T) {
finalState, _ := New(types.EmptyRootHash, NewDatabaseWithNodeDB(finalDb, finalNdb), nil)
modify := func(state *StateDB, addr common.Address, i, tweak byte) {
- state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(tweak)))
+ state.SetBalance(addr, uint256.NewInt(uint64(11*i)+uint64(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{})
@@ -167,7 +168,7 @@ func TestCopy(t *testing.T) {
for i := byte(0); i < 255; i++ {
obj := orig.getOrNewStateObject(common.BytesToAddress([]byte{i}))
- obj.AddBalance(uint256.NewInt(uint64(i)))
+ obj.AddBalance(uint256.NewInt(uint64(i)), tracing.BalanceChangeUnspecified)
orig.updateStateObject(obj)
}
orig.Finalise(false)
@@ -184,9 +185,9 @@ func TestCopy(t *testing.T) {
copyObj := copy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
ccopyObj := ccopy.getOrNewStateObject(common.BytesToAddress([]byte{i}))
- origObj.AddBalance(uint256.NewInt(2 * uint64(i)))
- copyObj.AddBalance(uint256.NewInt(3 * uint64(i)))
- ccopyObj.AddBalance(uint256.NewInt(4 * uint64(i)))
+ origObj.AddBalance(uint256.NewInt(2*uint64(i)), tracing.BalanceChangeUnspecified)
+ copyObj.AddBalance(uint256.NewInt(3*uint64(i)), tracing.BalanceChangeUnspecified)
+ ccopyObj.AddBalance(uint256.NewInt(4*uint64(i)), tracing.BalanceChangeUnspecified)
orig.updateStateObject(origObj)
copy.updateStateObject(copyObj)
@@ -266,14 +267,14 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction {
{
name: "SetBalance",
fn: func(a testAction, s *StateDB) {
- s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])))
+ s.SetBalance(addr, uint256.NewInt(uint64(a.args[0])), tracing.BalanceChangeUnspecified)
},
args: make([]int64, 1),
},
{
name: "AddBalance",
fn: func(a testAction, s *StateDB) {
- s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])))
+ s.AddBalance(addr, uint256.NewInt(uint64(a.args[0])), tracing.BalanceChangeUnspecified)
},
args: make([]int64, 1),
},
@@ -536,7 +537,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(uint256.Int))
+ s.state.AddBalance(common.Address{}, new(uint256.Int), tracing.BalanceChangeUnspecified)
if len(s.state.journal.dirties) != 1 {
t.Fatal("expected one dirty state object")
@@ -552,7 +553,7 @@ func TestTouchDelete(t *testing.T) {
func TestCopyOfCopy(t *testing.T) {
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
addr := common.HexToAddress("aaaa")
- state.SetBalance(addr, uint256.NewInt(42))
+ state.SetBalance(addr, uint256.NewInt(42), tracing.BalanceChangeUnspecified)
if got := state.Copy().GetBalance(addr).Uint64(); got != 42 {
t.Fatalf("1st copy fail, expected 42, got %v", got)
@@ -575,9 +576,9 @@ func TestCopyCommitCopy(t *testing.T) {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, uint256.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, uint256.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(uint256.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
@@ -648,9 +649,9 @@ func TestCopyCopyCommitCopy(t *testing.T) {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, uint256.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, uint256.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(uint256.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
@@ -717,9 +718,9 @@ func TestCommitCopy(t *testing.T) {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, uint256.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, uint256.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(uint256.NewInt(42)) != 0 {
t.Fatalf("initial balance mismatch: have %v, want %v", balance, 42)
@@ -766,7 +767,7 @@ func TestDeleteCreateRevert(t *testing.T) {
state, _ := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), nil)
addr := common.BytesToAddress([]byte("so"))
- state.SetBalance(addr, uint256.NewInt(1))
+ state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
root, _ := state.Commit(0, false)
state, _ = New(root, state.db, state.snaps)
@@ -776,7 +777,7 @@ func TestDeleteCreateRevert(t *testing.T) {
state.Finalise(true)
id := state.Snapshot()
- state.SetBalance(addr, uint256.NewInt(2))
+ state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified)
state.RevertToSnapshot(id)
// Commit the entire state and make sure we don't crash and have the correct state
@@ -818,10 +819,10 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
state, _ := New(types.EmptyRootHash, db, nil)
addr := common.BytesToAddress([]byte("so"))
{
- state.SetBalance(addr, uint256.NewInt(1))
+ state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
state.SetCode(addr, []byte{1, 2, 3})
a2 := common.BytesToAddress([]byte("another"))
- state.SetBalance(a2, uint256.NewInt(100))
+ state.SetBalance(a2, uint256.NewInt(100), tracing.BalanceChangeUnspecified)
state.SetCode(a2, []byte{1, 2, 4})
root, _ = state.Commit(0, false)
t.Logf("root: %x", root)
@@ -846,7 +847,7 @@ func testMissingTrieNodes(t *testing.T, scheme string) {
t.Errorf("expected %d, got %d", exp, got)
}
// Modify the state
- state.SetBalance(addr, uint256.NewInt(2))
+ state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified)
root, err := state.Commit(0, false)
if err == nil {
t.Fatalf("expected error, got root :%x", root)
@@ -1114,13 +1115,13 @@ func TestResetObject(t *testing.T) {
slotB = common.HexToHash("0x2")
)
// Initialize account with balance and storage in first transaction.
- state.SetBalance(addr, uint256.NewInt(1))
+ state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
state.SetState(addr, slotA, common.BytesToHash([]byte{0x1}))
state.IntermediateRoot(true)
// Reset account and mutate balance and storages
state.CreateAccount(addr)
- state.SetBalance(addr, uint256.NewInt(2))
+ state.SetBalance(addr, uint256.NewInt(2), tracing.BalanceChangeUnspecified)
state.SetState(addr, slotB, common.BytesToHash([]byte{0x2}))
root, _ := state.Commit(0, true)
@@ -1146,7 +1147,7 @@ func TestDeleteStorage(t *testing.T) {
addr = common.HexToAddress("0x1")
)
// Initialize account and populate storage
- state.SetBalance(addr, uint256.NewInt(1))
+ state.SetBalance(addr, uint256.NewInt(1), tracing.BalanceChangeUnspecified)
state.CreateAccount(addr)
for i := 0; i < 1000; i++ {
slot := common.Hash(uint256.NewInt(uint64(i)).Bytes32())
diff --git a/core/state/sync_test.go b/core/state/sync_test.go
index 052c166578f7..b7039c9e1cb7 100644
--- a/core/state/sync_test.go
+++ b/core/state/sync_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"
@@ -61,7 +62,7 @@ func makeTestState(scheme string) (ethdb.Database, Database, *triedb.Database, c
obj := state.getOrNewStateObject(common.BytesToAddress([]byte{i}))
acc := &testAccount{address: common.BytesToAddress([]byte{i})}
- obj.AddBalance(uint256.NewInt(uint64(11 * i)))
+ obj.AddBalance(uint256.NewInt(uint64(11*i)), tracing.BalanceChangeUnspecified)
acc.balance = uint256.NewInt(uint64(11 * i))
obj.SetNonce(uint64(42 * i))
diff --git a/core/state/trie_prefetcher_test.go b/core/state/trie_prefetcher_test.go
index 711ec832505a..a616adf98f3a 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"
"github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256"
)
@@ -35,9 +36,9 @@ func filledStateDB() *StateDB {
skey := common.HexToHash("aaa")
sval := common.HexToHash("bbb")
- state.SetBalance(addr, uint256.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, uint256.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_processor.go b/core/state_processor.go
index 9c8beaa7f5cc..b1a8938f677a 100644
--- a/core/state_processor.go
+++ b/core/state_processor.go
@@ -67,6 +67,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
allLogs []*types.Log
gp = new(GasPool).AddGas(block.GasLimit())
)
+
// 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)
@@ -86,7 +87,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
statedb.SetTxContext(tx.Hash(), i)
- receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
+
+ receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
@@ -104,7 +106,18 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return receipts, allLogs, *usedGas, nil
}
-func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (*types.Receipt, error) {
+// ApplyTransactionWithEVM attempts to apply a transaction to the given state database
+// and uses the input parameters for its environment similar to ApplyTransaction. However,
+// this method takes an already created EVM instance as input.
+func ApplyTransactionWithEVM(msg *Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, evm *vm.EVM) (receipt *types.Receipt, err error) {
+ if evm.Config.Tracer != nil && evm.Config.Tracer.OnTxStart != nil {
+ evm.Config.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
+ 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)
@@ -126,7 +139,7 @@ func applyTransaction(msg *Message, config *params.ChainConfig, gp *GasPool, sta
// 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 = &types.Receipt{Type: tx.Type(), PostState: root, CumulativeGasUsed: *usedGas}
if result.Failed() {
receipt.Status = types.ReceiptStatusFailed
} else {
@@ -167,7 +180,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
blockContext := NewEVMBlockContext(header, bc, author)
txContext := NewEVMTxContext(msg)
vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg)
- return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
+ return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv)
}
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
diff --git a/core/state_transition.go b/core/state_transition.go
index 8fcf4c093dbc..a52e24dc4395 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common"
cmath "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/crypto/kzg4844"
@@ -263,11 +264,15 @@ func (st *StateTransition) buyGas() error {
if err := st.gp.SubGas(st.msg.GasLimit); err != nil {
return err
}
+
+ if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil {
+ st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance)
+ }
st.gasRemaining = st.msg.GasLimit
st.initialGas = st.msg.GasLimit
mgvalU256, _ := uint256.FromBig(mgval)
- st.state.SubBalance(st.msg.From, mgvalU256)
+ st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy)
return nil
}
@@ -380,13 +385,6 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, err
}
- if tracer := st.evm.Config.Tracer; tracer != nil {
- tracer.CaptureTxStart(st.initialGas)
- defer func() {
- tracer.CaptureTxEnd(st.gasRemaining)
- }()
- }
-
var (
msg = st.msg
sender = vm.AccountRef(msg.From)
@@ -402,6 +400,9 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
if st.gasRemaining < gas {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
}
+ if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil {
+ t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas)
+ }
st.gasRemaining -= gas
// Check clause 6
@@ -456,7 +457,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
} else {
fee := new(uint256.Int).SetUint64(st.gasUsed())
fee.Mul(fee, effectiveTipU256)
- st.state.AddBalance(st.evm.Context.Coinbase, fee)
+ st.state.AddBalance(st.evm.Context.Coinbase, fee, tracing.BalanceIncreaseRewardTransactionFee)
}
return &ExecutionResult{
@@ -473,12 +474,21 @@ func (st *StateTransition) refundGas(refundQuotient uint64) 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.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds)
+ }
+
st.gasRemaining += refund
// Return ETH for remaining gas, exchanged at the original rate.
remaining := uint256.NewInt(st.gasRemaining)
remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice))
- st.state.AddBalance(st.msg.From, remaining)
+ st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn)
+
+ if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 {
+ st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned)
+ }
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go
new file mode 100644
index 000000000000..48cb4d20275c
--- /dev/null
+++ b/core/tracing/hooks.go
@@ -0,0 +1,275 @@
+// 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
+
+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) *uint256.Int
+ GetNonce(common.Address) uint64
+ GetCode(common.Address) []byte
+ GetState(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
+ Random *common.Hash
+ // 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
+ Safe *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.
+ EnterHook = func(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int)
+
+ // 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`.
+ 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)
+
+ // 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)
+
+ /*
+ - 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)
+
+ // 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)
+)
+
+type Hooks struct {
+ // VM events
+ OnTxStart TxStartHook
+ OnTxEnd TxEndHook
+ OnEnter EnterHook
+ OnExit ExitHook
+ OnOpcode OpcodeHook
+ OnFault FaultHook
+ OnGasChange GasChangeHook
+ // Chain events
+ OnBlockchainInit BlockchainInitHook
+ OnBlockStart BlockStartHook
+ OnBlockEnd BlockEndHook
+ OnSkippedBlock SkippedBlockHook
+ OnGenesisBlock GenesisBlockHook
+ // State events
+ OnBalanceChange BalanceChangeHook
+ OnNonceChange NonceChangeHook
+ OnCodeChange CodeChangeHook
+ OnStorageChange StorageChangeHook
+ OnLog LogHook
+}
+
+// BalanceChangeReason is used to indicate the reason for a balance change, useful
+// for tracing and reporting.
+type BalanceChangeReason byte
+
+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
+)
+
+// 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
+
+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
+ // GasChangeContractCreation 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
+
+ // 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
+)
diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go
index 279750c73f2a..85e13980bee6 100644
--- a/core/txpool/blobpool/blobpool_test.go
+++ b/core/txpool/blobpool/blobpool_test.go
@@ -35,6 +35,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"
@@ -545,19 +546,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), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(gapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(dangler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(filler.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.SetNonce(crypto.PubkeyToAddress(filler.PublicKey), 3)
- statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(overlapper.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.SetNonce(crypto.PubkeyToAddress(overlapper.PublicKey), 2)
- statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000))
- statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000))
- statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000))
+ statedb.AddBalance(crypto.PubkeyToAddress(underpayer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(outpricer.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(exceeder.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(overdrafter.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(overcapper.PublicKey), uint256.NewInt(10000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(duplicater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(crypto.PubkeyToAddress(repeater.PublicKey), uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -676,7 +677,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, uint256.NewInt(1_000_000_000))
+ statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -776,9 +777,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, uint256.NewInt(1_000_000_000))
- statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000))
- statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000))
+ statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -856,9 +857,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, uint256.NewInt(1_000_000_000))
- statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000))
- statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000))
+ statedb.AddBalance(addr1, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr2, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
+ statedb.AddBalance(addr3, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
statedb.Commit(0, true)
chain := &testBlockChain{
@@ -1272,7 +1273,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(uint256.Int).SetUint64(seed.balance))
+ statedb.AddBalance(addrs[acc], new(uint256.Int).SetUint64(seed.balance), tracing.BalanceChangeUnspecified)
statedb.SetNonce(addrs[acc], seed.nonce)
// Sign the seed transactions and store them in the data store
@@ -1352,7 +1353,7 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
if err != nil {
b.Fatal(err)
}
- statedb.AddBalance(addr, uint256.NewInt(1_000_000_000))
+ statedb.AddBalance(addr, uint256.NewInt(1_000_000_000), tracing.BalanceChangeUnspecified)
pool.add(tx)
}
statedb.Commit(0, true)
diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go
index c8d3a76b83ff..fd961d1d925c 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"
@@ -50,7 +51,7 @@ func fillPool(t testing.TB, pool *LegacyPool) {
nonExecutableTxs := types.Transactions{}
for i := 0; i < 384; i++ {
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(10000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.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))
@@ -92,7 +93,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), uint256.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.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), uint256.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.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))
@@ -183,7 +184,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), uint256.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified)
futureTxs = append(futureTxs, pricedTransaction(1000+uint64(j), 21000, big.NewInt(500), key))
pool.addRemotesSync(futureTxs)
}
@@ -191,7 +192,7 @@ func TestTransactionZAttack(t *testing.T) {
overDraftTxs := types.Transactions{}
{
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified)
for j := 0; j < int(pool.config.GlobalSlots); j++ {
overDraftTxs = append(overDraftTxs, pricedValuedTransaction(uint64(j), 600000000000, 21000, big.NewInt(500), key))
}
@@ -228,7 +229,7 @@ func BenchmarkFutureAttack(b *testing.B) {
fillPool(b, pool)
key, _ := crypto.GenerateKey()
- pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000))
+ pool.currentState.AddBalance(crypto.PubkeyToAddress(key.PublicKey), uint256.NewInt(100000000000), tracing.BalanceChangeUnspecified)
futureTxs := types.Transactions{}
for n := 0; n < b.N; n++ {
diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go
index 7ffbf745bb8e..68d7b6f411fa 100644
--- a/core/txpool/legacypool/legacypool_test.go
+++ b/core/txpool/legacypool/legacypool_test.go
@@ -33,6 +33,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"
@@ -253,7 +254,7 @@ func (c *testChain) State() (*state.StateDB, error) {
c.statedb, _ = state.New(types.EmptyRootHash, 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(uint256.Int).SetUint64(params.Ether))
+ c.statedb.SetBalance(c.address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified)
*c.trigger = false
}
return stdb, nil
@@ -273,7 +274,7 @@ func TestStateChangeDuringReset(t *testing.T) {
)
// setup pool with 2 transaction in it
- statedb.SetBalance(address, new(uint256.Int).SetUint64(params.Ether))
+ statedb.SetBalance(address, new(uint256.Int).SetUint64(params.Ether), tracing.BalanceChangeUnspecified)
blockchain := &testChain{newTestBlockChain(params.TestChainConfig, 1000000000, statedb, new(event.Feed)), address, &trigger}
tx0 := transaction(0, 100000, key)
@@ -307,7 +308,7 @@ func TestStateChangeDuringReset(t *testing.T) {
func testAddBalance(pool *LegacyPool, addr common.Address, amount *big.Int) {
pool.mu.Lock()
- pool.currentState.AddBalance(addr, uint256.MustFromBig(amount))
+ pool.currentState.AddBalance(addr, uint256.MustFromBig(amount), tracing.BalanceChangeUnspecified)
pool.mu.Unlock()
}
@@ -468,7 +469,7 @@ func TestChainFork(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- statedb.AddBalance(addr, uint256.NewInt(100000000000000))
+ statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
<-pool.requestReset(nil, nil)
@@ -497,7 +498,7 @@ func TestDoubleNonce(t *testing.T) {
addr := crypto.PubkeyToAddress(key.PublicKey)
resetState := func() {
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- statedb.AddBalance(addr, uint256.NewInt(100000000000000))
+ statedb.AddBalance(addr, uint256.NewInt(100000000000000), tracing.BalanceChangeUnspecified)
pool.chain = newTestBlockChain(pool.chainconfig, 1000000, statedb, new(event.Feed))
<-pool.requestReset(nil, nil)
@@ -2660,7 +2661,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, uint256.NewInt(1000000))
+ pool.currentState.AddBalance(account, uint256.NewInt(1000000), tracing.BalanceChangeUnspecified)
tx := transaction(uint64(0), 100000, key)
batches[i] = tx
}
diff --git a/core/vm/contract.go b/core/vm/contract.go
index 16b669ebca27..4e28260a67b7 100644
--- a/core/vm/contract.go
+++ b/core/vm/contract.go
@@ -18,6 +18,7 @@ package vm
import (
"github.com/ethereum/go-ethereum/common"
+ "github.com/ethereum/go-ethereum/core/tracing"
"github.com/holiman/uint256"
)
@@ -157,14 +158,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 33a867654e71..a6af31f58456 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -25,6 +25,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/crypto"
"github.com/ethereum/go-ethereum/crypto/blake2b"
"github.com/ethereum/go-ethereum/crypto/bls12381"
@@ -168,11 +169,14 @@ func ActivePrecompiles(rules params.Rules) []common.Address {
// - 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
diff --git a/core/vm/contracts_fuzz_test.go b/core/vm/contracts_fuzz_test.go
index 87c1fff7cc81..1e5cc8007471 100644
--- a/core/vm/contracts_fuzz_test.go
+++ b/core/vm/contracts_fuzz_test.go
@@ -36,7 +36,7 @@ func FuzzPrecompiledContracts(f *testing.F) {
return
}
inWant := string(input)
- RunPrecompiledContract(p, input, gas)
+ RunPrecompiledContract(p, input, gas, nil)
if inHave := string(input); inWant != inHave {
t.Errorf("Precompiled %v modified input data", a)
}
diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go
index fc30541d4596..6608ff09fcfb 100644
--- a/core/vm/contracts_test.go
+++ b/core/vm/contracts_test.go
@@ -98,7 +98,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))
@@ -120,7 +120,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)
}
@@ -137,7 +137,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)
}
@@ -169,7 +169,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))
diff --git a/core/vm/errors.go b/core/vm/errors.go
index 004f8ef1c83c..ba3261c797fc 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
@@ -70,3 +71,122 @@ type ErrInvalidOpCode struct {
}
func (e *ErrInvalidOpCode) Error() string { return fmt.Sprintf("invalid opcode: %s", e.opcode) }
+
+// rpcError is the same interface as the one defined in rpc/errors.go
+// but we do not want to depend on rpc package here so we redefine it.
+//
+// It's used to ensure that the VMError implements the RPC error interface.
+type rpcError interface {
+ Error() string // returns the message
+ ErrorCode() int // returns the code
+}
+
+var _ rpcError = (*VMError)(nil)
+
+// 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 16cc8549080a..25b5bc84e8bd 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -17,10 +17,12 @@
package vm
import (
+ "errors"
"math/big"
"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/crypto"
"github.com/ethereum/go-ethereum/params"
@@ -177,6 +179,13 @@ func (evm *EVM) Interpreter() *EVMInterpreter {
// 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 *uint256.Int) (ret []byte, leftOverGas uint64, err error) {
+ // 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.ToBig())
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
+ }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -187,44 +196,18 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
snapshot := evm.StateDB.Snapshot()
p, isPrecompile := evm.precompile(addr)
- debug := evm.Config.Tracer != nil
if !evm.StateDB.Exist(addr) {
if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() {
- // 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.ToBig())
- evm.Config.Tracer.CaptureEnd(ret, 0, nil)
- } else {
- evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value.ToBig())
- evm.Config.Tracer.CaptureExit(ret, 0, nil)
- }
- }
+ // Calling a non-existing account, don't do anything.
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.ToBig())
- defer func(startGas uint64) { // Lazy evaluation of the parameters
- evm.Config.Tracer.CaptureEnd(ret, startGas-gas, err)
- }(gas)
- } else {
- // Handle tracer events for entering and exiting a call frame
- evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value.ToBig())
- 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.
@@ -242,11 +225,15 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
}
// When an error was returned by the EVM or when setting the creation code
- // above we revert to the snapshot and consume any gas remaining. Additionally
+ // above we revert to the snapshot and consume any gas remaining. Additionally,
// when we're in homestead this also counts for code storage gas errors.
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:
@@ -264,6 +251,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 *uint256.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.ToBig())
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
+ }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -277,17 +271,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
}
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.ToBig())
- defer func(startGas uint64) {
- evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
- }(gas)
- }
-
// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(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.
@@ -300,6 +286,10 @@ 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
}
}
@@ -312,27 +302,26 @@ 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) {
- // Fail if we're trying to execute above the call depth limit
- if evm.depth > int(params.CallCreateDepth) {
- 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.ToBig())
+ evm.captureBegin(evm.depth, DELEGATECALL, caller.Address(), addr, input, gas, parent.value.ToBig())
defer func(startGas uint64) {
- evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
}(gas)
}
+ // Fail if we're trying to execute above the call depth limit
+ if evm.depth > int(params.CallCreateDepth) {
+ return nil, gas, ErrDepth
+ }
+ var snapshot = evm.StateDB.Snapshot()
// It is allowed to call precompiles, even via delegatecall
if p, isPrecompile := evm.precompile(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
@@ -344,6 +333,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
}
}
@@ -355,6 +347,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)
+ }
// Fail if we're trying to execute above the call depth limit
if evm.depth > int(params.CallCreateDepth) {
return nil, gas, ErrDepth
@@ -370,18 +369,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// 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, new(uint256.Int))
-
- // 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, new(uint256.Int), tracing.BalanceChangeTouchAccount)
if p, isPrecompile := evm.precompile(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'
@@ -400,6 +391,10 @@ 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
}
}
@@ -419,7 +414,13 @@ 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 *uint256.Int, address common.Address, typ OpCode) ([]byte, common.Address, uint64, error) {
+func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64, value *uint256.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.ToBig())
+ defer func(startGas uint64) {
+ evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err)
+ }(gas)
+ }
// Depth check execution. Fail if we're trying to execute above the
// limit.
if evm.depth > int(params.CallCreateDepth) {
@@ -441,6 +442,10 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
// Ensure there's no existing contract already at the designated address
contractHash := evm.StateDB.GetCodeHash(address)
if evm.StateDB.GetNonce(address) != 0 || (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) {
+ 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
@@ -456,15 +461,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
contract := NewContract(caller, AccountRef(address), value, gas)
contract.SetCodeOptionalHash(&address, codeAndHash)
- if evm.Config.Tracer != nil {
- if evm.depth == 0 {
- evm.Config.Tracer.CaptureStart(evm, caller.Address(), address, true, codeAndHash.code, gas, value.ToBig())
- } else {
- evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value.ToBig())
- }
- }
-
- 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 && evm.chainRules.IsEIP158 && len(ret) > params.MaxCodeSize {
@@ -482,7 +479,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
@@ -490,22 +487,15 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
}
// When an error was returned by the EVM or when setting the creation code
- // above we revert to the snapshot and consume any gas remaining. Additionally
+ // above we revert to the snapshot and consume any gas remaining. Additionally,
// when we're in homestead this also counts for code storage gas errors.
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 evm.Config.Tracer != nil {
- 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
}
@@ -527,3 +517,44 @@ func (evm *EVM) Create2(caller ContractRef, code []byte, gas uint64, endowment *
// ChainConfig returns the environment's chain configuration
func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig }
+
+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)
+ }
+ 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,
+ Random: evm.Context.Random,
+ GasPrice: evm.TxContext.GasPrice,
+ ChainConfig: evm.ChainConfig(),
+ StateDB: evm.StateDB,
+ }
+}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index ac3ea4bcd62b..990bdbf925ad 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -20,6 +20,7 @@ import (
"math"
"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/params"
@@ -249,7 +250,6 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
if evm.Config.EnablePreimageRecording {
evm.StateDB.AddPreimage(interpreter.hasherBuf, data)
}
-
size.SetBytes(interpreter.hasherBuf[:])
return nil, nil
}
@@ -590,7 +590,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// reuse size int for stackvalue
stackvalue := size
- scope.Contract.UseGas(gas)
+ scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, tracing.GasChangeCallContractCreation)
res, addr, returnGas, suberr := interpreter.evm.Create(scope.Contract, input, gas, &value)
// Push item on the stack based on the returned error. If the ruleset is
@@ -605,7 +605,8 @@ 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)
if suberr == ErrExecutionReverted {
interpreter.returnData = res // set REVERT data to return data buffer
@@ -628,7 +629,7 @@ 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
res, addr, returnGas, suberr := interpreter.evm.Create2(scope.Contract, input, gas,
@@ -640,7 +641,8 @@ 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)
if suberr == ErrExecutionReverted {
interpreter.returnData = res // set REVERT data to return data buffer
@@ -679,7 +681,8 @@ 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)
interpreter.returnData = ret
return ret, nil
@@ -711,7 +714,8 @@ 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)
interpreter.returnData = ret
return ret, nil
@@ -739,7 +743,8 @@ 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)
interpreter.returnData = ret
return ret, nil
@@ -767,7 +772,8 @@ 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)
interpreter.returnData = ret
return ret, nil
@@ -802,11 +808,15 @@ func opSelfdestruct(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
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 tracer := interpreter.evm.Config.Tracer; tracer != nil {
- tracer.CaptureEnter(SELFDESTRUCT, scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
- tracer.CaptureExit([]byte{}, 0, nil)
+ if tracer.OnEnter != nil {
+ tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
+ }
+ if tracer.OnExit != nil {
+ tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
+ }
}
return nil, errStopToken
}
@@ -817,12 +827,16 @@ func opSelfdestruct6780(pc *uint64, interpreter *EVMInterpreter, scope *ScopeCon
}
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.ToBig())
- tracer.CaptureExit([]byte{}, 0, nil)
+ if tracer.OnEnter != nil {
+ tracer.OnEnter(interpreter.evm.depth, byte(SELFDESTRUCT), scope.Contract.Address(), beneficiary.Bytes20(), []byte{}, 0, balance.ToBig())
+ }
+ if tracer.OnExit != nil {
+ tracer.OnExit(interpreter.evm.depth, []byte{}, 0, nil, false)
+ }
}
return nil, errStopToken
}
diff --git a/core/vm/interface.go b/core/vm/interface.go
index 25bfa0672067..d7028cc7c7e3 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"
"github.com/holiman/uint256"
@@ -29,8 +30,8 @@ import (
type StateDB interface {
CreateAccount(common.Address)
- SubBalance(common.Address, *uint256.Int)
- AddBalance(common.Address, *uint256.Int)
+ SubBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason)
+ AddBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason)
GetBalance(common.Address) *uint256.Int
GetNonce(common.Address) uint64
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index 1968289f4eaa..8b7f8b02bda5 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -19,16 +19,18 @@ package vm
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/crypto"
"github.com/ethereum/go-ethereum/log"
+ "github.com/holiman/uint256"
)
// Config are the configuration options for the Interpreter
type Config struct {
- Tracer EVMLogger // Opcode logger
- NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
- EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
- ExtraEips []int // Additional EIPS that are to be enabled
+ Tracer *tracing.Hooks
+ NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
+ EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages
+ ExtraEips []int // Additional EIPS that are to be enabled
}
// ScopeContext contains the things that are per-call, such as stack and memory,
@@ -39,6 +41,45 @@ 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 {
+ return ctx.Contract.Value()
+}
+
+// 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
+}
+
// EVMInterpreter represents an EVM interpreter
type EVMInterpreter struct {
evm *EVM
@@ -146,8 +187,8 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
res []byte // result of the opcode execution function
debug = in.evm.Config.Tracer != nil
)
- // Don't move this deferred function, it's placed before the capturestate-deferred method,
- // so that it gets executed _after_: the capturestate needs the stacks before
+ // Don't move this deferred function, it's placed before the OnOpcode-deferred method,
+ // so that it gets executed _after_: the OnOpcode needs the stacks before
// they are returned to the pools
defer func() {
returnStack(stack)
@@ -155,13 +196,15 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
contract.Input = input
if debug {
- defer func() {
- if err != nil {
- if !logged {
- in.evm.Config.Tracer.CaptureState(pcCopy, op, gasCopy, cost, callContext, in.returnData, in.evm.depth, err)
- } else {
- in.evm.Config.Tracer.CaptureFault(pcCopy, op, gasCopy, cost, callContext, in.evm.depth, err)
- }
+ defer func() { // this deferred method handles exit-with-error
+ 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))
}
}()
}
@@ -185,9 +228,10 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
} else if sLen > operation.maxStack {
return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack}
}
- if !contract.UseGas(cost) {
+ if !contract.UseGas(cost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
return nil, ErrOutOfGas
}
+
if operation.dynamicGas != nil {
// All ops with a dynamic memory usage also has a dynamic gas cost.
var memorySize uint64
@@ -211,21 +255,33 @@ 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 // for tracing
- if err != nil || !contract.UseGas(dynamicCost) {
+ if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, tracing.GasChangeIgnored) {
return nil, ErrOutOfGas
}
+
// Do tracing before memory expansion
if debug {
- in.evm.Config.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)
}
} else if debug {
- in.evm.Config.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
+ }
}
+
// execute the operation
res, err = operation.execute(&pc, in, callContext)
if err != nil {
diff --git a/core/vm/logger.go b/core/vm/logger.go
deleted file mode 100644
index 2667908a84d1..000000000000
--- 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)
- 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 f420a241058b..289da44be3aa 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/params"
)
@@ -169,7 +170,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
}
}
diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go
index 46f2bb5d5f64..b587d6d5a044 100644
--- a/core/vm/runtime/runtime.go
+++ b/core/vm/runtime/runtime.go
@@ -123,6 +123,9 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
sender = vm.AccountRef(cfg.Origin)
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
)
+ 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)
@@ -156,6 +159,9 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
sender = vm.AccountRef(cfg.Origin)
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
)
+ 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)
@@ -184,6 +190,9 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
statedb = cfg.State
rules = cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, vmenv.Context.Random != nil, vmenv.Context.Time)
)
+ 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)
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index b9e3c8ed661c..45228e78c41a 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -336,7 +336,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
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
@@ -812,7 +812,7 @@ func TestRuntimeJSTracer(t *testing.T) {
byte(vm.PUSH1), 0,
byte(vm.RETURN),
}
- depressedCode := []byte{
+ suicideCode := []byte{
byte(vm.PUSH1), 0xaa,
byte(vm.SELFDESTRUCT),
}
@@ -825,7 +825,7 @@ func TestRuntimeJSTracer(t *testing.T) {
statedb.SetCode(common.HexToAddress("0xcc"), calleeCode)
statedb.SetCode(common.HexToAddress("0xdd"), calleeCode)
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
- statedb.SetCode(common.HexToAddress("0xff"), depressedCode)
+ statedb.SetCode(common.HexToAddress("0xff"), suicideCode)
tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
if err != nil {
@@ -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)
@@ -869,7 +869,7 @@ func TestJSTracerCreateTx(t *testing.T) {
_, _, _, err = Create(code, &Config{
State: statedb,
EVMConfig: vm.Config{
- Tracer: tracer,
+ Tracer: tracer.Hooks,
}})
if err != nil {
t.Fatal(err)
diff --git a/eth/api_backend.go b/eth/api_backend.go
index 48c46447c5a0..a97942599c97 100644
--- a/eth/api_backend.go
+++ b/eth/api_backend.go
@@ -420,6 +420,6 @@ func (b *EthAPIBackend) StateAtBlock(ctx context.Context, block *types.Block, re
return b.eth.stateAtBlock(ctx, block, reexec, base, readOnly, preferDisk)
}
-func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
+func (b *EthAPIBackend) StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, tracers.StateReleaseFunc, error) {
return b.eth.stateAtTransaction(ctx, block, txIndex, reexec)
}
diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go
index 671e935beb13..1d75c4c041b0 100644
--- a/eth/api_debug_test.go
+++ b/eth/api_debug_test.go
@@ -27,6 +27,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/triedb"
@@ -73,7 +74,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], uint256.NewInt(1))
+ sdb.SetBalance(addrs[i], uint256.NewInt(1), tracing.BalanceChangeUnspecified)
if _, ok := m[addr]; ok {
t.Fatalf("bad")
} else {
diff --git a/eth/backend.go b/eth/backend.go
index 81d84028a5f8..e6f9c05950d8 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -18,6 +18,7 @@
package eth
import (
+ "encoding/json"
"errors"
"fmt"
"math/big"
@@ -42,6 +43,7 @@ import (
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/protocols/eth"
"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"
@@ -199,6 +201,17 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
StateScheme: scheme,
}
)
+ if config.VMTrace != "" {
+ var 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
+ }
// Override the chain config with provided settings.
var overrides core.ChainOverrides
if config.OverrideCancun != nil {
diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go
index 420a8b147a7f..fef7f29f4e28 100644
--- a/eth/ethconfig/config.go
+++ b/eth/ethconfig/config.go
@@ -141,6 +141,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/state_accessor.go b/eth/state_accessor.go
index 526361a2b8a6..770532cbfe73 100644
--- a/eth/state_accessor.go
+++ b/eth/state_accessor.go
@@ -217,7 +217,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")
@@ -244,7 +244,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
if idx == txIndex {
- return msg, context, statedb, release, nil
+ return tx, context, statedb, release, nil
}
// Not yet the searched for transaction, execute on top of the current state
vmenv := vm.NewEVM(context, txContext, statedb, eth.blockchain.Config(), vm.Config{})
diff --git a/eth/tracers/api.go b/eth/tracers/api.go
index 0add06c8f69b..7a7c5e48d901 100644
--- a/eth/tracers/api.go
+++ b/eth/tracers/api.go
@@ -22,6 +22,7 @@ import (
"encoding/json"
"errors"
"fmt"
+ "math/big"
"os"
"runtime"
"sync"
@@ -86,7 +87,7 @@ type Backend interface {
Engine() consensus.Engine
ChainDb() ethdb.Database
StateAtBlock(ctx context.Context, block *types.Block, reexec uint64, base *state.StateDB, readOnly bool, preferDisk bool) (*state.StateDB, StateReleaseFunc, error)
- StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*core.Message, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
+ StateAtTransaction(ctx context.Context, block *types.Block, txIndex int, reexec uint64) (*types.Transaction, vm.BlockContext, *state.StateDB, StateReleaseFunc, error)
}
// API is the collection of tracing APIs exposed over the private debugging endpoint.
@@ -277,14 +278,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
TxIndex: i,
TxHash: tx.Hash(),
}
- res, err := api.traceTx(ctx, msg, txctx, blockCtx, task.statedb, config)
+ res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, task.statedb, config)
if err != nil {
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Error: err.Error()}
log.Warn("Tracing failed", "hash", tx.Hash(), "block", task.block.NumberU64(), "err", err)
break
}
- // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
- task.statedb.Finalise(api.backend.ChainConfig().IsEIP158(task.block.Number()))
task.results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
}
// Tracing state is used up, queue it for de-referencing. Note the
@@ -598,7 +597,6 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
var (
txs = block.Transactions()
blockHash = block.Hash()
- is158 = api.backend.ChainConfig().IsEIP158(block.Number())
blockCtx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time())
results = make([]*txTraceResult, len(txs))
@@ -612,14 +610,11 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
TxIndex: i,
TxHash: tx.Hash(),
}
- res, err := api.traceTx(ctx, msg, txctx, blockCtx, statedb, config)
+ res, err := api.traceTx(ctx, tx, msg, txctx, blockCtx, statedb, config)
if err != nil {
return nil, err
}
results[i] = &txTraceResult{TxHash: tx.Hash(), Result: res}
- // Finalize the state so any modifications are written to the trie
- // Only delete empty objects if EIP158/161 (a.k.a Spurious Dragon) is in effect
- statedb.Finalise(is158)
}
return results, nil
}
@@ -659,7 +654,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)
+ res, err := api.traceTx(ctx, txs[task.index], msg, txctx, blockCtx, task.statedb, config)
if err != nil {
results[task.index] = &txTraceResult{TxHash: txs[task.index].Hash(), Error: err.Error()}
continue
@@ -794,7 +789,9 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Execute the transaction and flush any traces to disk
vmenv := vm.NewEVM(vmctx, txContext, statedb, chainConfig, vmConf)
statedb.SetTxContext(tx.Hash(), i)
- _, err = core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
+ vmConf.Tracer.OnTxStart(vmenv.GetVMContext(), tx, msg.From)
+ 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()
}
@@ -851,11 +848,15 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
if err != nil {
return nil, err
}
- msg, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
+ tx, vmctx, statedb, release, err := api.backend.StateAtTransaction(ctx, block, int(index), reexec)
if err != nil {
return nil, err
}
defer release()
+ msg, err := core.TransactionToMessage(tx, types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()), block.BaseFee())
+ if err != nil {
+ return nil, err
+ }
txctx := &Context{
BlockHash: blockHash,
@@ -863,7 +864,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
TxIndex: int(index),
TxHash: hash,
}
- return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
+ return api.traceTx(ctx, tx, msg, txctx, vmctx, statedb, config)
}
// TraceCall lets you trace a given eth_call. It collects the structured logs
@@ -924,40 +925,49 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
config.BlockOverrides.Apply(&vmctx)
}
// Execute the trace
- msg, err := args.ToMessage(api.backend.RPCGasCap(), vmctx.BaseFee)
- if err != nil {
+ if err := args.CallDefaults(api.backend.RPCGasCap(), vmctx.BaseFee, api.backend.ChainConfig().ChainID); err != nil {
return nil, err
}
-
- var traceConfig *TraceConfig
+ var (
+ msg = args.ToMessage(vmctx.BaseFee)
+ tx = args.ToTransaction()
+ traceConfig *TraceConfig
+ )
if config != nil {
traceConfig = &config.TraceConfig
}
- return api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
+ return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
}
// traceTx configures a new tracer according to the provided configuration, and
// executes the given message in the provided environment. The return value will
// be tracer dependent.
-func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
+func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *core.Message, txctx *Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
var (
- tracer Tracer
- err error
- timeout = defaultTraceTimeout
- txContext = core.NewEVMTxContext(message)
+ tracer *Tracer
+ err error
+ timeout = defaultTraceTimeout
+ usedGas uint64
)
if config == nil {
config = &TraceConfig{}
}
// Default tracer is the struct logger
- tracer = logger.NewStructLogger(config.Config)
- if config.Tracer != nil {
+ 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)
if err != nil {
return nil, err
}
}
- vmenv := vm.NewEVM(vmctx, txContext, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer, NoBaseFee: true})
+ vmenv := vm.NewEVM(vmctx, vm.TxContext{GasPrice: big.NewInt(0)}, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
+ statedb.SetLogger(tracer.Hooks)
// Define a meaningful timeout of a single transaction trace
if config.Timeout != nil {
@@ -978,7 +988,8 @@ func (api *API) traceTx(ctx context.Context, message *core.Message, txctx *Conte
// Call Prepare to clear out the statedb access list
statedb.SetTxContext(txctx.TxHash, txctx.TxIndex)
- if _, err = core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.GasLimit)); err != nil {
+ _, err = core.ApplyTransactionWithEVM(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)
}
return tracer.GetResult()
diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go
index d8e4b9a4ef3d..3254f4961fc7 100644
--- a/eth/tracers/api_test.go
+++ b/eth/tracers/api_test.go
@@ -155,7 +155,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
@@ -174,7 +174,7 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
txContext := core.NewEVMTxContext(msg)
context := core.NewEVMBlockContext(block.Header(), b.chain, nil)
if idx == txIndex {
- return msg, context, statedb, release, nil
+ return tx, context, statedb, release, nil
}
vmenv := vm.NewEVM(context, txContext, statedb, b.chainConfig, vm.Config{})
if _, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
@@ -666,7 +666,6 @@ func TestTracingWithOverrides(t *testing.T) {
From: &accounts[0].addr,
// BLOCKNUMBER PUSH1 MSTORE
Input: newRPCBytes(common.Hex2Bytes("4360005260206000f3")),
- //&hexutil.Bytes{0x43}, // blocknumber
},
config: &TraceCallConfig{
BlockOverrides: ðapi.BlockOverrides{Number: (*hexutil.Big)(big.NewInt(0x1337))},
diff --git a/eth/tracers/tracers.go b/eth/tracers/dir.go
similarity index 71%
rename from eth/tracers/tracers.go
rename to eth/tracers/dir.go
index 7b43b7cf834a..650815350b37 100644
--- a/eth/tracers/tracers.go
+++ b/eth/tracers/dir.go
@@ -14,17 +14,14 @@
// 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"
- "errors"
- "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
- "github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/core/tracing"
)
// Context contains some contextual infos for a transaction execution that is not
@@ -36,17 +33,19 @@ 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) (*Tracer, error)
+type jsCtorFn func(string, *Context, json.RawMessage) (*Tracer, error)
type elem struct {
ctor ctorFn
@@ -79,7 +78,7 @@ 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) (*Tracer, error) {
if elem, ok := d.elems[name]; ok {
return elem.ctor(ctx, cfg)
}
@@ -97,27 +96,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, errors.New("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/README.md b/eth/tracers/internal/tracetest/README.md
new file mode 100644
index 000000000000..8c3d5d275f2c
--- /dev/null
+++ b/eth/tracers/internal/tracetest/README.md
@@ -0,0 +1,10 @@
+# Filling test cases
+
+To fill test cases for the built-in tracers, the `makeTest.js` script can be used. Given a transaction on a dev/test network, `makeTest.js` will fetch its prestate and then traces with the given configuration.
+In the Geth console do:
+
+```terminal
+let tx = '0x...'
+loadScript('makeTest.js')
+makeTest(tx, { tracer: 'callTracer' })
+```
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go
index 6216a16ced9c..896d4d8a88d4 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"
@@ -141,15 +143,19 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
+
+ state.StateDB.SetLogger(tracer.Hooks)
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
- evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
+ evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
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 {
@@ -245,7 +251,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
- evm := vm.NewEVM(context, txContext, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
+ evm := vm.NewEVM(context, txContext, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
snap := state.StateDB.Snapshot()
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
if _, err = st.TransitionDb(); err != nil {
@@ -260,13 +266,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{},
@@ -274,9 +280,10 @@ 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 {
+ mkTracer := func(name string, cfg json.RawMessage) *tracers.Tracer {
tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
@@ -287,7 +294,7 @@ func TestInternals(t *testing.T) {
for _, tc := range []struct {
name string
code []byte
- tracer tracers.Tracer
+ tracer *tracers.Tracer
want string
}{
{
@@ -301,13 +308,13 @@ func TestInternals(t *testing.T) {
byte(vm.CALL),
},
tracer: mkTracer("callTracer", nil),
- want: `{"from":"0x000000000000000000000000000000000000feed","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"}`,
+ 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":"0x13880","gasUsed":"0x13880","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",
@@ -320,7 +327,7 @@ func TestInternals(t *testing.T) {
byte(vm.LOG0),
},
tracer: mkTracer("callTracer", json.RawMessage(`{ "withLog": true }`)),
- want: `{"from":"0x000000000000000000000000000000000000feed","gas":"0x13880","gasUsed":"0x5b9e","to":"0x00000000000000000000000000000000deadbeef","input":"0x","logs":[{"address":"0x00000000000000000000000000000000deadbeef","topics":[],"data":"0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","position":"0x0"}],"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
@@ -339,7 +346,7 @@ func TestInternals(t *testing.T) {
byte(vm.LOG0),
},
tracer: mkTracer("prestateTracer", nil),
- want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"}}`,
+ want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600164ffffffffff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex),
},
{
// CREATE2 which requires padding memory by prestate tracer
@@ -358,7 +365,7 @@ func TestInternals(t *testing.T) {
byte(vm.LOG0),
},
tracer: mkTracer("prestateTracer", nil),
- want: `{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x000000000000000000000000000000000000feed":{"balance":"0x1c6bf52647880"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"0x91ff9a805d36f54e3e272e230f3e3f5c1b330804":{"balance":"0x0"}}`,
+ want: fmt.Sprintf(`{"0x0000000000000000000000000000000000000000":{"balance":"0x0"},"0x00000000000000000000000000000000deadbeef":{"balance":"0x0","code":"0x6001600052600160ff60016000f560ff6000a0"},"%s":{"balance":"0x1c6bf52634000"}}`, originHex),
},
} {
t.Run(tc.name, func(t *testing.T) {
@@ -372,22 +379,31 @@ func TestInternals(t *testing.T) {
},
}, false, rawdb.HashScheme)
defer state.Close()
-
- evm := vm.NewEVM(context, txContext, state.StateDB, params.MainnetChainConfig, vm.Config{Tracer: tc.tracer})
- msg := &core.Message{
- To: &to,
- From: origin,
- Value: big.NewInt(0),
- GasLimit: 80000,
- GasPrice: big.NewInt(0),
- GasFeeCap: big.NewInt(0),
- GasTipCap: big.NewInt(0),
- SkipAccountChecks: false,
+ state.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(),
}
- st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
- if _, err := st.TransitionDb(); err != nil {
+ evm := vm.NewEVM(context, txContext, state.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.From)
+ 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 {
diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go
index abee48891767..cd9791db2a50 100644
--- a/eth/tracers/internal/tracetest/flat_calltrace_test.go
+++ b/eth/tracers/internal/tracetest/flat_calltrace_test.go
@@ -16,11 +16,9 @@ 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/eth/tracers"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests"
-
- // Force-load the native, to trigger registration
- "github.com/ethereum/go-ethereum/eth/tracers"
)
// flatCallTrace is the result of a callTracerParity run.
@@ -103,16 +101,19 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
if err != nil {
return fmt.Errorf("failed to create call tracer: %v", err)
}
+
+ state.StateDB.SetLogger(tracer.Hooks)
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil {
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
}
- evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
- st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
-
- if _, err = st.TransitionDb(); err != nil {
+ evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
+ 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()
@@ -124,7 +125,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
return fmt.Errorf("failed to unmarshal trace result: %v", err)
}
if !jsonEqualFlat(ret, test.Result) {
- t.Logf("tracer name: %s", tracerName)
+ t.Logf("test %s failed", filename)
// uncomment this for easier debugging
// have, _ := json.MarshalIndent(ret, "", " ")
diff --git a/eth/tracers/internal/tracetest/makeTest.js b/eth/tracers/internal/tracetest/makeTest.js
new file mode 100644
index 000000000000..306f10719009
--- /dev/null
+++ b/eth/tracers/internal/tracetest/makeTest.js
@@ -0,0 +1,48 @@
+// makeTest generates a test for the configured tracer by running
+// a prestate reassembled and a call trace run, assembling all the
+// gathered information into a test case.
+var makeTest = function(tx, traceConfig) {
+ // Generate the genesis block from the block, transaction and prestate data
+ var block = eth.getBlock(eth.getTransaction(tx).blockHash);
+ var genesis = eth.getBlock(block.parentHash);
+
+ delete genesis.gasUsed;
+ delete genesis.logsBloom;
+ delete genesis.parentHash;
+ delete genesis.receiptsRoot;
+ delete genesis.sha3Uncles;
+ delete genesis.size;
+ delete genesis.transactions;
+ delete genesis.transactionsRoot;
+ delete genesis.uncles;
+
+ genesis.gasLimit = genesis.gasLimit.toString();
+ genesis.number = genesis.number.toString();
+ genesis.timestamp = genesis.timestamp.toString();
+
+ genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer"});
+ for (var key in genesis.alloc) {
+ var nonce = genesis.alloc[key].nonce;
+ if (nonce) {
+ genesis.alloc[key].nonce = nonce.toString();
+ }
+ }
+ genesis.config = admin.nodeInfo.protocols.eth.config;
+
+ // Generate the call trace and produce the test input
+ var result = debug.traceTransaction(tx, traceConfig);
+ delete result.time;
+
+ console.log(JSON.stringify({
+ genesis: genesis,
+ context: {
+ number: block.number.toString(),
+ difficulty: block.difficulty,
+ timestamp: block.timestamp.toString(),
+ gasLimit: block.gasLimit.toString(),
+ miner: block.miner,
+ },
+ input: eth.getRawTransaction(tx),
+ result: result,
+ }, null, 2));
+}
\ No newline at end of file
diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go
index 38097ff334b2..dee2bf492e5b 100644
--- a/eth/tracers/internal/tracetest/prestate_test.go
+++ b/eth/tracers/internal/tracetest/prestate_test.go
@@ -117,15 +117,19 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
+
+ state.StateDB.SetLogger(tracer.Hooks)
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
if err != nil {
t.Fatalf("failed to prepare transaction for tracing: %v", err)
}
- evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer})
- st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
- if _, err = st.TransitionDb(); err != nil {
+ evm := vm.NewEVM(context, core.NewEVMTxContext(msg), state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
+ tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
+ 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/testdata/call_tracer/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer/inner_instafail.json
index 9b45b52fe9ad..ed3688a942e1 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_tracer_flat/callcode_precompiled_fail_hide.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/callcode_precompiled_fail_hide.json
index c796804a4bcd..a2386ea9c713 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/inner_instafail.json b/eth/tracers/internal/tracetest/testdata/call_tracer_flat/inner_instafail.json
index 4de08f2ccaf1..611e50e2c046 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 28e96684b2df..f3a7d9a94610 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 74fd87cc6c4d..3c5d6d9f2b07 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 96060d554539..6911ed4b32af 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/frontier_create_outofstorage.json b/eth/tracers/internal/tracetest/testdata/call_tracer_withLog/frontier_create_outofstorage.json
new file mode 100644
index 000000000000..c46fe080f7f2
--- /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/prestate_tracer/create_create.json b/eth/tracers/internal/tracetest/testdata/prestate_tracer/create_create.json
new file mode 100644
index 000000000000..909a1eabe38e
--- /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,
+ "shanghaiTime": 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/util.go b/eth/tracers/internal/tracetest/util.go
index 95d292c9240b..1913f352ddb7 100644
--- a/eth/tracers/internal/tracetest/util.go
+++ b/eth/tracers/internal/tracetest/util.go
@@ -9,59 +9,6 @@ import (
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
)
-// To generate a new callTracer test, copy paste the makeTest method below into
-// a Geth console and call it with a transaction hash you which to export.
-
-/*
-// makeTest generates a callTracer test by running a prestate reassembled and a
-// call trace run, assembling all the gathered information into a test case.
-var makeTest = function(tx, rewind) {
- // Generate the genesis block from the block, transaction and prestate data
- var block = eth.getBlock(eth.getTransaction(tx).blockHash);
- var genesis = eth.getBlock(block.parentHash);
-
- delete genesis.gasUsed;
- delete genesis.logsBloom;
- delete genesis.parentHash;
- delete genesis.receiptsRoot;
- delete genesis.sha3Uncles;
- delete genesis.size;
- delete genesis.transactions;
- delete genesis.transactionsRoot;
- delete genesis.uncles;
-
- genesis.gasLimit = genesis.gasLimit.toString();
- genesis.number = genesis.number.toString();
- genesis.timestamp = genesis.timestamp.toString();
-
- genesis.alloc = debug.traceTransaction(tx, {tracer: "prestateTracer", rewind: rewind});
- for (var key in genesis.alloc) {
- var nonce = genesis.alloc[key].nonce;
- if (nonce) {
- genesis.alloc[key].nonce = nonce.toString();
- }
- }
- genesis.config = admin.nodeInfo.protocols.eth.config;
-
- // Generate the call trace and produce the test input
- var result = debug.traceTransaction(tx, {tracer: "callTracer", rewind: rewind});
- delete result.time;
-
- console.log(JSON.stringify({
- genesis: genesis,
- context: {
- number: block.number.toString(),
- difficulty: block.difficulty,
- timestamp: block.timestamp.toString(),
- gasLimit: block.gasLimit.toString(),
- miner: block.miner,
- },
- input: eth.getRawTransaction(tx),
- result: result,
- }, null, 2));
-}
-*/
-
// camel converts a snake cased input string into a camel cased output.
func camel(str string) string {
pieces := strings.Split(str, "_")
diff --git a/eth/tracers/internal/util.go b/eth/tracers/internal/util.go
new file mode 100644
index 000000000000..18a372d192a1
--- /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 000000000000..6a467314cc86
--- /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 07c138bae47b..7e4930f81dbd 100644
--- a/eth/tracers/js/goja.go
+++ b/eth/tracers/js/goja.go
@@ -23,12 +23,16 @@ 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/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,9 +45,9 @@ func init() {
if err != nil {
panic(err)
}
- type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error)
+ type ctorFn = func(*tracers.Context, json.RawMessage) (*tracers.Tracer, error)
lookup := func(code string) ctorFn {
- return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+ return func(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
return newJsTracer(code, ctx, cfg)
}
}
@@ -96,7 +100,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
// 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
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 +108,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,7 +137,7 @@ 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) (*tracers.Tracer, error) {
vm := goja.New()
// By default field names are exported to JS as is, i.e. capitalized.
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
@@ -217,30 +220,62 @@ 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) {
- 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 := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
+ 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) {
- cancel := func(err error) {
- t.err = err
- t.env.Cancel()
+// 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
}
- t.env = env
- db := &dbObj{db: env.StateDB, vm: t.vm, toBig: t.toBig, toBuf: t.toBuf, fromBuf: t.fromBuf}
- t.dbValue = db.setupObject()
if create {
t.ctx["type"] = t.vm.ToValue("CREATE")
} else {
@@ -248,43 +283,32 @@ func (t *jsTracer) CaptureStart(env *vm.EVM, from common.Address, to common.Addr
}
fromVal, err := t.toBuf(t.vm, from.Bytes())
if err != nil {
- cancel(err)
+ t.err = err
return
}
t.ctx["from"] = fromVal
toVal, err := t.toBuf(t.vm, to.Bytes())
if err != nil {
- cancel(err)
+ t.err = err
return
}
t.ctx["to"] = toVal
inputVal, err := t.toBuf(t.vm, input)
if err != nil {
- cancel(err)
+ t.err = err
return
}
t.ctx["input"] = inputVal
- t.ctx["gas"] = t.vm.ToValue(t.gasLimit)
- gasPriceBig, err := t.toBig(t.vm, env.TxContext.GasPrice.String())
- if err != nil {
- cancel(err)
- return
- }
- t.ctx["gasPrice"] = gasPriceBig
valueBig, err := t.toBig(t.vm, value.String())
if err != nil {
- cancel(err)
+ 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, env.Context.Random != nil, env.Context.Time)
- 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
}
@@ -293,10 +317,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
@@ -308,20 +332,23 @@ 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) {
+// 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())
}
@@ -333,16 +360,20 @@ func (t *jsTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
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) {
+ 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)
@@ -357,9 +388,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
}
@@ -375,6 +413,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 {
@@ -384,7 +425,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.
@@ -397,9 +438,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 {
@@ -578,7 +616,7 @@ func (o *opObj) setupObject() *goja.Object {
}
type memoryObj struct {
- memory *vm.Memory
+ memory []byte
vm *goja.Runtime
toBig toBigFn
toBuf toBufFn
@@ -606,7 +644,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
}
@@ -629,14 +667,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 {
@@ -648,7 +686,7 @@ func (m *memoryObj) setupObject() *goja.Object {
}
type stackObj struct {
- stack *vm.Stack
+ stack []uint256.Int
vm *goja.Runtime
toBig toBigFn
}
@@ -669,14 +707,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 {
@@ -687,7 +725,7 @@ func (s *stackObj) setupObject() *goja.Object {
}
type dbObj struct {
- db vm.StateDB
+ db tracing.StateDB
vm *goja.Runtime
toBig toBigFn
toBuf toBufFn
@@ -779,14 +817,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)
@@ -796,7 +834,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)
@@ -806,7 +844,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)
@@ -816,7 +854,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 b7f2693770be..d643289a64d7 100644
--- a/eth/tracers/js/tracer_test.go
+++ b/eth/tracers/js/tracer_test.go
@@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
+ "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/params"
@@ -61,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 = uint256.NewInt(0)
@@ -74,12 +75,12 @@ func runTrace(tracer tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCon
contract.Code = contractCode
}
- tracer.CaptureTxStart(gasLimit)
- tracer.CaptureStart(env, contract.Caller(), contract.Address(), false, []byte{}, startGas, value.ToBig())
+ 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.ToBig())
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
}
@@ -181,15 +182,16 @@ func TestHaltBetweenSteps(t *testing.T) {
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{}, uint256.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))
+ 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)
@@ -205,9 +207,10 @@ func TestNoStepExec(t *testing.T) {
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{}, 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{}, 1000, big.NewInt(0))
+ tracer.OnExit(0, nil, 0, nil, false)
ret, err := tracer.GetResult()
if err != nil {
t.Fatal(err)
@@ -276,8 +279,8 @@ func TestEnterExit(t *testing.T) {
scope := &vm.ScopeContext{
Contract: vm.NewContract(&account{}, &account{}, uint256.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))
+ tracer.OnExit(1, []byte{}, 400, nil, false)
have, err := tracer.GetResult()
if err != nil {
diff --git a/eth/tracers/live.go b/eth/tracers/live.go
new file mode 100644
index 000000000000..ffb2303af4f1
--- /dev/null
+++ b/eth/tracers/live.go
@@ -0,0 +1,31 @@
+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 f, ok := d.elems[name]; ok {
+ return f(config)
+ }
+ return nil, errors.New("not found")
+}
diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go
new file mode 100644
index 000000000000..7433c288408f
--- /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) {
+}
+
+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/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go
index 766ee4e4b95c..fc7713b24527 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"
)
@@ -132,17 +131,20 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi
}
}
-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())
@@ -158,20 +160,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) {}
-
-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 2b36f9f4922f..ef1d47146682 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"
@@ -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) {
- 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) {
+ 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) {}
-
-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
diff --git a/eth/tracers/logger/logger_json.go b/eth/tracers/logger/logger_json.go
index a2cb4cd9fc59..6fac2d115922 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) {}
-
-func (l *JSONLogger) CaptureTxEnd(restGas uint64) {}
diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go
index 1d8eb320f600..137608f8847d 100644
--- a/eth/tracers/logger/logger_test.go
+++ b/eth/tracers/logger/logger_test.go
@@ -56,12 +56,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(uint256.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)
diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go
index 5a2c4f91115f..6cb0e433d27d 100644
--- a/eth/tracers/native/4byte.go
+++ b/eth/tracers/native/4byte.go
@@ -23,6 +23,8 @@ 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"
)
@@ -46,20 +48,26 @@ 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
+ 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) (*tracers.Tracer, error) {
t := &fourByteTracer{
ids: make(map[string]int),
}
- 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 +86,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, env.Context.Random != nil, env.Context.Time)
+ rules := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
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) {
// Skip if tracing was interrupted
if t.interrupt.Load() {
return
@@ -99,6 +101,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 be9b58a4cd3c..3b6350658038 100644
--- a/eth/tracers/native/call.go
+++ b/eth/tracers/native/call.go
@@ -25,9 +25,10 @@ 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/log"
)
//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go
@@ -59,7 +60,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 {
@@ -67,16 +69,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
}
@@ -102,10 +105,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
}
@@ -117,7 +120,25 @@ 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) {
+func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (*tracers.Tracer, error) {
+ t, err := newCallTracerObject(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
+}
+
+func newCallTracerObject(ctx *tracers.Context, cfg json.RawMessage) (*callTracer, error) {
var config callTracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
@@ -126,84 +147,13 @@ func newCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, e
}
// First callframe contains tx context info
// and is populated on start and end.
- return &callTracer{callstack: make([]callFrame, 1), config: config}, 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
- }
-}
-
-// 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
- if t.config.OnlyTopCall && depth > 1 {
- return
- }
- // Skip if tracing was interrupted
- 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
- log.Warn("failed to copy CREATE2 input", "err", err, "tracer", "callTracer", "offset", mStart, "size", mSize)
- return
- }
-
- log := callLog{
- Address: scope.Contract.Address(),
- Topics: topics,
- Data: hexutil.Bytes(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, log)
- }
+ return &callTracer{callstack: make([]callFrame, 0, 1), config: config}, nil
}
-// 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 {
+// 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) {
+ t.depth = depth
+ if t.config.OnlyTopCall && depth > 0 {
return
}
// Skip if tracing was interrupted
@@ -213,48 +163,92 @@ func (t *callTracer) CaptureEnter(typ vm.OpCode, from common.Address, to common.
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) {
- 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) {
@@ -266,7 +260,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/call_flat.go b/eth/tracers/native/call_flat.go
index 266ab9900146..37be64310c47 100644
--- a/eth/tracers/native/call_flat.go
+++ b/eth/tracers/native/call_flat.go
@@ -25,6 +25,8 @@ 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"
)
@@ -112,7 +114,7 @@ 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
+ activePrecompiles []common.Address // Updated on tx start based on given rules
}
type flatCallTracerConfig struct {
@@ -121,7 +123,7 @@ 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) (*tracers.Tracer, error) {
var config flatCallTracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
@@ -131,45 +133,31 @@ func newFlatCallTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Trace
// 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, nil)
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, env.Context.Random != nil, env.Context.Time)
- 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}
+ 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) {
+ t.tracer.OnEnter(depth, typ, from, to, input, gas, value)
+ 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) {
- t.tracer.CaptureTxStart(gasLimit)
+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 := env.ChainConfig.Rules(env.BlockNumber, env.Random != nil, env.Time)
+ 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.
diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go
index db8ddd64380d..c3b1d9f8cafa 100644
--- a/eth/tracers/native/mux.go
+++ b/eth/tracers/native/mux.go
@@ -21,7 +21,8 @@ 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"
)
@@ -33,18 +34,18 @@ 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) (*tracers.Tracer, error) {
var config map[string]json.RawMessage
if cfg != nil {
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)
@@ -55,61 +56,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
}
-// 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) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
for _, t := range t.tracers {
- t.CaptureStart(env, from, to, create, input, gas, value)
+ if t.OnOpcode != nil {
+ t.OnOpcode(pc, op, gas, cost, scope, rData, depth, err)
+ }
+ }
+}
+
+func (t *muxTracer) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) {
+ for _, t := range t.tracers {
+ if t.OnFault != nil {
+ t.OnFault(pc, op, gas, cost, scope, depth, err)
+ }
+ }
+}
+
+func (t *muxTracer) OnGasChange(old, new uint64, reason tracing.GasChangeReason) {
+ for _, t := range t.tracers {
+ if t.OnGasChange != nil {
+ t.OnGasChange(old, new, reason)
+ }
+ }
+}
+
+func (t *muxTracer) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) {
+ for _, t := range t.tracers {
+ if t.OnEnter != nil {
+ t.OnEnter(depth, typ, from, to, input, gas, value)
+ }
+ }
+}
+
+func (t *muxTracer) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
+ for _, t := range t.tracers {
+ if t.OnExit != nil {
+ t.OnExit(depth, output, gasUsed, err, reverted)
+ }
}
}
-// CaptureEnd is called after the call finishes to finalize the tracing.
-func (t *muxTracer) CaptureEnd(output []byte, gasUsed uint64, err error) {
+func (t *muxTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
for _, t := range t.tracers {
- t.CaptureEnd(output, gasUsed, err)
+ if t.OnTxStart != nil {
+ t.OnTxStart(env, tx, from)
+ }
}
}
-// 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) OnTxEnd(receipt *types.Receipt, err error) {
for _, t := range t.tracers {
- t.CaptureState(pc, op, gas, cost, scope, rData, depth, err)
+ if t.OnTxEnd != nil {
+ t.OnTxEnd(receipt, err)
+ }
}
}
-// 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) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
for _, t := range t.tracers {
- t.CaptureFault(pc, op, gas, cost, scope, depth, err)
+ if t.OnBalanceChange != nil {
+ t.OnBalanceChange(a, prev, new, reason)
+ }
}
}
-// 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) OnNonceChange(a common.Address, prev, new uint64) {
for _, t := range t.tracers {
- t.CaptureEnter(typ, from, to, input, gas, value)
+ if t.OnNonceChange != nil {
+ t.OnNonceChange(a, prev, new)
+ }
}
}
-// 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) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
for _, t := range t.tracers {
- t.CaptureExit(output, gasUsed, err)
+ if t.OnCodeChange != nil {
+ t.OnCodeChange(a, prevCodeHash, prev, codeHash, code)
+ }
}
}
-func (t *muxTracer) CaptureTxStart(gasLimit uint64) {
+func (t *muxTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {
for _, t := range t.tracers {
- t.CaptureTxStart(gasLimit)
+ if t.OnStorageChange != nil {
+ t.OnStorageChange(a, k, prev, new)
+ }
}
}
-func (t *muxTracer) CaptureTxEnd(restGas uint64) {
+func (t *muxTracer) OnLog(log *types.Log) {
for _, t := range t.tracers {
- t.CaptureTxEnd(restGas)
+ if t.OnLog != nil {
+ t.OnLog(log)
+ }
}
}
diff --git a/eth/tracers/native/noop.go b/eth/tracers/native/noop.go
index 3beecd8abfed..f147134610c0 100644
--- a/eth/tracers/native/noop.go
+++ b/eth/tracers/native/noop.go
@@ -21,7 +21,8 @@ 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"
)
@@ -34,38 +35,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) (*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) {
}
-// 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) {}
+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 b86c5c461c7d..b353c0696067 100644
--- a/eth/tracers/native/prestate.go
+++ b/eth/tracers/native/prestate.go
@@ -24,11 +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"
)
//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go
@@ -37,13 +39,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 {
@@ -56,13 +59,10 @@ 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
@@ -74,76 +74,33 @@ 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) (*tracers.Tracer, error) {
var config prestateTracerConfig
if cfg != nil {
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
-
- t.lookupAccount(from)
- t.lookupAccount(to)
- t.lookupAccount(env.Context.Coinbase)
-
- // The recipient balance includes the value transferred.
- toBal := new(big.Int).Sub(t.pre[to].Balance, value)
- t.pre[to].Balance = toBal
- if env.ChainConfig().Rules(env.Context.BlockNumber, env.Context.Random != nil, env.Context.Time).IsEIP158 && create {
- t.pre[to].Nonce--
- }
-
- // The sender 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))
- fromBal.Add(fromBal, new(big.Int).Add(value, consumedGas))
-
- // Add blob fee to the sender's balance.
- if env.Context.BlobBaseFee != nil && len(env.TxContext.BlobHashes) > 0 {
- blobGas := uint64(params.BlobTxBlobGasPerBlob * len(env.TxContext.BlobHashes))
- fromBal.Add(fromBal, new(big.Int).Mul(env.Context.BlobBaseFee, new(big.Int).SetUint64(blobGas)))
- }
- 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
}
@@ -151,10 +108,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())
@@ -176,7 +133,7 @@ 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, err := tracers.GetMemoryCopyPadded(scope.Memory, 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
@@ -189,15 +146,62 @@ func (t *prestateTracer) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64,
}
}
-func (t *prestateTracer) CaptureTxStart(gasLimit uint64) {
- t.gasLimit = gasLimit
+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 {
@@ -247,38 +251,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
@@ -288,12 +260,16 @@ func (t *prestateTracer) lookupAccount(addr common.Address) {
return
}
- t.pre[addr] = &account{
+ acc := &account{
Balance: t.env.StateDB.GetBalance(addr).ToBig(),
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 6ac266e06d61..3cce7bffa19a 100644
--- a/eth/tracers/tracers_test.go
+++ b/eth/tracers/tracers_test.go
@@ -89,7 +89,7 @@ func BenchmarkTransactionTrace(b *testing.B) {
//EnableMemory: false,
//EnableReturnData: false,
})
- evm := vm.NewEVM(context, txContext, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer})
+ evm := vm.NewEVM(context, txContext, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()})
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
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}, // 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, 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/internal/ethapi/api.go b/internal/ethapi/api.go
index 863849f4da6a..6009d7003193 100644
--- a/internal/ethapi/api.go
+++ b/internal/ethapi/api.go
@@ -36,6 +36,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"
@@ -457,7 +458,7 @@ func (s *PersonalAccountAPI) signTransaction(ctx context.Context, args *Transact
return nil, err
}
// Assemble the transaction and sign with the wallet
- tx := args.toTransaction()
+ tx := args.ToTransaction()
return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID)
}
@@ -506,7 +507,7 @@ func (s *PersonalAccountAPI) SignTransaction(ctx context.Context, args Transacti
return nil, errors.New("nonce not specified")
}
// Before actually signing the transaction, ensure the transaction fee is reasonable.
- tx := args.toTransaction()
+ tx := args.ToTransaction()
if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil {
return nil, err
}
@@ -962,42 +963,42 @@ type OverrideAccount struct {
type StateOverride map[common.Address]OverrideAccount
// Apply overrides the fields of specified accounts into the given state.
-func (diff *StateOverride) Apply(state *state.StateDB) error {
+func (diff *StateOverride) Apply(statedb *state.StateDB) error {
if diff == nil {
return nil
}
for addr, account := range *diff {
// Override account nonce.
if account.Nonce != nil {
- state.SetNonce(addr, uint64(*account.Nonce))
+ statedb.SetNonce(addr, uint64(*account.Nonce))
}
// Override account(contract) code.
if account.Code != nil {
- state.SetCode(addr, *account.Code)
+ statedb.SetCode(addr, *account.Code)
}
// Override account balance.
if account.Balance != nil {
u256Balance, _ := uint256.FromBig((*big.Int)(*account.Balance))
- state.SetBalance(addr, u256Balance)
+ statedb.SetBalance(addr, u256Balance, tracing.BalanceChangeUnspecified)
}
if account.State != nil && account.StateDiff != nil {
return fmt.Errorf("account %s has both 'state' and 'stateDiff'", addr.Hex())
}
// Replace entire state if caller requires.
if account.State != nil {
- state.SetStorage(addr, *account.State)
+ statedb.SetStorage(addr, *account.State)
}
// Apply state diff into specified accounts.
if account.StateDiff != nil {
for key, value := range *account.StateDiff {
- state.SetState(addr, key, value)
+ statedb.SetState(addr, key, value)
}
}
}
// Now finalize the changes. Finalize is normally performed between transactions.
// By using finalize, the overrides are semantically behaving as
// if they were created in a transaction just before the tracing occur.
- state.Finalise(false)
+ statedb.Finalise(false)
return nil
}
@@ -1097,10 +1098,10 @@ func doCall(ctx context.Context, b Backend, args TransactionArgs, state *state.S
if blockOverrides != nil {
blockOverrides.Apply(&blockCtx)
}
- msg, err := args.ToMessage(globalGasCap, blockCtx.BaseFee)
- if err != nil {
+ if err := args.CallDefaults(globalGasCap, blockCtx.BaseFee, b.ChainConfig().ChainID); err != nil {
return nil, err
}
+ msg := args.ToMessage(blockCtx.BaseFee)
evm := b.GetEVM(ctx, msg, state, header, &vm.Config{NoBaseFee: true}, &blockCtx)
// Wait for the context to be done and cancel the evm. Even if the
@@ -1181,11 +1182,14 @@ func DoEstimateGas(ctx context.Context, b Backend, args TransactionArgs, blockNr
State: state,
ErrorRatio: estimateGasErrorRatio,
}
- // Run the gas estimation andwrap any revertals into a custom return
- call, err := args.ToMessage(gasCap, header.BaseFee)
+ if err := args.CallDefaults(gasCap, header.BaseFee, b.ChainConfig().ChainID); err != nil {
+ return 0, err
+ }
+ call := args.ToMessage(header.BaseFee)
if err != nil {
return 0, err
}
+ // Run the gas estimation andwrap any revertals into a custom return
estimate, revert, err := gasestimator.Estimate(ctx, call, opts, gasCap)
if err != nil {
if len(revert) > 0 {
@@ -1514,18 +1518,18 @@ 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)
+ msg := args.ToMessage(header.BaseFee)
if err != nil {
return nil, 0, nil, err
}
// Apply the transaction with the access list tracer
tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles)
- config := vm.Config{Tracer: tracer, NoBaseFee: true}
+ config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true}
vmenv := b.GetEVM(ctx, msg, statedb, header, &config, nil)
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)
+ return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction().Hash(), err)
}
if tracer.Equal(prevTracer) {
return accessList, res.UsedGas, res.Err, nil
@@ -1794,7 +1798,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr
return common.Hash{}, err
}
// Assemble the transaction and sign with the wallet
- tx := args.toTransaction()
+ tx := args.ToTransaction()
signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID)
if err != nil {
@@ -1814,7 +1818,7 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr
return nil, err
}
// Assemble the transaction and obtain rlp
- tx := args.toTransaction()
+ tx := args.ToTransaction()
data, err := tx.MarshalBinary()
if err != nil {
return nil, err
@@ -1883,7 +1887,7 @@ func (s *TransactionAPI) SignTransaction(ctx context.Context, args TransactionAr
return nil, err
}
// Before actually sign the transaction, ensure the transaction fee is reasonable.
- tx := args.toTransaction()
+ tx := args.ToTransaction()
if err := checkTxFee(tx.GasPrice(), tx.Gas(), s.b.RPCTxFeeCap()); err != nil {
return nil, err
}
@@ -1931,7 +1935,7 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g
if err := sendArgs.setDefaults(ctx, s.b, false); err != nil {
return common.Hash{}, err
}
- matchTx := sendArgs.toTransaction()
+ matchTx := sendArgs.ToTransaction()
// Before replacing the old transaction, ensure the _new_ transaction fee is reasonable.
var price = matchTx.GasPrice()
@@ -1961,7 +1965,7 @@ func (s *TransactionAPI) Resend(ctx context.Context, sendArgs TransactionArgs, g
if gasLimit != nil && *gasLimit != 0 {
sendArgs.Gas = gasLimit
}
- signedTx, err := s.sign(sendArgs.from(), sendArgs.toTransaction())
+ signedTx, err := s.sign(sendArgs.from(), sendArgs.ToTransaction())
if err != nil {
return common.Hash{}, err
}
diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go
index 2751d5b5aae6..bef6082ead4c 100644
--- a/internal/ethapi/transaction_args.go
+++ b/internal/ethapi/transaction_args.go
@@ -364,41 +364,71 @@ func (args *TransactionArgs) setBlobTxSidecar(ctx context.Context, b Backend) er
return nil
}
-// 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) (*core.Message, error) {
+// 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 nil, errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
+ return errors.New("both gasPrice and (maxFeePerGas or maxPriorityFeePerGas) specified")
}
- // Set sender address or use zero address if none specified.
- addr := args.from()
-
- // Set default gas & gas price if none were set
- gas := globalGasCap
- if gas == 0 {
- gas = uint64(math.MaxUint64 / 2)
+ 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.Gas != nil {
- gas = uint64(*args.Gas)
+ if args.Nonce == nil {
+ args.Nonce = new(hexutil.Uint64)
}
- if globalGasCap != 0 && globalGasCap < gas {
- log.Warn("Caller gas above allowance, capping", "requested", gas, "cap", globalGasCap)
- gas = globalGasCap
+ if args.Value == nil {
+ args.Value = new(hexutil.Big)
}
- var (
- gasPrice *big.Int
- gasFeeCap *big.Int
- gasTipCap *big.Int
- blobFeeCap *big.Int
- )
if baseFee == nil {
// If there's no basefee, then it must be a non-1559 execution
- gasPrice = new(big.Int)
- if args.GasPrice != nil {
- gasPrice = args.GasPrice.ToInt()
+ 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
+}
+
+// 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.
+// Assumes that fields are not nil, i.e. setDefaults or CallDefaults has been called.
+func (args *TransactionArgs) ToMessage(baseFee *big.Int) *core.Message {
+ var (
+ gasPrice *big.Int
+ gasFeeCap *big.Int
+ gasTipCap *big.Int
+ )
+ if baseFee == nil {
+ gasPrice = args.GasPrice.ToInt()
gasFeeCap, gasTipCap = gasPrice, gasPrice
} else {
// A basefee is provided, necessitating 1559-type execution
@@ -408,14 +438,8 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*
gasFeeCap, gasTipCap = gasPrice, gasPrice
} else {
// User specified 1559 gas fields (or none), use those
- gasFeeCap = new(big.Int)
- if args.MaxFeePerGas != nil {
- gasFeeCap = args.MaxFeePerGas.ToInt()
- }
- gasTipCap = new(big.Int)
- if args.MaxPriorityFeePerGas != nil {
- gasTipCap = args.MaxPriorityFeePerGas.ToInt()
- }
+ gasFeeCap = args.MaxFeePerGas.ToInt()
+ gasTipCap = args.MaxPriorityFeePerGas.ToInt()
// Backfill the legacy gasPrice for EVM execution, unless we're all zeroes
gasPrice = new(big.Int)
if gasFeeCap.BitLen() > 0 || gasTipCap.BitLen() > 0 {
@@ -423,40 +447,29 @@ func (args *TransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int) (*
}
}
}
- if args.BlobFeeCap != nil {
- blobFeeCap = args.BlobFeeCap.ToInt()
- } else if args.BlobHashes != nil {
- blobFeeCap = new(big.Int)
- }
- value := new(big.Int)
- if args.Value != nil {
- value = args.Value.ToInt()
- }
- data := args.data()
var accessList types.AccessList
if args.AccessList != nil {
accessList = *args.AccessList
}
- msg := &core.Message{
- From: addr,
+ return &core.Message{
+ From: args.from(),
To: args.To,
- Value: value,
- GasLimit: gas,
+ Value: (*big.Int)(args.Value),
+ GasLimit: uint64(*args.Gas),
GasPrice: gasPrice,
GasFeeCap: gasFeeCap,
GasTipCap: gasTipCap,
- Data: data,
+ Data: args.data(),
AccessList: accessList,
- BlobGasFeeCap: blobFeeCap,
+ BlobGasFeeCap: (*big.Int)(args.BlobFeeCap),
BlobHashes: args.BlobHashes,
SkipAccountChecks: true,
}
- return msg, nil
}
-// toTransaction converts the arguments to a transaction.
+// ToTransaction converts the arguments to a transaction.
// This assumes that setDefaults has been called.
-func (args *TransactionArgs) toTransaction() *types.Transaction {
+func (args *TransactionArgs) ToTransaction() *types.Transaction {
var data types.TxData
switch {
case args.BlobHashes != nil:
diff --git a/miner/worker.go b/miner/worker.go
index f22242841f77..9f8d9f663f86 100644
--- a/miner/worker.go
+++ b/miner/worker.go
@@ -265,7 +265,7 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
snap = env.state.Snapshot()
gp = env.gasPool.Gas()
)
- receipt, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, *miner.chain.GetVMConfig())
+ receipt, err := core.ApplyTransaction(miner.chainConfig, miner.chain, &env.coinbase, env.gasPool, env.state, env.header, tx, &env.header.GasUsed, vm.Config{})
if err != nil {
env.state.RevertToSnapshot(snap)
env.gasPool.SetGas(gp)
diff --git a/tests/block_test_util.go b/tests/block_test_util.go
index 53d733f1c44d..04a04fdc288c 100644
--- a/tests/block_test_util.go
+++ b/tests/block_test_util.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/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/log"
@@ -109,7 +110,7 @@ type btHeaderMarshaling struct {
ExcessBlobGas *math.HexOrDecimal64
}
-func (t *BlockTest) Run(snapshotter bool, scheme string, tracer vm.EVMLogger, postCheck func(error, *core.BlockChain)) (result error) {
+func (t *BlockTest) Run(snapshotter bool, scheme string, tracer *tracing.Hooks, postCheck func(error, *core.BlockChain)) (result error) {
config, ok := Forks[t.json.Network]
if !ok {
return UnsupportedForkError{t.json.Network}
diff --git a/tests/state_test_util.go b/tests/state_test_util.go
index c916d26d412a..367688e57f9e 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"
@@ -227,15 +228,15 @@ func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bo
// RunNoVerify runs a specific subtest and returns the statedb and post-state root.
// Remember to call state.Close after verifying the test result!
-func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (state StateTestState, root common.Hash, err error) {
+func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (st StateTestState, root common.Hash, err error) {
config, eips, err := GetChainConfig(subtest.Fork)
if err != nil {
- return state, common.Hash{}, UnsupportedForkError{subtest.Fork}
+ return st, common.Hash{}, UnsupportedForkError{subtest.Fork}
}
vmconfig.ExtraEips = eips
block := t.genesis(config).ToBlock()
- state = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme)
+ st = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme)
var baseFee *big.Int
if config.IsLondon(new(big.Int)) {
@@ -249,7 +250,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
post := t.json.Post[subtest.Fork][subtest.Index]
msg, err := t.json.Tx.toMessage(post, baseFee)
if err != nil {
- return state, common.Hash{}, err
+ return st, common.Hash{}, err
}
{ // Blob transactions may be present after the Cancun fork.
@@ -259,7 +260,7 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
// Here, we just do this shortcut smaller fix, since state tests do not
// utilize those codepaths
if len(msg.BlobHashes)*params.BlobTxBlobGasPerBlob > params.MaxBlobGasPerBlock {
- return state, common.Hash{}, errors.New("blob gas exceeds maximum")
+ return st, common.Hash{}, errors.New("blob gas exceeds maximum")
}
}
@@ -268,10 +269,10 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
var ttx types.Transaction
err := ttx.UnmarshalBinary(post.TxBytes)
if err != nil {
- return state, common.Hash{}, err
+ return st, common.Hash{}, err
}
if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil {
- return state, common.Hash{}, err
+ return st, common.Hash{}, err
}
}
@@ -292,26 +293,26 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil {
context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas)
}
- evm := vm.NewEVM(context, txContext, state.StateDB, config, vmconfig)
+ evm := vm.NewEVM(context, txContext, st.StateDB, config, vmconfig)
// Execute the message.
- snapshot := state.StateDB.Snapshot()
+ snapshot := st.StateDB.Snapshot()
gaspool := new(core.GasPool)
gaspool.AddGas(block.GasLimit())
_, err = core.ApplyMessage(evm, msg, gaspool)
if err != nil {
- state.StateDB.RevertToSnapshot(snapshot)
+ st.StateDB.RevertToSnapshot(snapshot)
}
// Add 0-value mining reward. This only makes a difference in the cases
// where
// - the coinbase self-destructed, 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
- state.StateDB.AddBalance(block.Coinbase(), new(uint256.Int))
+ st.StateDB.AddBalance(block.Coinbase(), new(uint256.Int), tracing.BalanceChangeUnspecified)
// Commit state mutations into database.
- root, _ = state.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
- return state, root, err
+ root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()))
+ return st, root, err
}
func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
@@ -456,7 +457,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, uint256.MustFromBig(a.Balance))
+ statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceChangeUnspecified)
for k, v := range a.Storage {
statedb.SetState(addr, k, v)
}