@@ -93,21 +93,35 @@ impl AccountEntry {
93
93
}
94
94
}
95
95
96
- // Create a new account entry and mark it as dirty
96
+ // Create a new account entry and mark it as dirty.
97
97
fn new_dirty ( account : Option < Account > ) -> AccountEntry {
98
98
AccountEntry {
99
99
account : account,
100
100
state : AccountState :: Dirty ,
101
101
}
102
102
}
103
-
104
- // Create a new account entry and mark it as clean
103
+
104
+ // Create a new account entry and mark it as clean.
105
105
fn new_clean ( account : Option < Account > ) -> AccountEntry {
106
106
AccountEntry {
107
107
account : account,
108
108
state : AccountState :: Clean ,
109
109
}
110
110
}
111
+
112
+ // Replace data with another entry but preserve storage cache.
113
+ fn overwrite_with ( & mut self , other : AccountEntry ) {
114
+ self . state = other. state ;
115
+ match other. account {
116
+ Some ( acc) => match self . account {
117
+ Some ( ref mut ours) => {
118
+ ours. overwrite_with ( acc) ;
119
+ } ,
120
+ None => { } ,
121
+ } ,
122
+ None => self . account = None ,
123
+ }
124
+ }
111
125
}
112
126
113
127
/// Representation of the entire state of all accounts in the system.
@@ -142,10 +156,24 @@ impl AccountEntry {
142
156
///
143
157
/// Upon destruction all the local cache data merged into the global cache.
144
158
/// The merge might be rejected if current state is non-canonical.
159
+ ///
160
+ /// State snapshotting.
161
+ ///
162
+ /// A new snapshot can be created with `snapshot()`. Snapshots can be
163
+ /// created in a hierarchy.
164
+ /// When a snapshot is active all changes are applied directly into
165
+ /// `cache` and the original value is copied into an active snapshot.
166
+ /// Reverting a snapshot with `revert_to_snapshot` involves copying
167
+ /// original values from the latest snapshot back into `cache`. The code
168
+ /// takes care not to overwrite cached storage while doing that.
169
+ /// Snapshot can be discateded with `discard_snapshot`. All of the orignal
170
+ /// backed-up values are moved into a parent snapshot (if any).
171
+ ///
145
172
pub struct State {
146
173
db : StateDB ,
147
174
root : H256 ,
148
175
cache : RefCell < HashMap < Address , AccountEntry > > ,
176
+ // The original account is preserved in
149
177
snapshots : RefCell < Vec < HashMap < Address , Option < AccountEntry > > > > ,
150
178
account_start_nonce : U256 ,
151
179
factories : Factories ,
@@ -199,31 +227,44 @@ impl State {
199
227
Ok ( state)
200
228
}
201
229
202
- /// Create a recoverable snaphot of this state
230
+ /// Create a recoverable snaphot of this state.
203
231
pub fn snapshot ( & mut self ) {
204
232
self . snapshots . borrow_mut ( ) . push ( HashMap :: new ( ) ) ;
205
233
}
206
234
207
- /// Merge last snapshot with previous
208
- pub fn clear_snapshot ( & mut self ) {
235
+ /// Merge last snapshot with previous.
236
+ pub fn discard_snapshot ( & mut self ) {
209
237
// merge with previous snapshot
210
238
let last = self . snapshots . borrow_mut ( ) . pop ( ) ;
211
239
if let Some ( mut snapshot) = last {
212
240
if let Some ( ref mut prev) = self . snapshots . borrow_mut ( ) . last_mut ( ) {
213
- for ( k, v) in snapshot. drain ( ) {
214
- prev. entry ( k) . or_insert ( v) ;
241
+ if prev. is_empty ( ) {
242
+ * * prev = snapshot;
243
+ } else {
244
+ for ( k, v) in snapshot. drain ( ) {
245
+ prev. entry ( k) . or_insert ( v) ;
246
+ }
215
247
}
216
248
}
217
249
}
218
250
}
219
251
220
- /// Revert to snapshot
221
- pub fn revert_snapshot ( & mut self ) {
252
+ /// Revert to the last snapshot and discard it.
253
+ pub fn revert_to_snapshot ( & mut self ) {
222
254
if let Some ( mut snapshot) = self . snapshots . borrow_mut ( ) . pop ( ) {
223
255
for ( k, v) in snapshot. drain ( ) {
224
256
match v {
225
257
Some ( v) => {
226
- self . cache . borrow_mut ( ) . insert ( k, v) ;
258
+ match self . cache . borrow_mut ( ) . entry ( k) {
259
+ Entry :: Occupied ( mut e) => {
260
+ // Merge snapshotted changes back into the main account
261
+ // storage preserving the cache.
262
+ e. get_mut ( ) . overwrite_with ( v) ;
263
+ } ,
264
+ Entry :: Vacant ( e) => {
265
+ e. insert ( v) ;
266
+ }
267
+ }
227
268
} ,
228
269
None => {
229
270
match self . cache . borrow_mut ( ) . entry ( k) {
@@ -1717,12 +1758,12 @@ fn snapshot_basic() {
1717
1758
state. snapshot ( ) ;
1718
1759
state. add_balance ( & a, & U256 :: from ( 69u64 ) ) ;
1719
1760
assert_eq ! ( state. balance( & a) , U256 :: from( 69u64 ) ) ;
1720
- state. clear_snapshot ( ) ;
1761
+ state. discard_snapshot ( ) ;
1721
1762
assert_eq ! ( state. balance( & a) , U256 :: from( 69u64 ) ) ;
1722
1763
state. snapshot ( ) ;
1723
1764
state. add_balance ( & a, & U256 :: from ( 1u64 ) ) ;
1724
1765
assert_eq ! ( state. balance( & a) , U256 :: from( 70u64 ) ) ;
1725
- state. revert_snapshot ( ) ;
1766
+ state. revert_to_snapshot ( ) ;
1726
1767
assert_eq ! ( state. balance( & a) , U256 :: from( 69u64 ) ) ;
1727
1768
}
1728
1769
@@ -1735,9 +1776,9 @@ fn snapshot_nested() {
1735
1776
state. snapshot ( ) ;
1736
1777
state. add_balance ( & a, & U256 :: from ( 69u64 ) ) ;
1737
1778
assert_eq ! ( state. balance( & a) , U256 :: from( 69u64 ) ) ;
1738
- state. clear_snapshot ( ) ;
1779
+ state. discard_snapshot ( ) ;
1739
1780
assert_eq ! ( state. balance( & a) , U256 :: from( 69u64 ) ) ;
1740
- state. revert_snapshot ( ) ;
1781
+ state. revert_to_snapshot ( ) ;
1741
1782
assert_eq ! ( state. balance( & a) , U256 :: from( 0 ) ) ;
1742
1783
}
1743
1784
0 commit comments