@@ -72,16 +72,16 @@ type StateDB struct {
7272 // It will be updated when the Commit is called.
7373 originalRoot common.Hash
7474
75- snaps * snapshot.Tree
76- snap snapshot.Snapshot
77- snapDestructs map [common.Hash ]struct {}
78- snapAccounts map [common.Hash ][]byte
79- snapStorage map [common.Hash ]map [common.Hash ][]byte
75+ snaps * snapshot.Tree
76+ snap snapshot.Snapshot
77+ snapAccounts map [common.Hash ][]byte
78+ snapStorage map [common.Hash ]map [common.Hash ][]byte
8079
8180 // This map holds 'live' objects, which will get modified while processing a state transition.
82- stateObjects map [common.Address ]* stateObject
83- stateObjectsPending map [common.Address ]struct {} // State objects finalized but not yet written to the trie
84- stateObjectsDirty map [common.Address ]struct {} // State objects modified in the current execution
81+ stateObjects map [common.Address ]* stateObject
82+ stateObjectsPending map [common.Address ]struct {} // State objects finalized but not yet written to the trie
83+ stateObjectsDirty map [common.Address ]struct {} // State objects modified in the current execution
84+ stateObjectsDestruct map [common.Address ]struct {} // State objects destructed in the block
8585
8686 // DB error.
8787 // State objects are used by the consensus core and VM which are
@@ -139,23 +139,23 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
139139 return nil , err
140140 }
141141 sdb := & StateDB {
142- db : db ,
143- trie : tr ,
144- originalRoot : root ,
145- snaps : snaps ,
146- stateObjects : make (map [common.Address ]* stateObject ),
147- stateObjectsPending : make (map [common.Address ]struct {}),
148- stateObjectsDirty : make (map [common.Address ]struct {}),
149- logs : make (map [common.Hash ][]* types.Log ),
150- preimages : make (map [common.Hash ][]byte ),
151- journal : newJournal (),
152- accessList : newAccessList (),
153- transientStorage : newTransientStorage (),
154- hasher : crypto .NewKeccakState (),
142+ db : db ,
143+ trie : tr ,
144+ originalRoot : root ,
145+ snaps : snaps ,
146+ stateObjects : make (map [common.Address ]* stateObject ),
147+ stateObjectsPending : make (map [common.Address ]struct {}),
148+ stateObjectsDirty : make (map [common.Address ]struct {}),
149+ stateObjectsDestruct : make (map [common.Address ]struct {}),
150+ logs : make (map [common.Hash ][]* types.Log ),
151+ preimages : make (map [common.Hash ][]byte ),
152+ journal : newJournal (),
153+ accessList : newAccessList (),
154+ transientStorage : newTransientStorage (),
155+ hasher : crypto .NewKeccakState (),
155156 }
156157 if sdb .snaps != nil {
157158 if sdb .snap = sdb .snaps .Snapshot (root ); sdb .snap != nil {
158- sdb .snapDestructs = make (map [common.Hash ]struct {})
159159 sdb .snapAccounts = make (map [common.Hash ][]byte )
160160 sdb .snapStorage = make (map [common.Hash ]map [common.Hash ][]byte )
161161 }
@@ -622,10 +622,10 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
622622 prev = s .getDeletedStateObject (addr ) // Note, prev might have been deleted, we need that!
623623
624624 var prevdestruct bool
625- if s . snap != nil && prev != nil {
626- _ , prevdestruct = s .snapDestructs [prev .addrHash ]
625+ if prev != nil {
626+ _ , prevdestruct = s .stateObjectsDestruct [prev .address ]
627627 if ! prevdestruct {
628- s .snapDestructs [prev .addrHash ] = struct {}{}
628+ s .stateObjectsDestruct [prev .address ] = struct {}{}
629629 }
630630 }
631631 newobj = newObject (s , addr , types.StateAccount {})
@@ -696,18 +696,19 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
696696func (s * StateDB ) Copy () * StateDB {
697697 // Copy all the basic fields, initialize the memory ones
698698 state := & StateDB {
699- db : s .db ,
700- trie : s .db .CopyTrie (s .trie ),
701- originalRoot : s .originalRoot ,
702- stateObjects : make (map [common.Address ]* stateObject , len (s .journal .dirties )),
703- stateObjectsPending : make (map [common.Address ]struct {}, len (s .stateObjectsPending )),
704- stateObjectsDirty : make (map [common.Address ]struct {}, len (s .journal .dirties )),
705- refund : s .refund ,
706- logs : make (map [common.Hash ][]* types.Log , len (s .logs )),
707- logSize : s .logSize ,
708- preimages : make (map [common.Hash ][]byte , len (s .preimages )),
709- journal : newJournal (),
710- hasher : crypto .NewKeccakState (),
699+ db : s .db ,
700+ trie : s .db .CopyTrie (s .trie ),
701+ originalRoot : s .originalRoot ,
702+ stateObjects : make (map [common.Address ]* stateObject , len (s .journal .dirties )),
703+ stateObjectsPending : make (map [common.Address ]struct {}, len (s .stateObjectsPending )),
704+ stateObjectsDirty : make (map [common.Address ]struct {}, len (s .journal .dirties )),
705+ stateObjectsDestruct : make (map [common.Address ]struct {}, len (s .stateObjectsDestruct )),
706+ refund : s .refund ,
707+ logs : make (map [common.Hash ][]* types.Log , len (s .logs )),
708+ logSize : s .logSize ,
709+ preimages : make (map [common.Hash ][]byte , len (s .preimages )),
710+ journal : newJournal (),
711+ hasher : crypto .NewKeccakState (),
711712 }
712713 // Copy the dirty states, logs, and preimages
713714 for addr := range s .journal .dirties {
@@ -725,9 +726,10 @@ func (s *StateDB) Copy() *StateDB {
725726 state .stateObjectsPending [addr ] = struct {}{} // Mark the copy pending to force external (account) commits
726727 }
727728 }
728- // Above, we don't copy the actual journal. This means that if the copy is copied, the
729- // loop above will be a no-op, since the copy's journal is empty.
730- // Thus, here we iterate over stateObjects, to enable copies of copies
729+ // Above, we don't copy the actual journal. This means that if the copy
730+ // is copied, the loop above will be a no-op, since the copy's journal
731+ // is empty. Thus, here we iterate over stateObjects, to enable copies
732+ // of copies.
731733 for addr := range s .stateObjectsPending {
732734 if _ , exist := state .stateObjects [addr ]; ! exist {
733735 state .stateObjects [addr ] = s .stateObjects [addr ].deepCopy (state )
@@ -740,6 +742,10 @@ func (s *StateDB) Copy() *StateDB {
740742 }
741743 state .stateObjectsDirty [addr ] = struct {}{}
742744 }
745+ // Deep copy the destruction flag.
746+ for addr := range s .stateObjectsDestruct {
747+ state .stateObjectsDestruct [addr ] = struct {}{}
748+ }
743749 for hash , logs := range s .logs {
744750 cpy := make ([]* types.Log , len (logs ))
745751 for i , l := range logs {
@@ -751,13 +757,13 @@ func (s *StateDB) Copy() *StateDB {
751757 for hash , preimage := range s .preimages {
752758 state .preimages [hash ] = preimage
753759 }
754- // Do we need to copy the access list? In practice: No. At the start of a
755- // transaction, the access list is empty. In practice, we only ever copy state
756- // _between_ transactions/blocks, never in the middle of a transaction.
757- // However, it doesn't cost us much to copy an empty list, so we do it anyway
758- // to not blow up if we ever decide copy it in the middle of a transaction
760+ // Do we need to copy the access list and transient storage?
761+ // In practice: No. At the start of a transaction, these two lists are empty.
762+ // In practice, we only ever copy state _between_ transactions/blocks, never
763+ // in the middle of a transaction. However, it doesn't cost us much to copy
764+ // empty lists, so we do it anyway to not blow up if we ever decide copy them
765+ // in the middle of a transaction.
759766 state .accessList = s .accessList .Copy ()
760-
761767 state .transientStorage = s .transientStorage .Copy ()
762768
763769 // If there's a prefetcher running, make an inactive copy of it that can
@@ -768,16 +774,13 @@ func (s *StateDB) Copy() *StateDB {
768774 }
769775 if s .snaps != nil {
770776 // In order for the miner to be able to use and make additions
771- // to the snapshot tree, we need to copy that aswell .
777+ // to the snapshot tree, we need to copy that as well .
772778 // Otherwise, any block mined by ourselves will cause gaps in the tree,
773779 // and force the miner to operate trie-backed only
774780 state .snaps = s .snaps
775781 state .snap = s .snap
782+
776783 // deep copy needed
777- state .snapDestructs = make (map [common.Hash ]struct {})
778- for k , v := range s .snapDestructs {
779- state .snapDestructs [k ] = v
780- }
781784 state .snapAccounts = make (map [common.Hash ][]byte )
782785 for k , v := range s .snapAccounts {
783786 state .snapAccounts [k ] = v
@@ -842,14 +845,17 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
842845 if obj .suicided || (deleteEmptyObjects && obj .empty ()) {
843846 obj .deleted = true
844847
848+ // We need to maintain account deletions explicitly (will remain
849+ // set indefinitely).
850+ s .stateObjectsDestruct [obj .address ] = struct {}{}
851+
845852 // If state snapshotting is active, also mark the destruction there.
846853 // Note, we can't do this only at the end of a block because multiple
847854 // transactions within the same block might self destruct and then
848855 // resurrect an account; but the snapshotter needs both events.
849856 if s .snap != nil {
850- s .snapDestructs [obj .addrHash ] = struct {}{} // We need to maintain account deletions explicitly (will remain set indefinitely)
851- delete (s .snapAccounts , obj .addrHash ) // Clear out any previously updated account data (may be recreated via a resurrect)
852- delete (s .snapStorage , obj .addrHash ) // Clear out any previously updated storage data (may be recreated via a resurrect)
857+ delete (s .snapAccounts , obj .addrHash ) // Clear out any previously updated account data (may be recreated via a resurrect)
858+ delete (s .snapStorage , obj .addrHash ) // Clear out any previously updated storage data (may be recreated via a resurrect)
853859 }
854860 } else {
855861 obj .finalise (true ) // Prefetch slots in the background
@@ -1037,7 +1043,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
10371043 start := time .Now ()
10381044 // Only update if there's a state transition (skip empty Clique blocks)
10391045 if parent := s .snap .Root (); parent != root {
1040- if err := s .snaps .Update (root , parent , s .snapDestructs , s .snapAccounts , s .snapStorage ); err != nil {
1046+ if err := s .snaps .Update (root , parent , s .convertAccountSet ( s . stateObjectsDestruct ) , s .snapAccounts , s .snapStorage ); err != nil {
10411047 log .Warn ("Failed to update snapshot tree" , "from" , parent , "to" , root , "err" , err )
10421048 }
10431049 // Keep 128 diff layers in the memory, persistent layer is 129th.
@@ -1051,7 +1057,10 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
10511057 if metrics .EnabledExpensive {
10521058 s .SnapshotCommits += time .Since (start )
10531059 }
1054- s .snap , s .snapDestructs , s .snapAccounts , s .snapStorage = nil , nil , nil , nil
1060+ s .snap , s .snapAccounts , s .snapStorage = nil , nil , nil
1061+ }
1062+ if len (s .stateObjectsDestruct ) > 0 {
1063+ s .stateObjectsDestruct = make (map [common.Address ]struct {})
10551064 }
10561065 if root == (common.Hash {}) {
10571066 root = emptyRoot
@@ -1148,3 +1157,17 @@ func (s *StateDB) AddressInAccessList(addr common.Address) bool {
11481157func (s * StateDB ) SlotInAccessList (addr common.Address , slot common.Hash ) (addressPresent bool , slotPresent bool ) {
11491158 return s .accessList .Contains (addr , slot )
11501159}
1160+
1161+ // convertAccountSet converts a provided account set from address keyed to hash keyed.
1162+ func (s * StateDB ) convertAccountSet (set map [common.Address ]struct {}) map [common.Hash ]struct {} {
1163+ ret := make (map [common.Hash ]struct {})
1164+ for addr := range set {
1165+ obj , exist := s .stateObjects [addr ]
1166+ if ! exist {
1167+ ret [crypto .Keccak256Hash (addr [:])] = struct {}{}
1168+ } else {
1169+ ret [obj .addrHash ] = struct {}{}
1170+ }
1171+ }
1172+ return ret
1173+ }
0 commit comments