1
+ import os
2
+ import copy
3
+ import rlp
1
4
from ethereum import utils
2
5
from ethereum .utils import sha3 , ecsign , encode_int32
3
- from ethereum .state import State
4
6
from ethereum .transactions import Transaction
5
7
from ethereum .config import Env , default_config
6
8
from ethereum .state_transition import apply_transaction , apply_const_message , \
7
- initialize
9
+ apply_message , initialize
8
10
from ethereum .block import Block , BlockHeader
11
+ from ethereum .state import State
9
12
from ethereum .parse_genesis_declaration import mk_basic_state
10
13
from ethereum import vm
11
14
from ethereum import abi
12
- import copy
13
- import os
14
- import rlp
15
15
from ethereum .slogging import get_logger
16
+
16
17
log_bc = get_logger ('eth.block_creation' )
17
18
mydir = os .path .split (__file__ )[0 ]
18
19
casper_path = os .path .join (mydir , 'casper_contract.py' )
19
20
rlp_decoder_path = os .path .join (mydir , 'rlp_decoder_contract.py' )
20
21
hash_without_ed_path = os .path .join (mydir , 'hash_without_ed_contract.py' )
21
22
finalizer_path = os .path .join (mydir , 'finalizer_contract.py' )
22
23
24
+
25
+ # Get the final saved code of a contract from the init code
26
+ def get_contract_code (init_code ):
27
+ s = State (env = Env (config = casper_config ))
28
+ s .gas_limit = 10 ** 9
29
+ apply_transaction (s , Transaction (0 , 0 , 10 ** 8 , '' , 0 , init_code ))
30
+ addr = utils .mk_metropolis_contract_address (casper_config ['METROPOLIS_ENTRY_POINT' ], init_code )
31
+ o = s .get_code (addr )
32
+ assert o
33
+ return o
34
+
23
35
def get_casper_code ():
24
36
import serpent
25
37
return get_contract_code (serpent .compile (open (casper_path ).read ()))
@@ -36,29 +48,30 @@ def get_finalizer_code():
36
48
import serpent
37
49
return get_contract_code (serpent .compile (open (finalizer_path ).read ()))
38
50
39
- _casper_ct = None
40
-
41
- def get_casper_ct ():
42
- import serpent
43
- global _casper_ct
44
- if not _casper_ct :
45
- _casper_ct = abi .ContractTranslator (serpent .mk_full_signature (open (casper_path ).read ()))
46
- return _casper_ct
47
51
48
52
# The Casper-specific config declaration
49
53
casper_config = copy .deepcopy (default_config )
50
54
casper_config ['HOMESTEAD_FORK_BLKNUM' ] = 0
51
55
casper_config ['METROPOLIS_FORK_BLKNUM' ] = 0
52
56
casper_config ['SERENITY_FORK_BLKNUM' ] = 0
53
- casper_config ['HEADER_VALIDATION' ] = 'contract'
54
- casper_config ['HEADER_STRATEGY' ] = 'casper'
55
- casper_config ['FINALIZATION' ] = 'contract'
57
+ # config['CASPER_ADDR'] == config['SERENITY_HEADER_VERIFIER']
56
58
casper_config ['CASPER_ADDR' ] = utils .int_to_addr (255 )
57
59
casper_config ['RLP_DECODER_ADDR' ] = utils .int_to_addr (253 )
58
60
casper_config ['HASH_WITHOUT_BLOOM_ADDR' ] = utils .int_to_addr (252 )
59
61
casper_config ['MAX_UNCLE_DEPTH' ] = 0
60
62
casper_config ['PREV_HEADER_DEPTH' ] = 1
61
63
64
+
65
+ _casper_ct = None
66
+
67
+ def get_casper_ct ():
68
+ import serpent
69
+ global _casper_ct
70
+ if not _casper_ct :
71
+ _casper_ct = abi .ContractTranslator (serpent .mk_full_signature (open (casper_path ).read ()))
72
+ return _casper_ct
73
+
74
+
62
75
# RandaoManager object to be used by validators to provide randaos
63
76
# when signing their block
64
77
RANDAO_SAVE_INTERVAL = 100
@@ -88,16 +101,6 @@ def get_parent(self, val):
88
101
val = utils .sha3 (val )
89
102
raise Exception ("Randao parent not found" )
90
103
91
- # Get the final saved code of a contract from the init code
92
- def get_contract_code (init_code ):
93
- s = State (env = Env (config = casper_config ))
94
- s .gas_limit = 10 ** 9
95
- apply_transaction (s , Transaction (0 , 0 , 10 ** 8 , '' , 0 , init_code ))
96
- addr = utils .mk_metropolis_contract_address (casper_config ['METROPOLIS_ENTRY_POINT' ], init_code )
97
- o = s .get_code (addr )
98
- assert o
99
- return o
100
-
101
104
# Create the validation code for a given address
102
105
def generate_validation_code (addr ):
103
106
import serpent
@@ -163,58 +166,77 @@ def make_withdrawal_signature(key):
163
166
v , r , s = ecsign (h , key )
164
167
return encode_int32 (v ) + encode_int32 (r ) + encode_int32 (s )
165
168
169
+ def casper_contract_bootstrap (state , timestamp = 0 , epoch_length = 100 , number = 0 , gas_limit = 4712388 , nonce = 0 ):
170
+ ct = get_casper_ct ()
171
+ # Set genesis time, and initialize epoch number
172
+ t = Transaction (nonce , 0 , 10 ** 8 , casper_config ['CASPER_ADDR' ], 0 , ct .encode ('initialize' , [timestamp , epoch_length , number , gas_limit ]))
173
+ success = apply_transaction (state , t )
174
+ assert success
175
+
176
+ def validator_inject (state , vcode , deposit_size , randao_commitment , address , nonce = 0 , ct = None ):
177
+ if not ct :
178
+ ct = get_casper_ct ()
179
+ state .set_balance (utils .int_to_addr (1 ), deposit_size )
180
+ t = Transaction (nonce , 0 , 10 ** 8 , casper_config ['CASPER_ADDR' ], deposit_size ,
181
+ ct .encode ('deposit' , [vcode , randao_commitment , address ]))
182
+ t ._sender = utils .int_to_addr (1 )
183
+ success = apply_transaction (state , t )
184
+ assert success
185
+
186
+ def casper_state_initialize (state ):
187
+ config = state .config
188
+
189
+ # preparation for casper
190
+ # TODO: maybe serveral blocks before serenity hf?
191
+ if state .is_SERENITY (at_fork_height = True ):
192
+ state .set_code (config ['CASPER_ADDR' ], get_casper_code ())
193
+ state .set_code (config ['RLP_DECODER_ADDR' ], get_rlp_decoder_code ())
194
+ state .set_code (config ['HASH_WITHOUT_BLOOM_ADDR' ], get_hash_without_ed_code ())
195
+ state .set_code (config ['SERENITY_HEADER_POST_FINALIZER' ], get_finalizer_code ())
196
+ state .set_code (config ['METROPOLIS_STATEROOT_STORE' ], config ['SERENITY_GETTER_CODE' ])
197
+ state .set_code (config ['METROPOLIS_BLOCKHASH_STORE' ], config ['SERENITY_GETTER_CODE' ])
198
+
166
199
# Create a casper genesis from given parameters
167
200
# Validators: (vcode, deposit_size, randao_commitment)
168
201
# Alloc: state declaration
169
202
def make_casper_genesis (validators , alloc , timestamp = 0 , epoch_length = 100 ):
170
- state = mk_basic_state ({} , None , env = Env (config = casper_config ))
203
+ state = mk_basic_state (alloc , None , env = Env (config = casper_config ))
171
204
state .gas_limit = 10 ** 8 * (len (validators ) + 1 )
172
- state .prev_headers [0 ].timestamp = timestamp
173
- state .prev_headers [0 ].difficulty = 1
174
205
state .timestamp = timestamp
175
206
state .block_difficulty = 1
176
- state .set_code (casper_config ['CASPER_ADDR' ], get_casper_code ())
177
- state .set_code (casper_config ['RLP_DECODER_ADDR' ], get_rlp_decoder_code ())
178
- state .set_code (casper_config ['HASH_WITHOUT_BLOOM_ADDR' ], get_hash_without_ed_code ())
179
- state .set_code (casper_config ['SERENITY_HEADER_POST_FINALIZER' ], get_finalizer_code ())
180
- state .set_code (casper_config ['METROPOLIS_STATEROOT_STORE' ], casper_config ['SERENITY_GETTER_CODE' ])
181
- state .set_code (casper_config ['METROPOLIS_BLOCKHASH_STORE' ], casper_config ['SERENITY_GETTER_CODE' ])
207
+
208
+ header = state .prev_headers [0 ]
209
+ header .timestamp = timestamp
210
+ header .difficulty = 1
211
+
182
212
ct = get_casper_ct ()
183
- # Set genesis time, and initialize epoch number
184
- t = Transaction ( 0 , 0 , 10 ** 8 , casper_config [ 'CASPER_ADDR' ], 0 , ct . encode ( 'initialize' , [ timestamp , epoch_length , 0 , 4712388 ]) )
185
- apply_transaction ( state , t )
213
+ initialize ( state )
214
+ casper_contract_bootstrap ( state , timestamp = header . timestamp , gas_limit = header . gas_limit )
215
+
186
216
# Add validators
187
217
for i , (vcode , deposit_size , randao_commitment , address ) in enumerate (validators ):
188
- state .set_balance (utils .int_to_addr (1 ), deposit_size )
189
- t = Transaction (i , 0 , 10 ** 8 , casper_config ['CASPER_ADDR' ], deposit_size ,
190
- ct .encode ('deposit' , [vcode , randao_commitment , address ]))
191
- t ._sender = utils .int_to_addr (1 )
192
- success = apply_transaction (state , t )
193
- assert success
194
- for addr , data in alloc .items ():
195
- addr = utils .normalize_address (addr )
196
- assert len (addr ) == 20
197
- if 'wei' in data :
198
- state .set_balance (addr , utils .parse_as_int (data ['wei' ]))
199
- if 'balance' in data :
200
- state .set_balance (addr , utils .parse_as_int (data ['balance' ]))
201
- if 'code' in data :
202
- state .set_code (addr , utils .parse_as_bin (data ['code' ]))
203
- if 'nonce' in data :
204
- state .set_nonce (addr , utils .parse_as_int (data ['nonce' ]))
205
- if 'storage' in data :
206
- for k , v in data ['storage' ].items ():
207
- state .set_storage_data (addr , utils .parse_as_bin (k ), utils .parse_as_bin (v ))
218
+ validator_inject (state , vcode , deposit_size , randao_commitment , address , i , ct )
219
+
208
220
# Start the first epoch
209
- t = Transaction (0 , 0 , 10 ** 8 , casper_config ['CASPER_ADDR' ], 0 , ct .encode ('newEpoch' , [0 ]))
210
- t ._sender = casper_config ['CASPER_ADDR' ]
211
- apply_transaction (state , t )
221
+ casper_start_epoch (state )
222
+
212
223
assert call_casper (state , 'getEpoch' , []) == 0
213
224
assert call_casper (state , 'getTotalDeposits' , []) == sum ([d for a ,d ,r ,a in validators ])
225
+ state .set_storage_data (utils .normalize_address (state .config ['METROPOLIS_BLOCKHASH_STORE' ]),
226
+ state .block_number % state .config ['METROPOLIS_WRAPAROUND' ],
227
+ header .hash )
214
228
state .commit ()
229
+
215
230
return state
216
231
217
232
233
+ def casper_start_epoch (state ):
234
+ ct = get_casper_ct ()
235
+ t = Transaction (0 , 0 , 10 ** 8 , casper_config ['CASPER_ADDR' ], 0 , ct .encode ('newEpoch' , [0 ]))
236
+ t ._sender = casper_config ['CASPER_ADDR' ]
237
+ apply_transaction (state , t )
238
+
239
+
218
240
def get_dunkle_candidates (chain , state , scan_limit = 10 ):
219
241
blknumber = call_casper (state , 'getBlockNumber' )
220
242
anc = chain .get_block (chain .get_blockhash_by_number (blknumber - scan_limit ))
@@ -226,8 +248,8 @@ def get_dunkle_candidates(chain, state, scan_limit=10):
226
248
uncles = [x .header for x in potential_uncles if not call_casper (chain .state , 'isDunkleIncluded' , [x .header .hash ])]
227
249
dunkle_txs = []
228
250
ct = get_casper_ct ()
251
+ start_nonce = state .get_nonce (state .config ['METROPOLIS_ENTRY_POINT' ])
229
252
for i , u in enumerate (uncles [:4 ]):
230
- start_nonce = state .get_nonce (state .config ['METROPOLIS_ENTRY_POINT' ])
231
253
txdata = ct .encode ('includeDunkle' , [rlp .encode (u )])
232
254
dunkle_txs .append (Transaction (start_nonce + i , 0 , 650000 , chain .config ['CASPER_ADDR' ], 0 , txdata ))
233
255
return dunkle_txs
@@ -257,3 +279,20 @@ def casper_setup_block(chain, state=None, timestamp=None, coinbase='\x35'*20, ex
257
279
log_bc .info ('Block set up with number %d and prevhash %s, %d dunkles' %
258
280
(blk .header .number , utils .encode_hex (blk .header .prevhash ), len (blk .transactions )))
259
281
return blk
282
+
283
+ def casper_validate_header (state , header ):
284
+ output = apply_const_message (state ,
285
+ sender = state .config ['SYSTEM_ENTRY_POINT' ],
286
+ to = state .config ['SERENITY_HEADER_VERIFIER' ],
287
+ data = rlp .encode (header ))
288
+ if output is None :
289
+ raise ValueError ("Validation call failed with exception" )
290
+ elif output :
291
+ raise ValueError (output )
292
+
293
+ def casper_post_finalize_block (state , block ):
294
+ apply_message (state ,
295
+ sender = state .config ['SYSTEM_ENTRY_POINT' ],
296
+ to = state .config ['SERENITY_HEADER_POST_FINALIZER' ],
297
+ data = rlp .encode (block .header ))
298
+
0 commit comments