@@ -70,8 +70,6 @@ def __init__(self, nonce, balance, storage, code_hash, env):
70
70
71
71
def commit (self ):
72
72
for k , v in self .storage_cache .items ():
73
- assert is_numeric (k )
74
- assert is_numeric (v )
75
73
if v :
76
74
self .storage_trie .update (utils .encode_int32 (k ), rlp .encode (v ))
77
75
else :
@@ -85,7 +83,6 @@ def code(self):
85
83
86
84
@code .setter
87
85
def code (self , value ):
88
- assert is_string (value )
89
86
self .code_hash = utils .sha3 (value )
90
87
# Technically a db storage leak, but doesn't really matter; the only
91
88
# thing that fails to get garbage collected is when code disappears due
@@ -94,15 +91,12 @@ def code(self, value):
94
91
# self.env.db.inc_refcount(self.code_hash, value)
95
92
96
93
def get_storage_data (self , key ):
97
- assert is_numeric (key )
98
94
if key not in self .storage_cache :
99
95
v = self .storage_trie .get (utils .encode_int32 (key ))
100
96
self .storage_cache [key ] = utils .big_endian_to_int (rlp .decode (v ) if v else b'' )
101
97
return self .storage_cache [key ]
102
98
103
99
def set_storage_data (self , key , value ):
104
- assert is_numeric (key )
105
- assert is_numeric (value )
106
100
self .storage_cache [key ] = value
107
101
108
102
@classmethod
@@ -186,7 +180,6 @@ def set_and_journal(self, acct, param, val):
186
180
# self.journal.append((acct, param, getattr(acct, param)))
187
181
preval = getattr (acct , param )
188
182
self .journal .append (lambda : setattr (acct , param , preval ))
189
- assert acct ._mutable
190
183
setattr (acct , param , val )
191
184
192
185
def set_balance (self , address , value ):
@@ -368,6 +361,57 @@ def to_snapshot(self, root_only=False, no_prevblocks=False):
368
361
snapshot [k ] = {str (n ): ['0x' + encode_hex (h ) for h in headers ] for n , headers in v .items ()}
369
362
return snapshot
370
363
364
+ # Creates a state from a snapshot
365
+ @classmethod
366
+ def from_snapshot (cls , snapshot_data , env ):
367
+ state = State (env = env )
368
+ if "alloc" in snapshot_data :
369
+ for addr , data in snapshot_data ["alloc" ].items ():
370
+ if len (addr ) == 40 :
371
+ addr = decode_hex (addr )
372
+ assert len (addr ) == 20
373
+ if 'wei' in data :
374
+ state .set_balance (addr , parse_as_int (data ['wei' ]))
375
+ if 'balance' in data :
376
+ state .set_balance (addr , parse_as_int (data ['balance' ]))
377
+ if 'code' in data :
378
+ state .set_code (addr , parse_as_bin (data ['code' ]))
379
+ if 'nonce' in data :
380
+ state .set_nonce (addr , parse_as_int (data ['nonce' ]))
381
+ if 'storage' in data :
382
+ for k , v in data ['storage' ].items ():
383
+ state .set_storage_data (addr , parse_as_bin (k ), parse_as_bin (v ))
384
+ elif "state_root" in snapshot_data :
385
+ state .trie .root_hash = parse_as_bin (snapshot_data ["state_root" ])
386
+ else :
387
+ raise Exception ("Must specify either alloc or state root parameter" )
388
+ for k , default in STATE_DEFAULTS .items ():
389
+ default = copy .copy (default )
390
+ v = snapshot_data [k ] if k in snapshot_data else None
391
+ if is_numeric (default ):
392
+ setattr (state , k , parse_as_int (v ) if k in snapshot_data else default )
393
+ elif is_string (default ):
394
+ setattr (state , k , parse_as_bin (v ) if k in snapshot_data else default )
395
+ elif k == 'prev_headers' :
396
+ if k in snapshot_data :
397
+ headers = [dict_to_prev_header (h ) for h in v ]
398
+ else :
399
+ headers = default
400
+ setattr (state , k , headers )
401
+ elif k == 'recent_uncles' :
402
+ if k in snapshot_data :
403
+ uncles = {}
404
+ for height , _uncles in v .items ():
405
+ uncles [int (height )] = []
406
+ for uncle in _uncles :
407
+ uncles [int (height )].append (parse_as_bin (uncle ))
408
+ else :
409
+ uncles = default
410
+ setattr (state , k , uncles )
411
+ state .commit ()
412
+ return state
413
+
414
+
371
415
def ephemeral_clone (self ):
372
416
snapshot = self .to_snapshot (root_only = True , no_prevblocks = True )
373
417
env2 = Env (OverlayDB (self .env .db ), self .env .config )
@@ -376,8 +420,9 @@ def ephemeral_clone(self):
376
420
setattr (s , param , getattr (self , param ))
377
421
s .recent_uncles = self .recent_uncles
378
422
s .prev_headers = self .prev_headers
379
- assert len (self .journal ) == len (self .cache ) == 0
380
- s .journal = []
423
+ for acct in self .cache .values ():
424
+ assert not acct .touched
425
+ s .journal = copy .copy (self .journal )
381
426
s .cache = {}
382
427
return s
383
428
0 commit comments