diff --git a/core/blockchain.go b/core/blockchain.go index ec73d4885e..469844b503 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2192,6 +2192,7 @@ func (bc *BlockChain) ProcessBlock(parentRoot common.Hash, block *types.Block, s stats.UniqueAccountsAccessed = statedb.UniqueAccountsAccessed() stats.UniqueStorageAccessed = statedb.UniqueStorageAccessed() stats.UniqueCodeExecuted = statedb.UniqueCodeExecuted() + stats.SystemCodeExecuted = statedb.SystemCodeExecuted() stats.Execution = ptime - (statedb.AccountReads + statedb.StorageReads + statedb.CodeReads) // The time spent on EVM processing stats.Validation = vtime - (statedb.AccountHashes + statedb.AccountUpdates + statedb.StorageUpdates) // The time spent on block validation diff --git a/core/blockchain_stats.go b/core/blockchain_stats.go index 81586d1926..33a716da01 100644 --- a/core/blockchain_stats.go +++ b/core/blockchain_stats.go @@ -52,6 +52,7 @@ type ExecuteStats struct { UniqueAccountsAccessed int // Number of unique accounts accessed UniqueStorageAccessed int // Number of unique storage slots accessed UniqueCodeExecuted int // Number of unique contracts executed + SystemCodeExecuted int // Number of unique system contracts executed (subset of UniqueCodeExecuted) Execution time.Duration // Time spent on the EVM execution Validation time.Duration // Time spent on the block validation @@ -132,7 +133,7 @@ State read: %v Unique state access: Accounts: %d Storage slots: %d - Contracts executed: %d + Contracts executed: %d (%d system) State hash: %v Account hash: %v @@ -158,7 +159,7 @@ DB write: %v // Unique state access s.UniqueAccountsAccessed, s.UniqueStorageAccessed, - s.UniqueCodeExecuted, + s.UniqueCodeExecuted, s.SystemCodeExecuted, // State hash common.PrettyDuration(s.AccountHashes+s.AccountUpdates+s.StorageUpdates+max(s.AccountCommits, s.StorageCommits)), diff --git a/core/state/statedb.go b/core/state/statedb.go index b95f864b6e..d3283d18a2 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -163,7 +163,8 @@ type StateDB struct { CodeBytesRead int64 // Total bytes of contract code read during the state transition // Unique contracts executed tracking (set of code hashes executed during the state transition) - executedCodes map[common.Hash]struct{} + executedCodes map[common.Hash]struct{} + systemExecutedCodes map[common.Hash]struct{} // Subset of executedCodes that are system calls } // New creates a new state from a given trie. @@ -191,6 +192,7 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro accessList: newAccessList(), transientStorage: newTransientStorage(), executedCodes: make(map[common.Hash]struct{}), + systemExecutedCodes: make(map[common.Hash]struct{}), } if db.TrieDB().IsVerkle() { sdb.accessEvents = NewAccessEvents(db.PointCache()) @@ -386,7 +388,8 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash { // MarkCodeExecuted records that a contract's code was executed. // This is used for metrics tracking to count unique contracts executed. -func (s *StateDB) MarkCodeExecuted(codeHash common.Hash) { +// The isSystem parameter indicates if this is a system call (e.g., EIP-4788 beacon root). +func (s *StateDB) MarkCodeExecuted(codeHash common.Hash, isSystem bool) { if codeHash == types.EmptyCodeHash || codeHash == (common.Hash{}) { return } @@ -394,6 +397,9 @@ func (s *StateDB) MarkCodeExecuted(codeHash common.Hash) { return // Skip tracking for state copies (e.g., prefetcher) } s.executedCodes[codeHash] = struct{}{} + if isSystem { + s.systemExecutedCodes[codeHash] = struct{}{} + } } // UniqueCodeExecuted returns the number of unique contract codes executed. @@ -401,6 +407,12 @@ func (s *StateDB) UniqueCodeExecuted() int { return len(s.executedCodes) } +// SystemCodeExecuted returns the number of unique system contract codes executed +// (e.g., EIP-4788 beacon root, EIP-2935 history storage, etc.). +func (s *StateDB) SystemCodeExecuted() int { + return len(s.systemExecutedCodes) +} + // UniqueAccountsAccessed returns the number of unique accounts accessed during the state transition. func (s *StateDB) UniqueAccountsAccessed() int { return len(s.stateObjects) diff --git a/core/state/statedb_hooked.go b/core/state/statedb_hooked.go index 997ef91667..0e3b543322 100644 --- a/core/state/statedb_hooked.go +++ b/core/state/statedb_hooked.go @@ -298,6 +298,6 @@ func (s *hookedStateDB) Inner() *StateDB { } // MarkCodeExecuted records that a contract's code was executed. -func (s *hookedStateDB) MarkCodeExecuted(codeHash common.Hash) { - s.inner.MarkCodeExecuted(codeHash) +func (s *hookedStateDB) MarkCodeExecuted(codeHash common.Hash, isSystem bool) { + s.inner.MarkCodeExecuted(codeHash, isSystem) } diff --git a/core/vm/evm.go b/core/vm/evm.go index 43787c2d0f..0ffe4f7095 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -296,7 +296,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g codeHash := evm.resolveCodeHash(addr) contract.SetCallCode(codeHash, code) // Track unique contract execution for metrics - evm.StateDB.MarkCodeExecuted(codeHash) + evm.StateDB.MarkCodeExecuted(codeHash, contract.IsSystemCall) ret, err = evm.Run(contract, input, false) gas = contract.Gas } @@ -358,7 +358,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt codeHash := evm.resolveCodeHash(addr) contract.SetCallCode(codeHash, evm.resolveCode(addr)) // Track unique contract execution for metrics - evm.StateDB.MarkCodeExecuted(codeHash) + evm.StateDB.MarkCodeExecuted(codeHash, isSystemCall(caller)) ret, err = evm.Run(contract, input, false) gas = contract.Gas } @@ -405,7 +405,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, codeHash := evm.resolveCodeHash(addr) contract.SetCallCode(codeHash, evm.resolveCode(addr)) // Track unique contract execution for metrics - evm.StateDB.MarkCodeExecuted(codeHash) + evm.StateDB.MarkCodeExecuted(codeHash, isSystemCall(originCaller)) ret, err = evm.Run(contract, input, false) gas = contract.Gas } @@ -459,7 +459,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b codeHash := evm.resolveCodeHash(addr) contract.SetCallCode(codeHash, evm.resolveCode(addr)) // Track unique contract execution for metrics - evm.StateDB.MarkCodeExecuted(codeHash) + evm.StateDB.MarkCodeExecuted(codeHash, isSystemCall(caller)) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally diff --git a/core/vm/interface.go b/core/vm/interface.go index fc8efb02aa..13da4a1ea9 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -104,5 +104,6 @@ type StateDB interface { // MarkCodeExecuted records that a contract's code was executed. // Used for metrics tracking to count unique contracts executed. - MarkCodeExecuted(codeHash common.Hash) + // The isSystem parameter indicates if this is a system call (e.g., EIP-4788). + MarkCodeExecuted(codeHash common.Hash, isSystem bool) }