Skip to content
This repository was archived by the owner on May 23, 2023. It is now read-only.

Commit 60143a9

Browse files
Jan Xiekonradkonrad
authored andcommitted
optimize snapshot create and load
1 parent 80f023f commit 60143a9

File tree

2 files changed

+59
-6
lines changed

2 files changed

+59
-6
lines changed

ethereum/pruning_trie.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,49 @@ def to_dict(self):
884884
res[key] = value
885885
return res
886886

887+
def iter_branch(self):
888+
for key_str, value in self._iter_branch(self.root_node):
889+
if key_str:
890+
nibbles = [int(x) for x in key_str.split(b'+')]
891+
else:
892+
nibbles = []
893+
key = nibbles_to_bin(without_terminator(nibbles))
894+
yield key, value
895+
896+
def _iter_branch(self, node):
897+
'''yield (key, value) stored in this and the descendant nodes
898+
:param node: node in form of list, or BLANK_NODE
899+
900+
.. note::
901+
Here key is in full form, rather than key of the individual node
902+
'''
903+
if node == BLANK_NODE:
904+
raise StopIteration
905+
906+
node_type = self._get_node_type(node)
907+
908+
if is_key_value_type(node_type):
909+
nibbles = without_terminator(unpack_to_nibbles(node[0]))
910+
key = b'+'.join([to_string(x) for x in nibbles])
911+
if node_type == NODE_TYPE_EXTENSION:
912+
sub_tree = self._iter_branch(self._decode_to_node(node[1]))
913+
else:
914+
sub_tree = [(to_string(NIBBLE_TERMINATOR), node[1])]
915+
916+
# prepend key of this node to the keys of children
917+
for sub_key, sub_value in sub_tree:
918+
full_key = (key + b'+' + sub_key).strip(b'+')
919+
yield (full_key, sub_value)
920+
921+
elif node_type == NODE_TYPE_BRANCH:
922+
for i in range(16):
923+
sub_tree = self._iter_branch(self._decode_to_node(node[i]))
924+
for sub_key, sub_value in sub_tree:
925+
full_key = (str_to_bytes(str(i)) + b'+' + sub_key).strip(b'+')
926+
yield (full_key, sub_value)
927+
if node[16]:
928+
yield (to_string(NIBBLE_TERMINATOR), node[-1])
929+
887930
def get(self, key):
888931
return self._get(self.root_node, bin_to_nibbles(to_string(key)))
889932

ethereum/snapshot.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
from ethereum.blocks import Account, BlockHeader, Block, CachedBlock
44
from ethereum.utils import is_numeric, is_string, encode_hex, decode_hex, zpad, scan_bin, big_endian_to_int
55
from ethereum.securetrie import SecureTrie
6-
from ethereum.trie import Trie, BLANK_NODE, BLANK_ROOT
6+
from ethereum.trie import BLANK_NODE, BLANK_ROOT
7+
from ethereum.pruning_trie import Trie
78

89

910
class FakeHeader(object):
@@ -68,18 +69,18 @@ def create_base_snapshot(base):
6869
def create_state_snapshot(env, state_trie):
6970
alloc = dict()
7071
count = 0
71-
for addr, account_rlp in state_trie.to_dict().items():
72+
for addr, account_rlp in state_trie.iter_branch():
7273
alloc[encode_hex(addr)] = create_account_snapshot(env, account_rlp)
7374
count += 1
74-
print "[%d] created account snapshot %s" % encode_hex(addr)
75+
print "[%d] created account snapshot %s" % (count, encode_hex(addr))
7576
return alloc
7677

7778

7879
def create_account_snapshot(env, rlpdata):
7980
account = get_account(env, rlpdata)
8081
storage_trie = SecureTrie(Trie(env.db, account.storage))
8182
storage = dict()
82-
for k, v in storage_trie.to_dict().items():
83+
for k, v in storage_trie.iter_branch():
8384
storage[encode_hex(k.lstrip('\x00') or '\x00')] = encode_hex(v)
8485
return {
8586
'nonce': snapshot_form(account.nonce),
@@ -132,6 +133,7 @@ def get_block(env, blockhash):
132133
def validate_uncles():
133134
return True
134135

136+
print "Start loading recent blocks from snapshot"
135137
first_block = rlp.decode(first_block_rlp, Block, env=chain.env)
136138
chain.index.add_block(first_block)
137139
chain._store_block(first_block)
@@ -157,11 +159,15 @@ def validate_uncles():
157159
def load_state(env, alloc):
158160
db = env.db
159161
state = SecureTrie(Trie(db, BLANK_ROOT))
160-
for addr, account in alloc.items():
162+
count = 0
163+
print "Start loading state from snapshot"
164+
for addr in alloc:
165+
account = alloc[addr]
161166
acct = Account.blank_account(db, env.config['ACCOUNT_INITIAL_NONCE'])
162167
if len(account['storage']) > 0:
163168
t = SecureTrie(Trie(db, BLANK_ROOT))
164-
for k, v in account['storage'].items():
169+
for k in account['storage']:
170+
v = account['storage'][k]
165171
enckey = zpad(decode_hex(k), 32)
166172
t.update(enckey, decode_hex(v))
167173
acct.storage = t.root_hash
@@ -172,6 +178,10 @@ def load_state(env, alloc):
172178
if account['code']:
173179
acct.code = decode_hex(account['code'])
174180
state.update(decode_hex(addr), rlp.encode(acct))
181+
count += 1
182+
if count % 1000 == 0:
183+
db.commit()
184+
print "[%d] loaded account %s" % (count, addr)
175185
db.commit()
176186
return state
177187

0 commit comments

Comments
 (0)