diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index c05e76e1a5..6a2d788a4a 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -54,6 +54,7 @@ import (
"github.com/ethereum/go-ethereum/eth/filters"
"github.com/ethereum/go-ethereum/eth/gasprice"
"github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/ethdb/remotedb"
"github.com/ethereum/go-ethereum/ethstats"
@@ -518,9 +519,9 @@ var (
Usage: "Record information useful for VM and contract debugging",
Category: flags.VMCategory,
}
- VMTraceFlag = &cli.BoolFlag{
+ VMTraceFlag = &cli.StringFlag{
Name: "vmtrace",
- Usage: "Record internal VM operations (costly)",
+ Usage: "Name of tracer which should record internal VM operations (costly)",
Category: flags.VMCategory,
}
@@ -1723,9 +1724,6 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
// TODO(fjl): force-enable this in --dev mode
cfg.EnablePreimageRecording = ctx.Bool(VMEnableDebugFlag.Name)
}
- if ctx.IsSet(VMTraceFlag.Name) {
- cfg.LiveTrace = ctx.Bool(VMTraceFlag.Name)
- }
if ctx.IsSet(RPCGlobalGasCapFlag.Name) {
cfg.RPCGasCap = ctx.Uint64(RPCGlobalGasCapFlag.Name)
@@ -2143,7 +2141,13 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
}
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}
if ctx.IsSet(VMTraceFlag.Name) {
- vmcfg.Tracer = tracers.NewPrinter()
+ if name := ctx.String(VMTraceFlag.Name); name != "" {
+ t, err := directory.LiveDirectory.New(name)
+ 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)
diff --git a/core/blockchain.go b/core/blockchain.go
index 70418e7624..75c4e3f9bf 100644
--- a/core/blockchain.go
+++ b/core/blockchain.go
@@ -1774,121 +1774,117 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Process block using the parent state as reference point
pstart := time.Now()
- if bc.logger != nil {
- td := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
- bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock())
- }
- receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
- if err != nil {
- bc.reportBlock(block, receipts, err)
+ // The traced section of block import.
+ err, stop := func() (blockEndErr error, _ bool) {
+ if bc.logger != nil {
+ td := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
+ bc.logger.OnBlockStart(block, td, bc.CurrentFinalBlock(), bc.CurrentSafeBlock())
+ defer func() {
+ bc.logger.OnBlockEnd(blockEndErr)
+ }()
+ }
+ receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
+ if err != nil {
+ bc.reportBlock(block, receipts, err)
+ followupInterrupt.Store(true)
+ return err, true
+ }
+ 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 err, true
+ }
+ 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)
+ }
followupInterrupt.Store(true)
- if bc.logger != nil {
- bc.logger.OnBlockEnd(err)
+ if err != nil {
+ return err, true
}
- return it.index, err
- }
- ptime := time.Since(pstart)
+ // 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
- vstart := time.Now()
- if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
- bc.reportBlock(block, receipts, err)
- followupInterrupt.Store(true)
- if bc.logger != nil {
- bc.logger.OnBlockEnd(err)
+ 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
+
+ dirty, _ := bc.triedb.Size()
+ stats.report(chain, it.index, dirty, setHead)
+
+ if !setHead {
+ // After merge we expect few side chains. Simply count
+ // all blocks the CL gives us for GC processing time
+ bc.gcproc += proctime
+
+ return nil, true // Direct block insertion of a single block
}
- return it.index, err
- }
- vtime := time.Since(vstart)
- proctime := time.Since(start) // processing + validation
+ switch 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(),
+ "elapsed", common.PrettyDuration(time.Since(start)),
+ "root", block.Root())
- // 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
+ lastCanon = block
- // 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)
- }
- followupInterrupt.Store(true)
- if err != nil {
- if bc.logger != nil {
- bc.logger.OnBlockEnd(err)
+ // Only count canonical blocks for GC processing time
+ bc.gcproc += proctime
+
+ case SideStatTy:
+ log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(),
+ "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
+ "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
+ "root", block.Root())
+
+ default:
+ // This in theory is impossible, but lets be nice to our future selves and leave
+ // a log, instead of trying to track down blocks imports that don't emit logs.
+ log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(),
+ "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
+ "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
+ "root", block.Root())
}
+ return nil, false
+ }()
+ if err != nil || stop {
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
-
- dirty, _ := bc.triedb.Size()
- stats.report(chain, it.index, dirty, setHead)
-
- if bc.logger != nil {
- bc.logger.OnBlockEnd(nil)
- }
-
- if !setHead {
- // After merge we expect few side chains. Simply count
- // all blocks the CL gives us for GC processing time
- bc.gcproc += proctime
-
- return it.index, nil // Direct block insertion of a single block
- }
- switch 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(),
- "elapsed", common.PrettyDuration(time.Since(start)),
- "root", block.Root())
-
- lastCanon = block
-
- // Only count canonical blocks for GC processing time
- bc.gcproc += proctime
-
- case SideStatTy:
- log.Debug("Inserted forked block", "number", block.Number(), "hash", block.Hash(),
- "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
- "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
- "root", block.Root())
-
- default:
- // This in theory is impossible, but lets be nice to our future selves and leave
- // a log, instead of trying to track down blocks imports that don't emit logs.
- log.Warn("Inserted block with unknown status", "number", block.Number(), "hash", block.Hash(),
- "diff", block.Difficulty(), "elapsed", common.PrettyDuration(time.Since(start)),
- "txs", len(block.Transactions()), "gas", block.GasUsed(), "uncles", len(block.Uncles()),
- "root", block.Root())
- }
}
// Any blocks remaining here? The only ones we care about are the future ones
diff --git a/core/blockchain_test.go b/core/blockchain_test.go
index 1b4b569575..b5b9ff4e48 100644
--- a/core/blockchain_test.go
+++ b/core/blockchain_test.go
@@ -36,7 +36,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
@@ -3024,7 +3023,7 @@ func TestDeleteRecreateSlots(t *testing.T) {
})
// Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
- Tracer: logger.NewJSONLogger(nil, os.Stdout),
+ //Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
@@ -3101,7 +3100,7 @@ func TestDeleteRecreateAccount(t *testing.T) {
})
// Import the canonical chain
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), nil, gspec, nil, engine, vm.Config{
- Tracer: logger.NewJSONLogger(nil, os.Stdout),
+ //Tracer: logger.NewJSONLogger(nil, os.Stdout),
}, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
@@ -4307,7 +4306,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)*/ }, nil, nil)
if err != nil {
t.Fatalf("failed to create tester chain: %v", err)
}
diff --git a/core/rawdb/database.go b/core/rawdb/database.go
index e864bcb2e8..2108eebba3 100644
--- a/core/rawdb/database.go
+++ b/core/rawdb/database.go
@@ -317,6 +317,7 @@ func NewLevelDBDatabase(file string, cache int, handles int, namespace string, r
if err != nil {
return nil, err
}
+
log.Info("Using LevelDB as the backing database")
return NewDatabase(db), nil
}
diff --git a/core/state/statedb.go b/core/state/statedb.go
index 3f52b9f736..b3ee524fc1 100644
--- a/core/state/statedb.go
+++ b/core/state/statedb.go
@@ -56,6 +56,8 @@ func (n *proofList) Delete(key []byte) error {
// StateLogger is used to collect state update traces from EVM transaction
// execution.
+// The following hooks are invoked post execution. I.e. looking up state
+// after the hook should reflect the new value.
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
type StateLogger interface {
diff --git a/core/state_transition.go b/core/state_transition.go
index 99e04a7fbb..79b076ab88 100644
--- a/core/state_transition.go
+++ b/core/state_transition.go
@@ -265,7 +265,7 @@ func (st *StateTransition) buyGas() error {
}
if st.evm.Config.Tracer != nil {
- st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasInitialBalance)
+ st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, vm.GasChangeTxInitialBalance)
}
st.gasRemaining += st.msg.GasLimit
@@ -391,7 +391,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas)
}
if t := st.evm.Config.Tracer; t != nil {
- t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, vm.GasChangeIntrinsicGas)
+ t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, vm.GasChangeTxIntrinsicGas)
}
st.gasRemaining -= gas
@@ -458,8 +458,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
refund = st.state.GetRefund()
}
- if st.evm.Config.Tracer != nil {
- st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, vm.GasRefunded)
+ if st.evm.Config.Tracer != nil && refund > 0 {
+ st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, vm.GasChangeTxRefunds)
}
st.gasRemaining += refund
@@ -468,8 +468,8 @@ func (st *StateTransition) refundGas(refundQuotient uint64) {
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gasRemaining), st.msg.GasPrice)
st.state.AddBalance(st.msg.From, remaining, state.BalanceChangeGasRefund)
- if st.evm.Config.Tracer != nil {
- st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasBuyBack)
+ if st.evm.Config.Tracer != nil && st.gasRemaining > 0 {
+ st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, vm.GasChangeTxBuyBack)
}
// Also return remaining gas to the block gas counter so it is
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 9f7b4e44d4..7c1cf888bb 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -174,7 +174,7 @@ func RunPrecompiledContract(p PrecompiledContract, input []byte, suppliedGas uin
return nil, 0, ErrOutOfGas
}
if logger != nil {
- logger.OnGasChange(suppliedGas, suppliedGas-gasCost, GasChangePrecompiledContract)
+ logger.OnGasChange(suppliedGas, suppliedGas-gasCost, GasChangeCallPrecompiledContract)
}
suppliedGas -= gasCost
output, err := p.Run(input)
diff --git a/core/vm/evm.go b/core/vm/evm.go
index 884de10441..45dbc52fbb 100644
--- a/core/vm/evm.go
+++ b/core/vm/evm.go
@@ -189,9 +189,9 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
} else {
// Handle tracer events for entering and exiting a call frame
evm.Config.Tracer.CaptureEnter(CALL, caller.Address(), addr, input, gas, value)
- evm.Config.Tracer.OnGasChange(0, gas, GasInitialBalance)
+ evm.Config.Tracer.OnGasChange(0, gas, GasChangeCallInitialBalance)
defer func(startGas uint64) {
- evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasBuyBack)
+ evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverRefunded)
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
}(gas)
}
@@ -241,7 +241,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if evm.Config.Tracer != nil {
- evm.Config.Tracer.OnGasChange(gas, 0, GasChangeFailedExecution)
+ evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution)
}
gas = 0
@@ -264,9 +264,9 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
// 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)
- evm.Config.Tracer.OnGasChange(0, gas, GasInitialBalance)
+ evm.Config.Tracer.OnGasChange(0, gas, GasChangeCallInitialBalance)
defer func(startGas uint64) {
- evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasBuyBack)
+ evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverRefunded)
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
}(gas)
}
@@ -299,7 +299,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if evm.Config.Tracer != nil {
- evm.Config.Tracer.OnGasChange(gas, 0, GasChangeFailedExecution)
+ evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution)
}
gas = 0
@@ -321,9 +321,9 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
parent := caller.(*Contract)
// DELEGATECALL inherits value from parent call
evm.Config.Tracer.CaptureEnter(DELEGATECALL, caller.Address(), addr, input, gas, parent.value)
- evm.Config.Tracer.OnGasChange(0, gas, GasInitialBalance)
+ evm.Config.Tracer.OnGasChange(0, gas, GasChangeCallInitialBalance)
defer func(startGas uint64) {
- evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasBuyBack)
+ evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverRefunded)
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
}(gas)
}
@@ -348,7 +348,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if evm.Config.Tracer != nil {
- evm.Config.Tracer.OnGasChange(gas, 0, GasChangeFailedExecution)
+ evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution)
}
gas = 0
@@ -365,9 +365,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// 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)
- evm.Config.Tracer.OnGasChange(0, gas, GasInitialBalance)
+ evm.Config.Tracer.OnGasChange(0, gas, GasChangeCallInitialBalance)
defer func(startGas uint64) {
- evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasBuyBack)
+ evm.Config.Tracer.OnGasChange(leftOverGas, 0, GasChangeCallLeftOverRefunded)
evm.Config.Tracer.CaptureExit(ret, startGas-gas, err)
}(gas)
}
@@ -409,7 +409,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
if evm.Config.Tracer != nil {
- evm.Config.Tracer.OnGasChange(gas, 0, GasChangeFailedExecution)
+ evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution)
}
gas = 0
@@ -440,9 +440,9 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
}()
} else {
evm.Config.Tracer.CaptureEnter(typ, caller.Address(), address, codeAndHash.code, gas, value)
- evm.Config.Tracer.OnGasChange(0, gas, GasInitialBalance)
+ evm.Config.Tracer.OnGasChange(0, gas, GasChangeCallInitialBalance)
defer func() {
- evm.Config.Tracer.OnGasChange(leftoverGas, 0, GasBuyBack)
+ evm.Config.Tracer.OnGasChange(leftoverGas, 0, GasChangeCallLeftOverRefunded)
evm.Config.Tracer.CaptureExit(ret, gas-leftoverGas, err)
}()
}
@@ -469,7 +469,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
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(gas, 0, GasChangeFailedExecution)
+ evm.Config.Tracer.OnGasChange(gas, 0, GasChangeCallFailedExecution)
}
return nil, common.Address{}, 0, ErrContractAddressCollision
@@ -505,7 +505,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, evm.Config.Tracer, GasChangeCodeStorage) {
+ if contract.UseGas(createDataGas, evm.Config.Tracer, GasChangeCallCodeStorage) {
evm.StateDB.SetCode(address, ret)
} else {
err = ErrCodeStoreOutOfGas
@@ -518,7 +518,7 @@ func (evm *EVM) create(caller ContractRef, codeAndHash *codeAndHash, gas uint64,
if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) {
evm.StateDB.RevertToSnapshot(snapshot)
if err != ErrExecutionReverted {
- contract.UseGas(contract.Gas, evm.Config.Tracer, GasChangeFailedExecution)
+ contract.UseGas(contract.Gas, evm.Config.Tracer, GasChangeCallFailedExecution)
}
}
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 0d5b253951..42e55fcfa9 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -592,7 +592,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
// reuse size int for stackvalue
stackvalue := size
- scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeContractCreation)
+ scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeCallContractCreation)
//TODO: use uint256.Int instead of converting with toBig()
var bigVal = big0
if !value.IsZero() {
@@ -614,7 +614,7 @@ func opCreate(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]b
scope.Stack.push(&stackvalue)
if interpreter.evm.Config.Tracer != nil {
- interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded)
+ interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverReturned)
}
scope.Contract.Gas += returnGas
@@ -640,7 +640,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
)
// Apply EIP150
gas -= gas / 64
- scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeContractCreation2)
+ scope.Contract.UseGas(gas, interpreter.evm.Config.Tracer, GasChangeCallContractCreation2)
// reuse size int for stackvalue
stackvalue := size
//TODO: use uint256.Int instead of converting with toBig()
@@ -659,7 +659,7 @@ func opCreate2(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]
scope.Stack.push(&stackvalue)
if interpreter.evm.Config.Tracer != nil {
- interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded)
+ interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverReturned)
}
scope.Contract.Gas += returnGas
@@ -709,7 +709,7 @@ func opCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byt
}
if interpreter.evm.Config.Tracer != nil {
- interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded)
+ interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverReturned)
}
scope.Contract.Gas += returnGas
@@ -749,7 +749,7 @@ func opCallCode(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([
}
if interpreter.evm.Config.Tracer != nil {
- interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded)
+ interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverReturned)
}
scope.Contract.Gas += returnGas
@@ -782,7 +782,7 @@ func opDelegateCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext
}
if interpreter.evm.Config.Tracer != nil {
- interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded)
+ interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverReturned)
}
scope.Contract.Gas += returnGas
@@ -815,7 +815,7 @@ func opStaticCall(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
}
if interpreter.evm.Config.Tracer != nil {
- interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverRefunded)
+ interpreter.evm.Config.Tracer.OnGasChange(scope.Contract.Gas, scope.Contract.Gas+returnGas, GasChangeCallLeftOverReturned)
}
scope.Contract.Gas += returnGas
diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go
index 31ad6d142b..b02011fa0f 100644
--- a/core/vm/interpreter.go
+++ b/core/vm/interpreter.go
@@ -185,7 +185,7 @@ 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, in.evm.Config.Tracer, GasChangeOpCode) {
+ if !contract.UseGas(cost, in.evm.Config.Tracer, GasChangeCallOpCode) {
return nil, ErrOutOfGas
}
if operation.dynamicGas != nil {
@@ -211,7 +211,7 @@ 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, in.evm.Config.Tracer, GasChangeOpCode) {
+ if err != nil || !contract.UseGas(dynamicCost, in.evm.Config.Tracer, GasChangeCallOpCode) {
return nil, ErrOutOfGas
}
// Do tracing before memory expansion
diff --git a/core/vm/logger.go b/core/vm/logger.go
index 70da7ba9f1..2175c32ad2 100644
--- a/core/vm/logger.go
+++ b/core/vm/logger.go
@@ -48,47 +48,52 @@ type EVMLogger interface {
// 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 = iota
- // GasInitialBalance is the initial balance for the call which will be equal to the gasLimit of the call
- GasInitialBalance
- // GasRefunded is the amount of gas that will be refunded to the caller for data returned to the chain
- // PR Review: Is that the right description? Called in core/state_transition.go#StateTransition.refundGas
- GasRefunded
- // GasBuyBack is the amount of gas that will be bought back by the chain and returned in Wei to the caller
- GasBuyBack
- // GasChangeIntrinsicGas is the amount of gas that will be charged for the intrinsic cost of the transaction, there is
+ // 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
+ // 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
- GasChangeIntrinsicGas
+ GasChangeTxIntrinsicGas
+ // 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 only one such gas change per transaction.
+ GasChangeTxRefunds
+ // GasChangeTxBuyBack is the amount of gas that will be bought back by the chain and returned in Wei to the caller at the very
+ // end of the transaction's execution. There is only one such gas change per transaction.
+ GasChangeTxBuyBack
- // PR Review: `GasChangeContractCreation/2` are actually the EIP150 burn cost of CREATE/CREATE2 respectively.
- // I think our old name `GasChangeContractCreation/2` is not really accurate. I don't
- // think that using EIP150 as a name is a good idea as rules can change in the future. So
- // maybe we can just call them `GasChangeCreateBurn/GasChangeCreate2Burn`? Burn might
- // feels like the wrong term, `Stipend` came to mind also but I'm unsure.
- //
- // I would like also to keep the distinction between CREATE and CREATE2 however, it's an
- // important thing IMO as they are different and could use different rules in the future.
-
- // GasChangeContractCreation is the amount of gas that will be burned for a CREATE, today controlled by EIP150 rules
- GasChangeContractCreation
- // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2, today controlled by EIP150 rules
- GasChangeContractCreation2
- // GasChangeCodeStorage is the amount of gas that will be charged for code storage
- GasChangeCodeStorage
- // GasChangeOpCode 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 `CaptureState` handling
- GasChangeOpCode
- // GasChangePrecompiledContract is the amount of gas that will be charged for a precompiled contract execution
- GasChangePrecompiledContract
- // GasChangeStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules
- GasChangeStorageColdAccess
-
- // GasChangeCallLeftOverRefunded is the amount of gas that will be refunded to the caller after the execution of the call, if there is left over at the end of execution
+ // 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
+ // 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.
+ GasChangeCallLeftOverReturned
+ // 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.
GasChangeCallLeftOverRefunded
- // GasChangeFailedExecution is the burning of the remaining gas when the execution failed without a revert
- GasChangeFailedExecution
+ // GasChangeCallContractCreation is the amount of gas that will be burned for a CREATE, today controlled by EIP150 rules.
+ GasChangeCallContractCreation
+ // GasChangeContractCreation is the amount of gas that will be burned for a CREATE2, today controlled by EIP150 rules.
+ GasChangeCallContractCreation2
+ // GasChangeCallCodeStorage is the amount of gas that will be charged for code storage.
+ GasChangeCallCodeStorage
+ // 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 `CaptureState` handling.
+ GasChangeCallOpCode
+ // GasChangeCallPrecompiledContract is the amount of gas that will be charged for a precompiled contract execution.
+ GasChangeCallPrecompiledContract
+ // GasChangeCallStorageColdAccess is the amount of gas that will be charged for a cold storage access as controlled by EIP2929 rules.
+ GasChangeCallStorageColdAccess
+ // GasChangeCallFailedExecution is the burning of the remaining gas when the execution failed without a revert.
+ GasChangeCallFailedExecution
)
diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go
index 00f46395fe..55c9bf34b9 100644
--- a/core/vm/operations_acl.go
+++ b/core/vm/operations_acl.go
@@ -169,7 +169,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, evm.Config.Tracer, GasChangeStorageColdAccess) {
+ if !contract.UseGas(coldCost, evm.Config.Tracer, GasChangeCallStorageColdAccess) {
return 0, ErrOutOfGas
}
}
diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go
index f411a67f8d..51d8cbe62f 100644
--- a/core/vm/runtime/runtime_test.go
+++ b/core/vm/runtime/runtime_test.go
@@ -32,7 +32,7 @@ import (
"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/eth/tracers/directory"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/params"
@@ -330,7 +330,7 @@ func benchmarkNonModifyingCode(gas uint64, code []byte, name string, tracerCode
cfg.State, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
cfg.GasLimit = gas
if len(tracerCode) > 0 {
- tracer, err := tracers.DefaultDirectory.New(tracerCode, new(tracers.Context), nil)
+ tracer, err := directory.DefaultDirectory.New(tracerCode, new(directory.Context), nil)
if err != nil {
b.Fatal(err)
}
@@ -826,7 +826,7 @@ func TestRuntimeJSTracer(t *testing.T) {
statedb.SetCode(common.HexToAddress("0xee"), calleeCode)
statedb.SetCode(common.HexToAddress("0xff"), suicideCode)
- tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
+ tracer, err := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil)
if err != nil {
t.Fatal(err)
}
@@ -861,7 +861,7 @@ func TestJSTracerCreateTx(t *testing.T) {
code := []byte{byte(vm.PUSH1), 0, byte(vm.PUSH1), 0, byte(vm.RETURN)}
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
- tracer, err := tracers.DefaultDirectory.New(jsTracer, new(tracers.Context), nil)
+ tracer, err := directory.DefaultDirectory.New(jsTracer, new(directory.Context), nil)
if err != nil {
t.Fatal(err)
}
diff --git a/eth/backend.go b/eth/backend.go
index 031ff46d1e..ca762fdce1 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -44,7 +44,6 @@ 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"
@@ -194,10 +193,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
Preimages: config.Preimages,
}
)
- if config.LiveTrace {
- // vmConfig.Tracer = tracers.NewPrinter()
- vmConfig.Tracer = tracers.NewFirehoseLogger()
- }
+
// 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 55dd56316e..4bc8b8dc6c 100644
--- a/eth/ethconfig/config.go
+++ b/eth/ethconfig/config.go
@@ -140,9 +140,6 @@ type Config struct {
// Enables tracking of SHA3 preimages in the VM
EnablePreimageRecording bool
- // LiveTrace will enable tracing during normal chain processing.
- LiveTrace bool
-
// Miscellaneous options
DocRoot string `toml:"-"`
diff --git a/eth/tracers/api.go b/eth/tracers/api.go
index 1d3c57dc7c..69fe38ba20 100644
--- a/eth/tracers/api.go
+++ b/eth/tracers/api.go
@@ -37,6 +37,7 @@ import (
"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/directory"
"github.com/ethereum/go-ethereum/eth/tracers/logger"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/internal/ethapi"
@@ -272,7 +273,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
// Trace all the transactions contained within
for i, tx := range task.block.Transactions() {
msg, _ := core.TransactionToMessage(tx, signer, task.block.BaseFee())
- txctx := &Context{
+ txctx := &directory.Context{
BlockHash: task.block.Hash(),
BlockNumber: task.block.Number(),
TxIndex: i,
@@ -591,7 +592,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
// process that generates states in one thread and traces txes
// in separate worker threads.
if config != nil && config.Tracer != nil && *config.Tracer != "" {
- if isJS := DefaultDirectory.IsJS(*config.Tracer); isJS {
+ if isJS := directory.DefaultDirectory.IsJS(*config.Tracer); isJS {
return api.traceBlockParallel(ctx, block, statedb, config)
}
}
@@ -607,7 +608,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
- txctx := &Context{
+ txctx := &directory.Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: i,
@@ -650,7 +651,7 @@ func (api *API) traceBlockParallel(ctx context.Context, block *types.Block, stat
// Fetch and execute the next transaction trace tasks
for task := range jobs {
msg, _ := core.TransactionToMessage(txs[task.index], signer, block.BaseFee())
- txctx := &Context{
+ txctx := &directory.Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: task.index,
@@ -859,7 +860,7 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
return nil, err
}
- txctx := &Context{
+ txctx := &directory.Context{
BlockHash: blockHash,
BlockNumber: block.Number(),
TxIndex: int(index),
@@ -927,15 +928,15 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if config != nil {
traceConfig = &config.TraceConfig
}
- return api.traceTx(ctx, tx, msg, new(Context), vmctx, statedb, traceConfig)
+ return api.traceTx(ctx, tx, msg, new(directory.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, tx *types.Transaction, 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 *directory.Context, vmctx vm.BlockContext, statedb *state.StateDB, config *TraceConfig) (interface{}, error) {
var (
- tracer Tracer
+ tracer directory.Tracer
err error
timeout = defaultTraceTimeout
txContext = core.NewEVMTxContext(message)
@@ -946,7 +947,7 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
// Default tracer is the struct logger
tracer = logger.NewStructLogger(config.Config)
if config.Tracer != nil {
- tracer, err = DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
+ tracer, err = directory.DefaultDirectory.New(*config.Tracer, txctx, config.TracerConfig)
if err != nil {
return nil, err
}
diff --git a/eth/tracers/directory/live.go b/eth/tracers/directory/live.go
new file mode 100644
index 0000000000..dc6927b142
--- /dev/null
+++ b/eth/tracers/directory/live.go
@@ -0,0 +1,30 @@
+package directory
+
+import (
+ "errors"
+
+ "github.com/ethereum/go-ethereum/core"
+)
+
+type ctorFunc func() (core.BlockchainLogger, 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) (core.BlockchainLogger, error) {
+ if f, ok := d.elems[name]; ok {
+ return f()
+ }
+ return nil, errors.New("not found")
+}
diff --git a/eth/tracers/noop.go b/eth/tracers/directory/noop.go
similarity index 99%
rename from eth/tracers/noop.go
rename to eth/tracers/directory/noop.go
index 428c13fef4..973b1abb47 100644
--- a/eth/tracers/noop.go
+++ b/eth/tracers/directory/noop.go
@@ -14,7 +14,7 @@
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see .
-package tracers
+package directory
import (
"encoding/json"
diff --git a/eth/tracers/tracers.go b/eth/tracers/directory/tracers.go
similarity index 80%
rename from eth/tracers/tracers.go
rename to eth/tracers/directory/tracers.go
index c82fcf92ac..b16d9d2fe6 100644
--- a/eth/tracers/tracers.go
+++ b/eth/tracers/directory/tracers.go
@@ -14,13 +14,13 @@
// 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
+// Package directory provides functionality to lookup tracers by name.
+// It also includes utility functions that are imported by the other
+// tracing packages.
+package directory
import (
"encoding/json"
- "errors"
- "fmt"
"math/big"
"github.com/ethereum/go-ethereum/common"
@@ -101,27 +101,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/directory/util.go b/eth/tracers/directory/util.go
new file mode 100644
index 0000000000..92de735291
--- /dev/null
+++ b/eth/tracers/directory/util.go
@@ -0,0 +1,47 @@
+// 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 directory
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/ethereum/go-ethereum/core/vm"
+)
+
+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/directory/util_test.go b/eth/tracers/directory/util_test.go
new file mode 100644
index 0000000000..c72096708d
--- /dev/null
+++ b/eth/tracers/directory/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 directory
+
+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}, // Errror
+ {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Errror
+ {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Errror
+
+ } {
+ mem := vm.NewMemory()
+ mem.Resize(uint64(tc.memsize))
+ cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size)
+ if want := tc.wantErr; want != "" {
+ if err == nil {
+ t.Fatalf("test %d: want '%v' have no error", i, want)
+ }
+ if have := err.Error(); want != have {
+ t.Fatalf("test %d: want '%v' have '%v'", i, want, have)
+ }
+ continue
+ }
+ if err != nil {
+ t.Fatalf("test %d: unexpected error: %v", i, err)
+ }
+ if want, have := tc.wantSize, len(cpy); have != want {
+ t.Fatalf("test %d: want %v have %v", i, want, have)
+ }
+ }
+}
diff --git a/eth/tracers/firehose.go b/eth/tracers/firehose.go
index f1decd30cb..748df26585 100644
--- a/eth/tracers/firehose.go
+++ b/eth/tracers/firehose.go
@@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/rlp"
pbeth "github.com/streamingfast/firehose-ethereum/types/pb/sf/ethereum/type/v2"
"golang.org/x/exp/maps"
@@ -30,6 +31,8 @@ import (
"google.golang.org/protobuf/types/known/timestamppb"
)
+var _ core.BlockchainLogger = (*Firehose)(nil)
+
var firehoseTracerLogLevel = strings.ToLower(os.Getenv("GETH_FIREHOSE_TRACER_LOG_LEVEL"))
var isFirehoseDebugEnabled = firehoseTracerLogLevel == "debug" || firehoseTracerLogLevel == "trace"
var isFirehoseTracerEnabled = firehoseTracerLogLevel == "trace"
@@ -41,6 +44,13 @@ var emptyCommonHash = common.Hash{}
func init() {
staticFirehoseChainValidationOnInit()
+
+ directory.LiveDirectory.Register("firehose", newFirehoseTracer)
+}
+
+func newFirehoseTracer() (core.BlockchainLogger, error) {
+ firehoseDebug("New firehose tracer")
+ return NewFirehoseLogger(), nil
}
type Firehose struct {
@@ -759,7 +769,7 @@ func (f *Firehose) OnGasChange(old, new uint64, reason vm.GasChangeReason) {
return
}
- if reason == vm.GasChangeOpCode {
+ if reason == vm.GasChangeCallOpCode {
// We ignore those because we track OpCode gas consumption manually by tracking the gas value at `CaptureState` call
return
}
@@ -770,7 +780,7 @@ func (f *Firehose) OnGasChange(old, new uint64, reason vm.GasChangeReason) {
// For new chain, this code should be remove so that they are included and useful to user.
//
// Ref eb1916a67d9bea03df16a7a3e2cfac72
- if reason == vm.GasInitialBalance || reason == vm.GasRefunded || reason == vm.GasBuyBack {
+ if reason == vm.GasChangeTxInitialBalance || reason == vm.GasChangeTxRefunds || reason == vm.GasChangeTxBuyBack {
return
}
@@ -1111,24 +1121,26 @@ var gasChangeReasonToPb = map[vm.GasChangeReason]pbeth.GasChange_Reason{
//
// New chain should uncomment the code below and remove the same assigments to UNKNOWN
//
- // vm.GasInitialBalance: pbeth.GasChange_REASON_INITIAL_BALANCE,
- // vm.GasRefunded: pbeth.GasChange_REASON_REFUND,
- // vm.GasBuyBack: pbeth.GasChange_REASON_BUYBACK,
- vm.GasInitialBalance: pbeth.GasChange_REASON_UNKNOWN,
- vm.GasRefunded: pbeth.GasChange_REASON_UNKNOWN,
- vm.GasBuyBack: pbeth.GasChange_REASON_UNKNOWN,
+ // vm.GasChangeTxInitialBalance: pbeth.GasChange_REASON_INITIAL_BALANCE,
+ // vm.GasChangeTxRefunds: pbeth.GasChange_REASON_REFUND,
+ // vm.GasChangeTxBuyBack: pbeth.GasChange_REASON_BUYBACK,
+ // vm.GasChangeCallInitialBalance: pbeth.GasChange_REASON_BUYBACK,
+ vm.GasChangeTxInitialBalance: pbeth.GasChange_REASON_UNKNOWN,
+ vm.GasChangeTxRefunds: pbeth.GasChange_REASON_UNKNOWN,
+ vm.GasChangeTxBuyBack: pbeth.GasChange_REASON_UNKNOWN,
+ vm.GasChangeCallInitialBalance: pbeth.GasChange_REASON_UNKNOWN,
- vm.GasChangeIntrinsicGas: pbeth.GasChange_REASON_INTRINSIC_GAS,
- vm.GasChangeContractCreation: pbeth.GasChange_REASON_CONTRACT_CREATION,
- vm.GasChangeContractCreation2: pbeth.GasChange_REASON_CONTRACT_CREATION2,
- vm.GasChangeCodeStorage: pbeth.GasChange_REASON_CODE_STORAGE,
- vm.GasChangePrecompiledContract: pbeth.GasChange_REASON_PRECOMPILED_CONTRACT,
- vm.GasChangeStorageColdAccess: pbeth.GasChange_REASON_STATE_COLD_ACCESS,
- vm.GasChangeCallLeftOverRefunded: pbeth.GasChange_REASON_REFUND_AFTER_EXECUTION,
- vm.GasChangeFailedExecution: pbeth.GasChange_REASON_FAILED_EXECUTION,
+ vm.GasChangeTxIntrinsicGas: pbeth.GasChange_REASON_INTRINSIC_GAS,
+ vm.GasChangeCallContractCreation: pbeth.GasChange_REASON_CONTRACT_CREATION,
+ vm.GasChangeCallContractCreation2: pbeth.GasChange_REASON_CONTRACT_CREATION2,
+ vm.GasChangeCallCodeStorage: pbeth.GasChange_REASON_CODE_STORAGE,
+ vm.GasChangeCallPrecompiledContract: pbeth.GasChange_REASON_PRECOMPILED_CONTRACT,
+ vm.GasChangeCallStorageColdAccess: pbeth.GasChange_REASON_STATE_COLD_ACCESS,
+ vm.GasChangeCallLeftOverRefunded: pbeth.GasChange_REASON_REFUND_AFTER_EXECUTION,
+ vm.GasChangeCallFailedExecution: pbeth.GasChange_REASON_FAILED_EXECUTION,
// Ignored, we track them manually, newGasChange ensure that we panic if we see Unknown
- vm.GasChangeOpCode: pbeth.GasChange_REASON_UNKNOWN,
+ vm.GasChangeCallOpCode: pbeth.GasChange_REASON_UNKNOWN,
}
func gasChangeReasonFromChain(reason vm.GasChangeReason) pbeth.GasChange_Reason {
@@ -1180,6 +1192,10 @@ func gasPrice(tx *types.Transaction, baseFee *big.Int) *pbeth.BigInt {
panic(errUnhandledTransactionType("gasPrice", tx.Type()))
}
+func FirehoseDebug(msg string, args ...interface{}) {
+ firehoseDebug(msg, args...)
+}
+
func firehoseDebug(msg string, args ...interface{}) {
if isFirehoseDebugEnabled {
fmt.Fprintf(os.Stderr, "[Firehose] "+msg+"\n", args...)
diff --git a/eth/tracers/internal/tracetest/calltrace_test.go b/eth/tracers/internal/tracetest/calltrace_test.go
index a0001118a8..d342f2109d 100644
--- a/eth/tracers/internal/tracetest/calltrace_test.go
+++ b/eth/tracers/internal/tracetest/calltrace_test.go
@@ -33,7 +33,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/tests"
@@ -141,7 +141,7 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
}
_, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
)
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
@@ -247,7 +247,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil)
+ tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), nil)
if err != nil {
b.Fatalf("failed to create call tracer: %v", err)
}
@@ -283,8 +283,8 @@ func TestInternals(t *testing.T) {
BaseFee: new(big.Int),
}
)
- mkTracer := func(name string, cfg json.RawMessage) tracers.Tracer {
- tr, err := tracers.DefaultDirectory.New(name, nil, cfg)
+ mkTracer := func(name string, cfg json.RawMessage) directory.Tracer {
+ tr, err := directory.DefaultDirectory.New(name, nil, cfg)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
@@ -294,7 +294,7 @@ func TestInternals(t *testing.T) {
for _, tc := range []struct {
name string
code []byte
- tracer tracers.Tracer
+ tracer directory.Tracer
want string
}{
{
diff --git a/eth/tracers/internal/tracetest/flat_calltrace_test.go b/eth/tracers/internal/tracetest/flat_calltrace_test.go
index f8ca103314..be552ccfd5 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/directory"
"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,7 +101,7 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
_, statedb := tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
// Create the tracer, the EVM environment and run it
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig)
if err != nil {
return fmt.Errorf("failed to create call tracer: %v", err)
}
diff --git a/eth/tracers/internal/tracetest/prestate_test.go b/eth/tracers/internal/tracetest/prestate_test.go
index 74d5492d52..dc2e7293b9 100644
--- a/eth/tracers/internal/tracetest/prestate_test.go
+++ b/eth/tracers/internal/tracetest/prestate_test.go
@@ -29,7 +29,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/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/tests"
)
@@ -110,7 +110,7 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
}
_, statedb = tests.MakePreState(rawdb.NewMemoryDatabase(), test.Genesis.Alloc, false)
)
- tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), test.TracerConfig)
+ tracer, err := directory.DefaultDirectory.New(tracerName, new(directory.Context), test.TracerConfig)
if err != nil {
t.Fatalf("failed to create call tracer: %v", err)
}
diff --git a/eth/tracers/js/goja.go b/eth/tracers/js/goja.go
index 8ed55ef1c6..c21b01525a 100644
--- a/eth/tracers/js/goja.go
+++ b/eth/tracers/js/goja.go
@@ -24,12 +24,12 @@ import (
"github.com/dop251/goja"
"github.com/ethereum/go-ethereum/core/types"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"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"
)
@@ -42,16 +42,16 @@ func init() {
if err != nil {
panic(err)
}
- type ctorFn = func(*tracers.Context, json.RawMessage) (tracers.Tracer, error)
+ type ctorFn = func(*directory.Context, json.RawMessage) (directory.Tracer, error)
lookup := func(code string) ctorFn {
- return func(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+ return func(ctx *directory.Context, cfg json.RawMessage) (directory.Tracer, error) {
return newJsTracer(code, ctx, cfg)
}
}
for name, code := range assetTracers {
- tracers.DefaultDirectory.Register(name, lookup(code), true)
+ directory.DefaultDirectory.Register(name, lookup(code), true)
}
- tracers.DefaultDirectory.RegisterJSEval(newJsTracer)
+ directory.DefaultDirectory.RegisterJSEval(newJsTracer)
}
// bigIntProgram is compiled once and the exported function mostly invoked to convert
@@ -96,7 +96,7 @@ func fromBuf(vm *goja.Runtime, bufType goja.Value, buf goja.Value, allowString b
// jsTracer is an implementation of the Tracer interface which evaluates
// JS functions on the relevant EVM hooks. It uses Goja as its JS engine.
type jsTracer struct {
- tracers.NoopTracer
+ directory.NoopTracer
vm *goja.Runtime
env *vm.EVM
@@ -136,7 +136,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 *directory.Context, cfg json.RawMessage) (directory.Tracer, error) {
vm := goja.New()
// By default field names are exported to JS as is, i.e. capitalized.
vm.SetFieldNameMapper(goja.UncapFieldNameMapper())
@@ -145,7 +145,7 @@ func newJsTracer(code string, ctx *tracers.Context, cfg json.RawMessage) (tracer
ctx: make(map[string]goja.Value),
}
if ctx == nil {
- ctx = new(tracers.Context)
+ ctx = new(directory.Context)
}
if ctx.BlockHash != (common.Hash{}) {
t.ctx["blockHash"] = vm.ToValue(ctx.BlockHash.Bytes())
@@ -576,7 +576,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 := directory.GetMemoryCopyPadded(mo.memory, begin, end-begin)
if err != nil {
return nil, err
}
diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go
index 4a7d6c5bcd..0706690c89 100644
--- a/eth/tracers/js/tracer_test.go
+++ b/eth/tracers/js/tracer_test.go
@@ -28,7 +28,7 @@ import (
"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/eth/tracers/directory"
"github.com/ethereum/go-ethereum/params"
)
@@ -61,7 +61,7 @@ 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 directory.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})
gasLimit uint64 = 31000
@@ -264,14 +264,14 @@ func TestIsPrecompile(t *testing.T) {
func TestEnterExit(t *testing.T) {
// test that either both or none of enter() and exit() are defined
- if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(tracers.Context), nil); err == nil {
+ if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}}", new(directory.Context), nil); err == nil {
t.Fatal("tracer creation should've failed without exit() definition")
}
- if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(tracers.Context), nil); err != nil {
+ if _, err := newJsTracer("{step: function() {}, fault: function() {}, result: function() { return null; }, enter: function() {}, exit: function() {}}", new(directory.Context), nil); err != nil {
t.Fatal(err)
}
// test that the enter and exit method are correctly invoked and the values passed
- tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(tracers.Context), nil)
+ tracer, err := newJsTracer("{enters: 0, exits: 0, enterGas: 0, gasUsed: 0, step: function() {}, fault: function() {}, result: function() { return {enters: this.enters, exits: this.exits, enterGas: this.enterGas, gasUsed: this.gasUsed} }, enter: function(frame) { this.enters++; this.enterGas = frame.getGas(); }, exit: function(res) { this.exits++; this.gasUsed = res.getGasUsed(); }}", new(directory.Context), nil)
if err != nil {
t.Fatal(err)
}
@@ -293,7 +293,7 @@ func TestEnterExit(t *testing.T) {
func TestSetup(t *testing.T) {
// Test empty config
- _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(tracers.Context), nil)
+ _, err := newJsTracer(`{setup: function(cfg) { if (cfg !== "{}") { throw("invalid empty config") } }, fault: function() {}, result: function() {}}`, new(directory.Context), nil)
if err != nil {
t.Error(err)
}
@@ -303,12 +303,12 @@ func TestSetup(t *testing.T) {
t.Fatal(err)
}
// Test no setup func
- _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(tracers.Context), cfg)
+ _, err = newJsTracer(`{fault: function() {}, result: function() {}}`, new(directory.Context), cfg)
if err != nil {
t.Fatal(err)
}
// Test config value
- tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(tracers.Context), cfg)
+ tracer, err := newJsTracer("{config: null, setup: function(cfg) { this.config = JSON.parse(cfg) }, step: function() {}, fault: function() {}, result: function() { return this.config.foo }}", new(directory.Context), cfg)
if err != nil {
t.Fatal(err)
}
diff --git a/eth/tracers/printer.go b/eth/tracers/live/printer.go
similarity index 93%
rename from eth/tracers/printer.go
rename to eth/tracers/live/printer.go
index f04dbff905..ba65d5fbb4 100644
--- a/eth/tracers/printer.go
+++ b/eth/tracers/live/printer.go
@@ -1,4 +1,4 @@
-package tracers
+package live
import (
"encoding/json"
@@ -8,14 +8,20 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core"
+ "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
)
+func init() {
+ directory.LiveDirectory.Register("printer", newPrinter)
+}
+
type Printer struct{}
-func NewPrinter() *Printer {
- return &Printer{}
+func newPrinter() (core.BlockchainLogger, error) {
+ return &Printer{}, nil
}
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
@@ -91,7 +97,7 @@ func (p *Printer) OnGenesisBlock(b *types.Block, alloc core.GenesisAlloc) {
fmt.Printf("OnGenesisBlock: b=%v, allocLength=%d\n", b.NumberU64(), len(alloc))
}
-func (p *Printer) OnBalanceChange(a common.Address, prev, new *big.Int) {
+func (p *Printer) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) {
fmt.Printf("OnBalanceChange: a=%v, prev=%v, new=%v\n", a, prev, new)
}
diff --git a/eth/tracers/logger/access_list_tracer.go b/eth/tracers/logger/access_list_tracer.go
index 0c246bef4c..7df66066b5 100644
--- a/eth/tracers/logger/access_list_tracer.go
+++ b/eth/tracers/logger/access_list_tracer.go
@@ -17,11 +17,10 @@
package logger
import (
- "math/big"
-
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
)
// accessList is an accumulator for the set of accounts and storage slots an EVM
@@ -103,6 +102,7 @@ func (al accessList) accessList() types.AccessList {
// AccessListTracer is a tracer that accumulates touched accounts and storage
// slots into an internal set.
type AccessListTracer struct {
+ directory.NoopTracer
excl map[common.Address]struct{} // Set of account to exclude from the list
list accessList // Set of accounts and storage slots touched
}
@@ -132,9 +132,6 @@ func NewAccessListTracer(acl types.AccessList, from, to common.Address, precompi
}
}
-func (a *AccessListTracer) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
-}
-
// 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
@@ -158,37 +155,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) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
-
-func (*AccessListTracer) OnGasChange(old, new uint64, reason vm.GasChangeReason) {}
-
-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(env *vm.EVM, tx *types.Transaction) {}
-
-func (*AccessListTracer) CaptureTxEnd(receipt *types.Receipt, err error) {}
-
-func (*AccessListTracer) OnBalanceChange(a common.Address, prev, new *big.Int) {}
-
-func (*AccessListTracer) OnNonceChange(a common.Address, prev, new uint64) {}
-
-func (*AccessListTracer) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
-}
-
-func (*AccessListTracer) OnStorageChange(a common.Address, k, prev, new common.Hash) {}
-
-func (*AccessListTracer) OnLog(log *types.Log) {}
-
-func (*AccessListTracer) OnNewAccount(a common.Address) {}
-
// 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 3858bbd8f7..22294252af 100644
--- a/eth/tracers/logger/logger.go
+++ b/eth/tracers/logger/logger.go
@@ -28,9 +28,9 @@ 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/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
)
@@ -107,6 +107,7 @@ func (s *StructLog) ErrorString() string {
// a track record of modified storage which is used in reporting snapshots of the
// contract their storage.
type StructLogger struct {
+ directory.NoopTracer
cfg Config
env *vm.EVM
@@ -139,10 +140,6 @@ func (l *StructLogger) Reset() {
l.err = nil
}
-// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
-func (l *StructLogger) CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
-}
-
// CaptureState logs a new structured log message and pushes it out to the environment
//
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
@@ -211,16 +208,6 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
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) {
-}
-
-// CaptureKeccakPreimage is called during the KECCAK256 opcode.
-func (l *StructLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
-
-func (l *StructLogger) OnGasChange(old, new uint64, reason vm.GasChangeReason) {}
-
// CaptureEnd is called after the call finishes to finalize the tracing.
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
l.output = output
@@ -233,12 +220,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 {
@@ -280,20 +261,6 @@ func (l *StructLogger) CaptureTxEnd(receipt *types.Receipt, err error) {
l.usedGas = receipt.GasUsed
}
-func (l *StructLogger) OnBalanceChange(a common.Address, prev, new *big.Int, reason state.BalanceChangeReason) {
-}
-
-func (l *StructLogger) OnNonceChange(a common.Address, prev, new uint64) {}
-
-func (l *StructLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
-}
-
-func (l *StructLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {}
-
-func (l *StructLogger) OnLog(log *types.Log) {}
-
-func (l *StructLogger) OnNewAccount(a common.Address) {}
-
// StructLogs returns the captured log entries.
func (l *StructLogger) StructLogs() []StructLog { return l.logs }
@@ -351,6 +318,7 @@ func WriteLogs(writer io.Writer, logs []*types.Log) {
}
type mdLogger struct {
+ directory.NoopTracer
out io.Writer
cfg *Config
env *vm.EVM
@@ -408,37 +376,11 @@ func (t *mdLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, scope
fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
}
-func (t *mdLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
-
-func (t *mdLogger) OnGasChange(old, new uint64, reason vm.GasChangeReason) {}
-
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(env *vm.EVM, tx *types.Transaction) {}
-
-func (*mdLogger) CaptureTxEnd(receipt *types.Receipt, err error) {}
-
-func (*mdLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {}
-
-func (*mdLogger) OnNonceChange(a common.Address, prev, new uint64) {}
-
-func (*mdLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
-}
-
-func (*mdLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {}
-
-func (*mdLogger) OnLog(log *types.Log) {}
-
-func (*mdLogger) OnNewAccount(a common.Address) {}
-
// 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 6e687c7e64..1ea014a0d6 100644
--- a/eth/tracers/logger/logger_json.go
+++ b/eth/tracers/logger/logger_json.go
@@ -19,15 +19,16 @@ 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/types"
"github.com/ethereum/go-ethereum/core/vm"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
)
type JSONLogger struct {
+ directory.NoopTracer
encoder *json.Encoder
cfg *Config
env *vm.EVM
@@ -43,9 +44,6 @@ func NewJSONLogger(cfg *Config, writer io.Writer) *JSONLogger {
return l
}
-func (l *JSONLogger) CaptureStart(from, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
-}
-
func (l *JSONLogger) CaptureFault(pc uint64, op vm.OpCode, gas uint64, cost uint64, scope *vm.ScopeContext, depth int, err error) {
// TODO: Add rData to this interface as well
l.CaptureState(pc, op, gas, cost, scope, nil, depth, err)
@@ -78,11 +76,6 @@ func (l *JSONLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, sco
l.encoder.Encode(log)
}
-// CaptureKeccakPreimage is called during the KECCAK256 opcode.
-func (l *JSONLogger) CaptureKeccakPreimage(hash common.Hash, data []byte) {}
-
-func (l *JSONLogger) OnGasChange(old, new uint64, reason vm.GasChangeReason) {}
-
// CaptureEnd is triggered at end of execution.
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
type endLog struct {
@@ -97,26 +90,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) CaptureExit(output []byte, gasUsed uint64, err error) {}
-
func (l *JSONLogger) CaptureTxStart(env *vm.EVM, tx *types.Transaction) {
l.env = env
}
-
-func (l *JSONLogger) CaptureTxEnd(receipt *types.Receipt, err error) {}
-
-func (*JSONLogger) OnBalanceChange(a common.Address, prev, new *big.Int) {}
-
-func (*JSONLogger) OnNonceChange(a common.Address, prev, new uint64) {}
-
-func (*JSONLogger) OnCodeChange(a common.Address, prevCodeHash common.Hash, prev []byte, codeHash common.Hash, code []byte) {
-}
-
-func (*JSONLogger) OnStorageChange(a common.Address, k, prev, new common.Hash) {}
-
-func (*JSONLogger) OnLog(log *types.Log) {}
-
-func (*JSONLogger) OnNewAccount(a common.Address) {}
diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go
index 4a7db6e72f..e6c3be41cd 100644
--- a/eth/tracers/logger/logger_test.go
+++ b/eth/tracers/logger/logger_test.go
@@ -60,6 +60,7 @@ func TestStoreCapture(t *testing.T) {
)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)}
var index common.Hash
+ logger.CaptureTxStart(env, nil)
logger.CaptureStart(common.Address{}, contract.Address(), false, nil, 0, nil)
_, err := env.Interpreter().Run(contract, []byte{}, false)
if err != nil {
diff --git a/eth/tracers/native/4byte.go b/eth/tracers/native/4byte.go
index 25152a098e..b25ff06ae2 100644
--- a/eth/tracers/native/4byte.go
+++ b/eth/tracers/native/4byte.go
@@ -25,11 +25,11 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
)
func init() {
- tracers.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false)
+ directory.DefaultDirectory.Register("4byteTracer", newFourByteTracer, false)
}
// fourByteTracer searches for 4byte-identifiers, and collects them for post-processing.
@@ -47,7 +47,7 @@ func init() {
// 0xc281d19e-0: 1
// }
type fourByteTracer struct {
- tracers.NoopTracer
+ directory.NoopTracer
env *vm.EVM
ids map[string]int // ids aggregates the 4byte ids found
interrupt atomic.Bool // Atomic flag to signal execution interruption
@@ -57,7 +57,7 @@ type fourByteTracer struct {
// 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 *directory.Context, _ json.RawMessage) (directory.Tracer, error) {
t := &fourByteTracer{
ids: make(map[string]int),
}
diff --git a/eth/tracers/native/call.go b/eth/tracers/native/call.go
index 3af18cd3ce..bb2ea19b54 100644
--- a/eth/tracers/native/call.go
+++ b/eth/tracers/native/call.go
@@ -27,13 +27,13 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
)
//go:generate go run github.com/fjl/gencodec -type callFrame -field-override callFrameMarshaling -out gen_callframe_json.go
func init() {
- tracers.DefaultDirectory.Register("callTracer", newCallTracer, false)
+ directory.DefaultDirectory.Register("callTracer", newCallTracer, false)
}
type callLog struct {
@@ -99,7 +99,7 @@ type callFrameMarshaling struct {
}
type callTracer struct {
- tracers.NoopTracer
+ directory.NoopTracer
callstack []callFrame
config callTracerConfig
gasLimit uint64
@@ -115,7 +115,7 @@ 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 *directory.Context, cfg json.RawMessage) (directory.Tracer, error) {
var config callTracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go
index 084df593a8..d5aebc00fd 100644
--- a/eth/tracers/native/call_flat.go
+++ b/eth/tracers/native/call_flat.go
@@ -27,14 +27,14 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
- "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
)
//go:generate go run github.com/fjl/gencodec -type flatCallAction -field-override flatCallActionMarshaling -out gen_flatcallaction_json.go
//go:generate go run github.com/fjl/gencodec -type flatCallResult -field-override flatCallResultMarshaling -out gen_flatcallresult_json.go
func init() {
- tracers.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false)
+ directory.DefaultDirectory.Register("flatCallTracer", newFlatCallTracer, false)
}
var parityErrorMapping = map[string]string{
@@ -109,12 +109,12 @@ type flatCallResultMarshaling struct {
// flatCallTracer reports call frame information of a tx in a flat format, i.e.
// as opposed to the nested format of `callTracer`.
type flatCallTracer struct {
- tracers.NoopTracer
+ directory.NoopTracer
tracer *callTracer
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
+ ctx *directory.Context // Holds tracer context data
+ reason error // Textual reason for the interruption
+ activePrecompiles []common.Address // Updated on CaptureStart based on given rules
}
type flatCallTracerConfig struct {
@@ -123,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 *directory.Context, cfg json.RawMessage) (directory.Tracer, error) {
var config flatCallTracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
@@ -133,7 +133,7 @@ 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)
+ tracer, err := directory.DefaultDirectory.New("callTracer", ctx, nil)
if err != nil {
return nil, err
}
@@ -244,7 +244,7 @@ func (t *flatCallTracer) isPrecompiled(addr common.Address) bool {
return false
}
-func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *tracers.Context) (output []flatCallFrame, err error) {
+func flatFromNested(input *callFrame, traceAddress []int, convertErrs bool, ctx *directory.Context) (output []flatCallFrame, err error) {
var frame *flatCallFrame
switch input.Type {
case vm.CREATE, vm.CREATE2:
@@ -343,7 +343,7 @@ func newFlatSelfdestruct(input *callFrame) *flatCallFrame {
}
}
-func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *tracers.Context) {
+func fillCallFrameFromContext(callFrame *flatCallFrame, ctx *directory.Context) {
if ctx == nil {
return
}
diff --git a/eth/tracers/native/mux.go b/eth/tracers/native/mux.go
index da2381b880..dab284a3a3 100644
--- a/eth/tracers/native/mux.go
+++ b/eth/tracers/native/mux.go
@@ -24,32 +24,32 @@ import (
"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/eth/tracers/directory"
)
func init() {
- tracers.DefaultDirectory.Register("muxTracer", newMuxTracer, false)
+ directory.DefaultDirectory.Register("muxTracer", newMuxTracer, false)
}
// muxTracer is a go implementation of the Tracer interface which
// runs multiple tracers in one go.
type muxTracer struct {
names []string
- tracers []tracers.Tracer
+ tracers []directory.Tracer
}
// newMuxTracer returns a new mux tracer.
-func newMuxTracer(ctx *tracers.Context, cfg json.RawMessage) (tracers.Tracer, error) {
+func newMuxTracer(ctx *directory.Context, cfg json.RawMessage) (directory.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([]directory.Tracer, 0, len(config))
names := make([]string, 0, len(config))
for k, v := range config {
- t, err := tracers.DefaultDirectory.New(k, ctx, v)
+ t, err := directory.DefaultDirectory.New(k, ctx, v)
if err != nil {
return nil, err
}
diff --git a/eth/tracers/native/prestate.go b/eth/tracers/native/prestate.go
index 9375279cb4..71cd7ce791 100644
--- a/eth/tracers/native/prestate.go
+++ b/eth/tracers/native/prestate.go
@@ -28,14 +28,14 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/eth/tracers"
+ "github.com/ethereum/go-ethereum/eth/tracers/directory"
"github.com/ethereum/go-ethereum/log"
)
//go:generate go run github.com/fjl/gencodec -type account -field-override accountMarshaling -out gen_account_json.go
func init() {
- tracers.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false)
+ directory.DefaultDirectory.Register("prestateTracer", newPrestateTracer, false)
}
type stateMap = map[common.Address]*account
@@ -57,7 +57,7 @@ type accountMarshaling struct {
}
type prestateTracer struct {
- tracers.NoopTracer
+ directory.NoopTracer
env *vm.EVM
pre stateMap
post stateMap
@@ -74,7 +74,7 @@ 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 *directory.Context, cfg json.RawMessage) (directory.Tracer, error) {
var config prestateTracerConfig
if cfg != nil {
if err := json.Unmarshal(cfg, &config); err != nil {
@@ -143,7 +143,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 := directory.GetMemoryCopyPadded(scope.Memory, 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
diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go
index 759e3a4dd3..b9c0ac526d 100644
--- a/eth/tracers/tracers_test.go
+++ b/eth/tracers/tracers_test.go
@@ -109,41 +109,3 @@ func BenchmarkTransactionTrace(b *testing.B) {
tracer.Reset()
}
}
-
-func TestMemCopying(t *testing.T) {
- for i, tc := range []struct {
- memsize int64
- offset int64
- size int64
- wantErr string
- wantSize int
- }{
- {0, 0, 100, "", 100}, // Should pad up to 100
- {0, 100, 0, "", 0}, // No need to pad (0 size)
- {100, 50, 100, "", 100}, // Should pad 100-150
- {100, 50, 5, "", 5}, // Wanted range fully within memory
- {100, -50, 0, "offset or size must not be negative", 0}, // Errror
- {0, 1, 1024*1024 + 1, "reached limit for padding memory slice: 1048578", 0}, // Errror
- {10, 0, 1024*1024 + 100, "reached limit for padding memory slice: 1048666", 0}, // Errror
-
- } {
- mem := vm.NewMemory()
- mem.Resize(uint64(tc.memsize))
- cpy, err := GetMemoryCopyPadded(mem, tc.offset, tc.size)
- if want := tc.wantErr; want != "" {
- if err == nil {
- t.Fatalf("test %d: want '%v' have no error", i, want)
- }
- if have := err.Error(); want != have {
- t.Fatalf("test %d: want '%v' have '%v'", i, want, have)
- }
- continue
- }
- if err != nil {
- t.Fatalf("test %d: unexpected error: %v", i, err)
- }
- if want, have := tc.wantSize, len(cpy); have != want {
- t.Fatalf("test %d: want %v have %v", i, want, have)
- }
- }
-}