@@ -72,16 +72,16 @@ type StateDB struct {
72
72
// It will be updated when the Commit is called.
73
73
originalRoot common.Hash
74
74
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
80
79
81
80
// 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
85
85
86
86
// DB error.
87
87
// 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)
139
139
return nil , err
140
140
}
141
141
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 (),
155
156
}
156
157
if sdb .snaps != nil {
157
158
if sdb .snap = sdb .snaps .Snapshot (root ); sdb .snap != nil {
158
- sdb .snapDestructs = make (map [common.Hash ]struct {})
159
159
sdb .snapAccounts = make (map [common.Hash ][]byte )
160
160
sdb .snapStorage = make (map [common.Hash ]map [common.Hash ][]byte )
161
161
}
@@ -622,10 +622,10 @@ func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject)
622
622
prev = s .getDeletedStateObject (addr ) // Note, prev might have been deleted, we need that!
623
623
624
624
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 ]
627
627
if ! prevdestruct {
628
- s .snapDestructs [prev .addrHash ] = struct {}{}
628
+ s .stateObjectsDestruct [prev .address ] = struct {}{}
629
629
}
630
630
}
631
631
newobj = newObject (s , addr , types.StateAccount {})
@@ -696,18 +696,19 @@ func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common
696
696
func (s * StateDB ) Copy () * StateDB {
697
697
// Copy all the basic fields, initialize the memory ones
698
698
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 (),
711
712
}
712
713
// Copy the dirty states, logs, and preimages
713
714
for addr := range s .journal .dirties {
@@ -725,9 +726,10 @@ func (s *StateDB) Copy() *StateDB {
725
726
state .stateObjectsPending [addr ] = struct {}{} // Mark the copy pending to force external (account) commits
726
727
}
727
728
}
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.
731
733
for addr := range s .stateObjectsPending {
732
734
if _ , exist := state .stateObjects [addr ]; ! exist {
733
735
state .stateObjects [addr ] = s .stateObjects [addr ].deepCopy (state )
@@ -740,6 +742,10 @@ func (s *StateDB) Copy() *StateDB {
740
742
}
741
743
state .stateObjectsDirty [addr ] = struct {}{}
742
744
}
745
+ // Deep copy the destruction flag.
746
+ for addr := range s .stateObjectsDestruct {
747
+ state .stateObjectsDestruct [addr ] = struct {}{}
748
+ }
743
749
for hash , logs := range s .logs {
744
750
cpy := make ([]* types.Log , len (logs ))
745
751
for i , l := range logs {
@@ -751,13 +757,13 @@ func (s *StateDB) Copy() *StateDB {
751
757
for hash , preimage := range s .preimages {
752
758
state .preimages [hash ] = preimage
753
759
}
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.
759
766
state .accessList = s .accessList .Copy ()
760
-
761
767
state .transientStorage = s .transientStorage .Copy ()
762
768
763
769
// If there's a prefetcher running, make an inactive copy of it that can
@@ -768,16 +774,13 @@ func (s *StateDB) Copy() *StateDB {
768
774
}
769
775
if s .snaps != nil {
770
776
// 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 .
772
778
// Otherwise, any block mined by ourselves will cause gaps in the tree,
773
779
// and force the miner to operate trie-backed only
774
780
state .snaps = s .snaps
775
781
state .snap = s .snap
782
+
776
783
// deep copy needed
777
- state .snapDestructs = make (map [common.Hash ]struct {})
778
- for k , v := range s .snapDestructs {
779
- state .snapDestructs [k ] = v
780
- }
781
784
state .snapAccounts = make (map [common.Hash ][]byte )
782
785
for k , v := range s .snapAccounts {
783
786
state .snapAccounts [k ] = v
@@ -842,14 +845,17 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
842
845
if obj .suicided || (deleteEmptyObjects && obj .empty ()) {
843
846
obj .deleted = true
844
847
848
+ // We need to maintain account deletions explicitly (will remain
849
+ // set indefinitely).
850
+ s .stateObjectsDestruct [obj .address ] = struct {}{}
851
+
845
852
// If state snapshotting is active, also mark the destruction there.
846
853
// Note, we can't do this only at the end of a block because multiple
847
854
// transactions within the same block might self destruct and then
848
855
// resurrect an account; but the snapshotter needs both events.
849
856
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)
853
859
}
854
860
} else {
855
861
obj .finalise (true ) // Prefetch slots in the background
@@ -1037,7 +1043,7 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
1037
1043
start := time .Now ()
1038
1044
// Only update if there's a state transition (skip empty Clique blocks)
1039
1045
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 {
1041
1047
log .Warn ("Failed to update snapshot tree" , "from" , parent , "to" , root , "err" , err )
1042
1048
}
1043
1049
// Keep 128 diff layers in the memory, persistent layer is 129th.
@@ -1051,7 +1057,10 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
1051
1057
if metrics .EnabledExpensive {
1052
1058
s .SnapshotCommits += time .Since (start )
1053
1059
}
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 {})
1055
1064
}
1056
1065
if root == (common.Hash {}) {
1057
1066
root = emptyRoot
@@ -1148,3 +1157,17 @@ func (s *StateDB) AddressInAccessList(addr common.Address) bool {
1148
1157
func (s * StateDB ) SlotInAccessList (addr common.Address , slot common.Hash ) (addressPresent bool , slotPresent bool ) {
1149
1158
return s .accessList .Contains (addr , slot )
1150
1159
}
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