1
+ import json
2
+ import random
1
3
import time
2
- from ethereum import utils
3
- from ethereum .utils import parse_as_bin , big_endian_to_int
4
- from ethereum import parse_genesis_declaration
5
- from ethereum .state_transition import apply_block , initialize , \
6
- pre_seal_finalize , post_seal_finalize , apply_transaction , mk_receipt_sha , \
7
- mk_transaction_sha , calc_difficulty , Receipt , mk_receipt , \
8
- update_block_env_variables , validate_uncles , validate_block_header
4
+
9
5
import rlp
10
6
from rlp .utils import encode_hex
11
- from ethereum . exceptions import InvalidNonce , InsufficientStartGas , UnsignedTransaction , \
12
- BlockGasLimitReached , InsufficientBalance
13
- from ethereum .slogging import get_logger
7
+
8
+ from ethereum import parse_genesis_declaration
9
+ from ethereum .block import Block , BlockHeader , FakeHeader , BLANK_UNCLES_HASH
14
10
from ethereum .config import Env
11
+ from ethereum .slogging import get_logger
15
12
from ethereum .state import State , dict_to_prev_header
16
- from ethereum .block import Block , BlockHeader , FakeHeader , BLANK_UNCLES_HASH
17
- import random
18
- import json
13
+ from ethereum .state_transition import apply_block , initialize , \
14
+ update_block_env_variables
15
+ from ethereum .utils import parse_as_bin , big_endian_to_int
16
+
19
17
log = get_logger ('eth.chain' )
20
18
21
19
22
20
class Chain (object ):
23
21
24
22
def __init__ (self , genesis = None , env = None , coinbase = b'\x00 ' * 20 , \
25
- new_head_cb = None , ** kwargs ):
23
+ new_head_cb = None , reset_genesis = False , ** kwargs ):
26
24
self .env = env or Env ()
27
25
# Initialize the state
28
- if 'head_hash' in self .db :
26
+ if 'head_hash' in self .db : # new head tag
29
27
self .state = self .mk_poststate_of_blockhash (self .db .get ('head_hash' ))
30
28
print ('Initializing chain from saved head, #%d (%s)' % \
31
29
(self .state .prev_headers [0 ].number , encode_hex (self .state .prev_headers [0 ].hash )))
30
+ elif 'HEAD' in self .db : # deprecated head tag
31
+ self .state = self .mk_poststate_of_blockhash (self .db .get ('HEAD' ), convert = True )
32
+ print ('Converting chain from saved head in deprecated format, #%d (%s)' % \
33
+ (self .state .prev_headers [0 ].number , encode_hex (self .state .prev_headers [0 ].hash )))
32
34
elif genesis is None :
33
35
raise Exception ("Need genesis decl!" )
34
36
elif isinstance (genesis , State ):
@@ -37,9 +39,11 @@ def __init__(self, genesis=None, env=None, coinbase=b'\x00' * 20, \
37
39
elif "extraData" in genesis :
38
40
self .state = parse_genesis_declaration .state_from_genesis_declaration (
39
41
genesis , self .env )
42
+ reset_genesis = True
40
43
print ('Initializing chain from provided genesis declaration' )
41
44
elif "prev_headers" in genesis :
42
45
self .state = State .from_snapshot (genesis , self .env )
46
+ reset_genesis = True
43
47
print ('Initializing chain from provided state snapshot, %d (%s)' % \
44
48
(self .state .block_number , encode_hex (self .state .prev_headers [0 ].hash [:8 ])))
45
49
else :
@@ -53,19 +57,23 @@ def __init__(self, genesis=None, env=None, coinbase=b'\x00' * 20, \
53
57
"hash" : kwargs .get ('prevhash' , '00' * 32 ),
54
58
"uncles_hash" : kwargs .get ('uncles_hash' , '0x' + encode_hex (BLANK_UNCLES_HASH ))
55
59
}, self .env )
60
+ reset_genesis = True
56
61
57
62
initialize (self .state )
58
63
self .new_head_cb = new_head_cb
59
64
60
65
self .head_hash = self .state .prev_headers [0 ].hash
61
- self .genesis = Block (self .state .prev_headers [0 ], [], [])
62
- self .db .put ('state:' + self .head_hash , self .state .trie .root_hash )
63
- self .db .put ('GENESIS_NUMBER' , str (self .state .block_number ))
64
- self .db .put ('GENESIS_HASH' , str (self .state .prev_headers [0 ].hash ))
65
66
assert self .state .block_number == self .state .prev_headers [0 ].number
66
- self .db .put ('score:' + self .state .prev_headers [0 ].hash , "0" )
67
- self .db .put ('GENESIS_STATE' , json .dumps (self .state .to_snapshot ()))
68
- self .db .put (self .head_hash , 'GENESIS' )
67
+ self .db .put ('state:' + self .head_hash , self .state .trie .root_hash )
68
+ if reset_genesis :
69
+ self .genesis = Block (self .state .prev_headers [0 ], [], [])
70
+ self .db .put ('GENESIS_NUMBER' , str (self .state .block_number ))
71
+ self .db .put ('GENESIS_HASH' , str (self .state .prev_headers [0 ].hash ))
72
+ self .db .put ('score:' + self .state .prev_headers [0 ].hash , "0" )
73
+ self .db .put ('GENESIS_STATE' , json .dumps (self .state .to_snapshot ()))
74
+ self .db .put (self .head_hash , 'GENESIS' )
75
+ else :
76
+ self .genesis = self .get_block_by_number (0 )
69
77
self .min_gasprice = kwargs .get ('min_gasprice' , 5 * 10 ** 9 )
70
78
self .coinbase = coinbase
71
79
self .extra_data = 'moo ha ha says the laughing cow.'
@@ -84,14 +92,17 @@ def head(self):
84
92
log .error (e )
85
93
return None
86
94
87
- def mk_poststate_of_blockhash (self , blockhash ):
95
+ def mk_poststate_of_blockhash (self , blockhash , convert = False ):
88
96
if blockhash not in self .db :
89
97
raise Exception ("Block hash %s not found" % encode_hex (blockhash ))
90
- if self .db .get (blockhash ) == 'GENESIS' :
98
+
99
+ block_rlp = self .db .get (blockhash )
100
+ if block_rlp == 'GENESIS' :
91
101
return State .from_snapshot (json .loads (self .db .get ('GENESIS_STATE' )), self .env )
102
+ block = rlp .decode (block_rlp , Block )
103
+
92
104
state = State (env = self .env )
93
- state .trie .root_hash = self .db .get ('state:' + blockhash )
94
- block = rlp .decode (self .db .get (blockhash ), Block )
105
+ state .trie .root_hash = block .header .state_root if convert else self .db .get ('state:' + blockhash )
95
106
update_block_env_variables (state , block )
96
107
state .gas_used = block .header .gas_used
97
108
state .txindex = len (block .transactions )
@@ -141,18 +152,18 @@ def get_block(self, blockhash):
141
152
# parent hash and see that it is one of its children
142
153
def add_child (self , child ):
143
154
try :
144
- existing = self .db .get ('child :' + child .header .prevhash )
155
+ existing = self .db .get ('ci :' + child .header .prevhash )
145
156
except :
146
157
existing = ''
147
158
existing_hashes = []
148
159
for i in range (0 , len (existing ), 32 ):
149
160
existing_hashes .append (existing [i : i + 32 ])
150
161
if child .header .hash not in existing_hashes :
151
- self .db .put ('child :' + child .header .prevhash , existing + child .header .hash )
162
+ self .db .put ('ci :' + child .header .prevhash , existing + child .header .hash )
152
163
153
164
def get_blockhash_by_number (self , number ):
154
165
try :
155
- return self .db .get ('block :' + str (number ))
166
+ return self .db .get ('blocknumber :' + str (number ))
156
167
except :
157
168
return None
158
169
0 commit comments