diff --git a/core/state/statedb.go b/core/state/statedb.go index 80a53dbb1772..db4d0b2b2ab4 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -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 @@ -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 diff --git a/core/tracing/hooks.go b/core/tracing/hooks.go index 1a2b0c86a147..8bd57903f5f4 100644 --- a/core/tracing/hooks.go +++ b/core/tracing/hooks.go @@ -171,6 +171,24 @@ 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) + + // 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) ) type Hooks struct { @@ -198,6 +216,13 @@ type Hooks struct { OnCodeChange CodeChangeHook OnStorageChange StorageChangeHook OnLog LogHook + // State reads + OnBalanceRead BalanceReadHook + OnNonceRead NonceReadHook + OnCodeRead CodeReadHook + OnCodeSizeRead CodeSizeReadHook + OnCodeHashRead CodeHashReadHook + OnStorageRead StorageReadHook } // BalanceChangeReason is used to indicate the reason for a balance change, useful diff --git a/eth/tracers/live/noop.go b/eth/tracers/live/noop.go index 7433c288408f..83ea74c24411 100644 --- a/eth/tracers/live/noop.go +++ b/eth/tracers/live/noop.go @@ -36,11 +36,18 @@ func newNoopTracer(_ json.RawMessage) (*tracing.Hooks, error) { OnBlockEnd: t.OnBlockEnd, OnSkippedBlock: t.OnSkippedBlock, OnGenesisBlock: t.OnGenesisBlock, + OnReorg: t.OnReorg, OnBalanceChange: t.OnBalanceChange, OnNonceChange: t.OnNonceChange, OnCodeChange: t.OnCodeChange, OnStorageChange: t.OnStorageChange, OnLog: t.OnLog, + OnBalanceRead: t.OnBalanceRead, + OnNonceRead: t.OnNonceRead, + OnCodeRead: t.OnCodeRead, + OnCodeSizeRead: t.OnCodeSizeRead, + OnCodeHashRead: t.OnCodeHashRead, + OnStorageRead: t.OnStorageRead, }, nil } @@ -76,6 +83,8 @@ func (t *noop) OnBlockchainInit(chainConfig *params.ChainConfig) { func (t *noop) OnGenesisBlock(b *types.Block, alloc types.GenesisAlloc) { } +func (t *noop) OnReorg(reverted []*types.Block) {} + func (t *noop) OnBalanceChange(a common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) { } @@ -92,5 +101,17 @@ func (t *noop) OnLog(l *types.Log) { } +func (t *noop) OnBalanceRead(addr common.Address, bal *big.Int) {} + +func (t *noop) OnNonceRead(addr common.Address, nonce uint64) {} + +func (t *noop) OnCodeRead(addr common.Address, code []byte) {} + +func (t *noop) OnCodeSizeRead(addr common.Address, size int) {} + +func (t *noop) OnCodeHashRead(addr common.Address, hash common.Hash) {} + +func (t *noop) OnStorageRead(addr common.Address, slot, val common.Hash) {} + func (t *noop) OnGasChange(old, new uint64, reason tracing.GasChangeReason) { }