Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/tracing: v1.1 #30441

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2375,6 +2375,10 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
if len(rebirthLogs) > 0 {
bc.logsFeed.Send(rebirthLogs)
}

if bc.logger != nil && bc.logger.OnReorg != nil {
bc.logger.OnReorg(oldChain)
}
return nil
}

Expand Down
49 changes: 36 additions & 13 deletions core/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,21 +331,28 @@ func (s *StateDB) Empty(addr common.Address) bool {

// GetBalance retrieves the balance from the given address or 0 if object not found
func (s *StateDB) GetBalance(addr common.Address) *uint256.Int {
bal := common.U2560
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.Balance()
bal = stateObject.Balance()
}
return common.U2560
if s.logger != nil && s.logger.OnBalanceRead != nil {
s.logger.OnBalanceRead(addr, bal.ToBig())
}
return bal
}

// GetNonce retrieves the nonce from the given address or 0 if object not found
func (s *StateDB) GetNonce(addr common.Address) uint64 {
var nonce uint64
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.Nonce()
nonce = stateObject.Nonce()
}

return 0
if s.logger != nil && s.logger.OnNonceRead != nil {
s.logger.OnNonceRead(addr, nonce)
}
return nonce
}

// GetStorageRoot retrieves the storage root from the given address or empty
Expand All @@ -364,36 +371,52 @@ func (s *StateDB) TxIndex() int {
}

func (s *StateDB) GetCode(addr common.Address) []byte {
var code []byte
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.Code()
code = stateObject.Code()
}
return nil
if s.logger != nil && s.logger.OnCodeRead != nil {
s.logger.OnCodeRead(addr, code)
}
return code
}

func (s *StateDB) GetCodeSize(addr common.Address) int {
var size int
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.CodeSize()
size = stateObject.CodeSize()
}
if s.logger != nil && s.logger.OnCodeSizeRead != nil {
s.logger.OnCodeSizeRead(addr, size)
}
return 0
return size
}

func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
hash := common.Hash{}
stateObject := s.getStateObject(addr)
if stateObject != nil {
return common.BytesToHash(stateObject.CodeHash())
hash = common.BytesToHash(stateObject.CodeHash())
}
return common.Hash{}
if s.logger != nil && s.logger.OnCodeHashRead != nil {
s.logger.OnCodeHashRead(addr, hash)
}
return hash
}

// GetState retrieves the value associated with the specific key.
func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
val := common.Hash{}
stateObject := s.getStateObject(addr)
if stateObject != nil {
return stateObject.GetState(hash)
val = stateObject.GetState(hash)
}
return common.Hash{}
if s.logger != nil && s.logger.OnStorageRead != nil {
s.logger.OnStorageRead(addr, hash, val)
}
return val
}

// GetCommittedState retrieves the value associated with the specific key
Expand Down
4 changes: 2 additions & 2 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
if tracer := vmenv.Config.Tracer; tracer != nil {
if tracer.OnSystemCallStart != nil {
tracer.OnSystemCallStart()
tracer.OnSystemCallStart(vmenv.GetVMContext())
}
if tracer.OnSystemCallEnd != nil {
defer tracer.OnSystemCallEnd()
Expand Down Expand Up @@ -212,7 +212,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
if tracer := vmenv.Config.Tracer; tracer != nil {
if tracer.OnSystemCallStart != nil {
tracer.OnSystemCallStart()
tracer.OnSystemCallStart(vmenv.GetVMContext())
}
if tracer.OnSystemCallEnd != nil {
defer tracer.OnSystemCallEnd()
Expand Down
48 changes: 47 additions & 1 deletion core/tracing/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,52 @@

All notable changes to the tracing interface will be documented in this file.

## [Unreleased]

The tracing interface has been extended with backwards-compatible changes to support more use-cases and simplify tracer code. The most notable changes are state read hooks as well a state journaling library which emits events when a call is reverted.

### New methods

- `OnReorg(reverted []*types.Block)`: This hook is called when a reorg is detected. The `reverted` slice contains the blocks that are no longer part of the canonical chain.
- `OnBalanceRead(addr common.Address, balance *big.Int)`: This hook is called when an account balance is read.
- `OnNonceRead(addr common.Address, nonce uint64)`: This hook is called when an account nonce is read.
- `OnCodeRead(addr common.Address, code []byte)`: This hook is called when an account code is read.
- `OnCodeSizeRead(addr common.Address, size int)`: This hook is called when an account code size is read.
- `OnCodeHashRead(addr common.Address, codeHash common.Hash)`: This hook is called when an account code hash is read.
- `OnStorageRead(addr common.Address, slot common.Hash, value common.Hash)`: This hook is called when an account storage slot is read.

### Modified methods

- `OnSystemCallStart()` -> `OnSystemCallStart(vm *VMContext)`. This allows access to EVM context during system calls.

### Modified types

- `VMContext.StateDB` has been extended with `GetCodeHash(addr common.Address) common.Hash` method used to retrieve the code hash an account.
- `BalanceChangeReason` has been extended with the `BalanceChangeRevert` reason. More on that below.

### State journaling

Tracers receive state changes events from the node. The tracer was so far expected to keep track of modified accounts and slots and revert those changes when a call frame failed. Now a utility tracer wrapper is provided which will emit "reverse change" events when a call frame fails. To use this feature the hooks have to be wrapped prior to registering the tracer. The following example demonstrates how to use the state journaling library:

```go
func init() {
tracers.LiveDirectory.Register("test", func (cfg json.RawMessage) (*tracing.Hooks, error) {
hooks, err := newTestTracer(cfg)
if err != nil {
return nil, err
}
return tracing.WrapWithJournal(hooks)
})
}
```

The state changes that are covered by the journaling library are:

- `OnBalanceChange`
- `OnNonceChange`
- `OnCodeChange`
- `OnStorageChange`

## [v1.14.3]

There have been minor backwards-compatible changes to the tracing interface to explicitly mark the execution of **system** contracts. As of now the only system call updates the parent beacon block root as per [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788). Other system calls are being considered for the future hardfork.
Expand Down Expand Up @@ -75,6 +121,6 @@ The hooks `CaptureStart` and `CaptureEnd` have been removed. These hooks signale
- `CaptureState` -> `OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error)`. `op` is of type `byte` which can be cast to `vm.OpCode` when necessary. A `*vm.ScopeContext` is not passed anymore. It is replaced by `tracing.OpContext` which offers access to the memory, stack and current contract.
- `CaptureFault` -> `OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error)`. Similar to above.

[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.0...master
[unreleased]: https://github.com/ethereum/go-ethereum/compare/v1.14.8...master
[v1.14.0]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0
[v1.14.3]: https://github.com/ethereum/go-ethereum/releases/tag/v1.14.3
40 changes: 39 additions & 1 deletion core/tracing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type StateDB interface {
GetBalance(common.Address) *uint256.Int
GetNonce(common.Address) uint64
GetCode(common.Address) []byte
GetCodeHash(common.Address) common.Hash
GetState(common.Address, common.Hash) common.Hash
Exist(common.Address) bool
GetRefund() uint64
Expand Down Expand Up @@ -133,6 +134,9 @@ type (
// GenesisBlockHook is called when the genesis block is being processed.
GenesisBlockHook = func(genesis *types.Block, alloc types.GenesisAlloc)

// ReorgHook is called when a segment of the chain is reverted.
ReorgHook = func(reverted []*types.Block)

// OnSystemCallStartHook is called when a system call is about to be executed. Today,
// this hook is invoked when the EIP-4788 system call is about to be executed to set the
// beacon block root.
Expand All @@ -142,7 +146,7 @@ type (
//
// Note that system call happens outside normal transaction execution, so the `OnTxStart/OnTxEnd` hooks
// will not be invoked.
OnSystemCallStartHook = func()
OnSystemCallStartHook = func(vm *VMContext)

// OnSystemCallEndHook is called when a system call has finished executing. Today,
// this hook is invoked when the EIP-4788 system call is about to be executed to set the
Expand All @@ -167,6 +171,27 @@ type (

// LogHook is called when a log is emitted.
LogHook = func(log *types.Log)

// BalanceReadHook is called when EVM reads the balance of an account.
BalanceReadHook = func(addr common.Address, bal *big.Int)

// NonceReadHook is called when EVM reads the nonce of an account.
NonceReadHook = func(addr common.Address, nonce uint64)

// CodeReadHook is called when EVM reads the code of an account.
CodeReadHook = func(addr common.Address, code []byte)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Open question: should we add codeHash here to be consistent with OnCodeChange?


// CodeSizeReadHook is called when EVM reads the code size of an account.
CodeSizeReadHook = func(addr common.Address, size int)

// CodeHashReadHook is called when EVM reads the code hash of an account.
CodeHashReadHook = func(addr common.Address, hash common.Hash)

// StorageReadHook is called when EVM reads a storage slot of an account.
StorageReadHook = func(addr common.Address, slot, value common.Hash)

// BlockHashReadHook is called when EVM reads the blockhash of a block.
BlockHashReadHook = func(blockNumber uint64, hash common.Hash)
)

type Hooks struct {
Expand All @@ -185,6 +210,7 @@ type Hooks struct {
OnBlockEnd BlockEndHook
OnSkippedBlock SkippedBlockHook
OnGenesisBlock GenesisBlockHook
OnReorg ReorgHook
OnSystemCallStart OnSystemCallStartHook
OnSystemCallEnd OnSystemCallEndHook
// State events
Expand All @@ -193,6 +219,15 @@ type Hooks struct {
OnCodeChange CodeChangeHook
OnStorageChange StorageChangeHook
OnLog LogHook
// State reads
OnBalanceRead BalanceReadHook
OnNonceRead NonceReadHook
OnCodeRead CodeReadHook
OnCodeSizeRead CodeSizeReadHook
OnCodeHashRead CodeHashReadHook
OnStorageRead StorageReadHook
// Block hash read
OnBlockHashRead BlockHashReadHook
}

// BalanceChangeReason is used to indicate the reason for a balance change, useful
Expand Down Expand Up @@ -244,6 +279,9 @@ const (
// account within the same tx (captured at end of tx).
// Note it doesn't account for a self-destruct which appoints itself as recipient.
BalanceDecreaseSelfdestructBurn BalanceChangeReason = 14

// BalanceChangeRevert is emitted when the balance is reverted back to a previous value due to call failure.
BalanceChangeRevert BalanceChangeReason = 15
)

// GasChangeReason is used to indicate the reason for a gas change, useful
Expand Down
Loading