From 5a1d8a5da3c1fec8ede83a04ece5eb113c015043 Mon Sep 17 00:00:00 2001 From: Austin Larson Date: Mon, 15 Jun 2026 13:28:26 -0400 Subject: [PATCH] feat(core/state): Account deletions are always informed to state.Trie --- core/state/statedb.go | 13 +++++++++++-- libevm/stateconf/conf.go | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 487560dab216..60826dc5a5cb 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -865,7 +865,7 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) { // IntermediateRoot computes the current root hash of the state trie. // It is called in between transactions to get the root hash that // goes into transaction receipts. -func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { +func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool, opts ...stateconf.StateDBIntermediateRootOption) common.Hash { // Finalise all the dirty storage states and write them into the tries s.Finalise(deleteEmptyObjects) @@ -883,6 +883,15 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.prefetcher = nil }() } + + if stateconf.ShouldDestructStateDB(opts...) { + for addr := range s.stateObjectsDestruct { + if obj := s.stateObjects[addr]; obj != nil { + s.trie.DeleteAccount(addr) // prefix delete in firewood + } + } + } + // Although naively it makes sense to retrieve the account trie and then do // the contract storage and account updates sequentially, that short circuits // the account prefetcher. Instead, let's process all the storage updates @@ -1163,7 +1172,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, opts ...statecon return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr) } // Finalize any pending changes and merge everything into the tries - s.IntermediateRoot(deleteEmptyObjects) + s.IntermediateRoot(deleteEmptyObjects, stateconf.ExtractIntermediateRootOpts(opts...)...) // Commit objects to the trie, measuring the elapsed time var ( diff --git a/libevm/stateconf/conf.go b/libevm/stateconf/conf.go index d56dc61c7be3..a0c50d008a31 100644 --- a/libevm/stateconf/conf.go +++ b/libevm/stateconf/conf.go @@ -26,8 +26,9 @@ import ( type StateDBCommitOption = options.Option[stateDBCommitConfig] type stateDBCommitConfig struct { - snapshotOpts []SnapshotUpdateOption - triedbOpts []TrieDBUpdateOption + snapshotOpts []SnapshotUpdateOption + triedbOpts []TrieDBUpdateOption + intermediateRootOpts []StateDBIntermediateRootOption } // WithSnapshotUpdateOpts returns a StateDBCommitOption carrying a list of @@ -60,6 +61,21 @@ func ExtractTrieDBUpdateOpts(opts ...StateDBCommitOption) []TrieDBUpdateOption { return options.As(opts...).triedbOpts } +// WithIntermediateRootOpts returns a StateDBCommitOption carrying a list of +// StateDBIntermediateRootOptions. If multiple such options are used, only the last will be +// applied as they overwrite each other. +func WithIntermediateRootOpts(opts ...StateDBIntermediateRootOption) StateDBCommitOption { + return options.Func[stateDBCommitConfig](func(c *stateDBCommitConfig) { + c.intermediateRootOpts = opts + }) +} + +// ExtractIntermediateRootOpts returns the list of StateDBIntermediateRootOptions carried by +// the provided slice of StateDBCommitOption. +func ExtractIntermediateRootOpts(opts ...StateDBCommitOption) []StateDBIntermediateRootOption { + return options.As(opts...).intermediateRootOpts +} + // A SnapshotUpdateOption configures the behaviour of // state.SnapshotTree.Update() implementations. This will be removed along with // state.SnapshotTree. @@ -114,6 +130,22 @@ func ExtractTrieDBUpdatePayload(opts ...TrieDBUpdateOption) (common.Hash, common return *conf.parentBlockHash, *conf.currentBlockHash, true } +type StateDBIntermediateRootOption = options.Option[stateDBIntermediateRootConfig] + +type stateDBIntermediateRootConfig struct { + shouldDestruct bool +} + +func WithStateDBDestruct() StateDBIntermediateRootOption { + return options.Func[stateDBIntermediateRootConfig](func(c *stateDBIntermediateRootConfig) { + c.shouldDestruct = true + }) +} + +func ShouldDestructStateDB(opts ...StateDBIntermediateRootOption) bool { + return options.As(opts...).shouldDestruct +} + // A StateDBStateOption configures the behaviour of state.StateDB methods for // getting and setting state: GetState(), GetCommittedState(), and SetState(). type StateDBStateOption = options.Option[stateDBStateConfig]