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

Commit e6ca4ee

Browse files
authored
Merge pull request #405 from ethereum/state_revamp_for_pyethapp
State revamp for pyethapp (WIP)
2 parents 9725a73 + 03cf231 commit e6ca4ee

11 files changed

+379
-197
lines changed

ethereum/block.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from ethereum.trie import Trie
88
from ethereum.securetrie import SecureTrie
99
from config import default_config
10-
from ethereum.ethpow import check_pow
1110
from ethereum.transactions import Transaction
1211
from db import BaseDB
1312
import sys
@@ -107,18 +106,6 @@ def mining_hash(self):
107106
def signing_hash(self):
108107
return utils.sha3(rlp.encode(self, BlockHeader.exclude(['extra_data'])))
109108

110-
def check_pow(self, nonce=None):
111-
"""Check if the proof-of-work of the block is valid.
112-
113-
:param nonce: if given the proof of work function will be evaluated
114-
with this nonce instead of the one already present in
115-
the header
116-
:returns: `True` or `False`
117-
"""
118-
# log.debug('checking pow', block=encode_hex(self.hash())[:8])
119-
return check_pow(self.number, self.mining_hash, self.mixhash, nonce or self.nonce,
120-
self.difficulty)
121-
122109
def to_dict(self):
123110
"""Serialize the header to a readable dictionary."""
124111
d = {}
@@ -191,6 +178,15 @@ def __getattribute__(self, name):
191178
except AttributeError:
192179
return getattr(self.header, name)
193180

181+
# TODO: remove chain_difficulty mock
182+
def chain_difficulty(self):
183+
return self.header.number + 1
184+
185+
@property
186+
def transaction_count(self):
187+
return len(self.transactions)
188+
189+
194190
BLANK_UNCLES_HASH = sha3(rlp.encode([]))
195191

196192

ethereum/block_creation.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from ethereum.state_transition import check_gaslimit, initialize, \
55
validate_uncles, pre_seal_finalize, mk_receipt_sha, mk_transaction_sha, \
66
apply_transaction
7+
from ethereum.consensus_strategy import get_consensus_strategy
78
from ethereum.exceptions import InsufficientBalance, BlockGasLimitReached, \
89
InsufficientStartGas, InvalidNonce, UnsignedTransaction
910
from ethereum.utils import sha3
@@ -52,12 +53,9 @@ def make_head_candidate(chain, txqueue,
5253
temp_state = State.from_snapshot(chain.state.to_snapshot(root_only=True), chain.env)
5354
else:
5455
temp_state = chain.mk_poststate_of_blockhash(parent.hash)
55-
if chain.config['HEADER_STRATEGY'] == 'ethereum1':
56-
block = ethpow_utils.ethereum1_setup_block(chain, temp_state, timestamp, coinbase, extra_data)
57-
elif chain.config['HEADER_STRATEGY'] == 'casper':
58-
block = casper_utils.casper_setup_block(chain, temp_state, timestamp, coinbase, extra_data)
59-
else:
60-
raise Exception("Header building strategy %s not supported" % chain.config['HEADER_STRATEGY'])
56+
57+
cs = get_consensus_strategy(chain.env.config)
58+
block = cs.block_setup(chain, temp_state, timestamp, coinbase, extra_data)
6159
add_transactions(temp_state, block, txqueue, min_gasprice)
6260
pre_seal(temp_state, block)
6361
assert validate_uncles(temp_state, block)

ethereum/casper_contract.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@
5959
# Event when a dunkle is added
6060
event DunkleAdded(hash:bytes32)
6161

62+
BLOCK_TIME = 3
63+
SKIP_TIME = 6
64+
6265
# 1 part-per-billion per block = ~1.05% annual interest assuming 3s blocks
6366
# 1 ppb per second = 3.20% annual interest
6467
BLOCK_MAKING_PPB = 10
@@ -208,7 +211,7 @@ def const getValidator(skips):
208211

209212

210213
def const getMinTimestamp(skips):
211-
return(self.genesisTimestamp + block.number * 3 + (self.totalSkips + skips) * 6)
214+
return(self.genesisTimestamp + block.number * BLOCK_TIME + (self.totalSkips + skips) * SKIP_TIME)
212215

213216

214217
def const getRandao(vchash:bytes32):

ethereum/casper_utils.py

Lines changed: 101 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,37 @@
1+
import os
2+
import copy
3+
import rlp
14
from ethereum import utils
25
from ethereum.utils import sha3, ecsign, encode_int32
3-
from ethereum.state import State
46
from ethereum.transactions import Transaction
57
from ethereum.config import Env, default_config
68
from ethereum.state_transition import apply_transaction, apply_const_message, \
7-
initialize
9+
apply_message, initialize
810
from ethereum.block import Block, BlockHeader
11+
from ethereum.state import State
912
from ethereum.parse_genesis_declaration import mk_basic_state
1013
from ethereum import vm
1114
from ethereum import abi
12-
import copy
13-
import os
14-
import rlp
1515
from ethereum.slogging import get_logger
16+
1617
log_bc = get_logger('eth.block_creation')
1718
mydir = os.path.split(__file__)[0]
1819
casper_path = os.path.join(mydir, 'casper_contract.py')
1920
rlp_decoder_path = os.path.join(mydir, 'rlp_decoder_contract.py')
2021
hash_without_ed_path = os.path.join(mydir, 'hash_without_ed_contract.py')
2122
finalizer_path = os.path.join(mydir, 'finalizer_contract.py')
2223

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+
2335
def get_casper_code():
2436
import serpent
2537
return get_contract_code(serpent.compile(open(casper_path).read()))
@@ -36,29 +48,30 @@ def get_finalizer_code():
3648
import serpent
3749
return get_contract_code(serpent.compile(open(finalizer_path).read()))
3850

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
4751

4852
# The Casper-specific config declaration
4953
casper_config = copy.deepcopy(default_config)
5054
casper_config['HOMESTEAD_FORK_BLKNUM'] = 0
5155
casper_config['METROPOLIS_FORK_BLKNUM'] = 0
5256
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']
5658
casper_config['CASPER_ADDR'] = utils.int_to_addr(255)
5759
casper_config['RLP_DECODER_ADDR'] = utils.int_to_addr(253)
5860
casper_config['HASH_WITHOUT_BLOOM_ADDR'] = utils.int_to_addr(252)
5961
casper_config['MAX_UNCLE_DEPTH'] = 0
6062
casper_config['PREV_HEADER_DEPTH'] = 1
6163

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+
6275
# RandaoManager object to be used by validators to provide randaos
6376
# when signing their block
6477
RANDAO_SAVE_INTERVAL = 100
@@ -88,16 +101,6 @@ def get_parent(self, val):
88101
val = utils.sha3(val)
89102
raise Exception("Randao parent not found")
90103

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-
101104
# Create the validation code for a given address
102105
def generate_validation_code(addr):
103106
import serpent
@@ -163,58 +166,77 @@ def make_withdrawal_signature(key):
163166
v, r, s = ecsign(h, key)
164167
return encode_int32(v) + encode_int32(r) + encode_int32(s)
165168

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+
166199
# Create a casper genesis from given parameters
167200
# Validators: (vcode, deposit_size, randao_commitment)
168201
# Alloc: state declaration
169202
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))
171204
state.gas_limit = 10**8 * (len(validators) + 1)
172-
state.prev_headers[0].timestamp = timestamp
173-
state.prev_headers[0].difficulty = 1
174205
state.timestamp = timestamp
175206
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+
182212
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+
186216
# Add validators
187217
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+
208220
# 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+
212223
assert call_casper(state, 'getEpoch', []) == 0
213224
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)
214228
state.commit()
229+
215230
return state
216231

217232

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+
218240
def get_dunkle_candidates(chain, state, scan_limit=10):
219241
blknumber = call_casper(state, 'getBlockNumber')
220242
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):
226248
uncles = [x.header for x in potential_uncles if not call_casper(chain.state, 'isDunkleIncluded', [x.header.hash])]
227249
dunkle_txs = []
228250
ct = get_casper_ct()
251+
start_nonce = state.get_nonce(state.config['METROPOLIS_ENTRY_POINT'])
229252
for i, u in enumerate(uncles[:4]):
230-
start_nonce = state.get_nonce(state.config['METROPOLIS_ENTRY_POINT'])
231253
txdata = ct.encode('includeDunkle', [rlp.encode(u)])
232254
dunkle_txs.append(Transaction(start_nonce + i, 0, 650000, chain.config['CASPER_ADDR'], 0, txdata))
233255
return dunkle_txs
@@ -257,3 +279,20 @@ def casper_setup_block(chain, state=None, timestamp=None, coinbase='\x35'*20, ex
257279
log_bc.info('Block set up with number %d and prevhash %s, %d dunkles' %
258280
(blk.header.number, utils.encode_hex(blk.header.prevhash), len(blk.transactions)))
259281
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

Comments
 (0)