backport 839 into dev

This commit is contained in:
Danny Ryan 2019-03-25 11:25:33 -06:00
parent 40aa82beb7
commit fceebeec4e
No known key found for this signature in database
GPG Key ID: 2765A792E42CE07A
9 changed files with 101 additions and 53 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@
/.pytest_cache /.pytest_cache
build/ build/
output/

View File

@ -692,7 +692,8 @@ def get_temporary_block_header(block: BeaconBlock) -> BeaconBlockHeader:
previous_block_root=block.previous_block_root, previous_block_root=block.previous_block_root,
state_root=ZERO_HASH, state_root=ZERO_HASH,
block_body_root=hash_tree_root(block.body), block_body_root=hash_tree_root(block.body),
signature=block.signature, # signed_root(block) is used for block id purposes so signature is a stub
signature=EMPTY_SIGNATURE,
) )
``` ```
@ -1749,7 +1750,7 @@ def cache_state(state: BeaconState) -> None:
state.latest_block_header.state_root = previous_slot_state_root state.latest_block_header.state_root = previous_slot_state_root
# store latest known block for previous slot # store latest known block for previous slot
state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = hash_tree_root(state.latest_block_header) state.latest_block_roots[state.slot % SLOTS_PER_HISTORICAL_ROOT] = signed_root(state.latest_block_header)
``` ```
### Per-epoch processing ### Per-epoch processing
@ -2198,8 +2199,8 @@ def update_registry_and_shuffling_data(state: BeaconState) -> None:
state.current_shuffling_epoch = next_epoch state.current_shuffling_epoch = next_epoch
state.current_shuffling_start_shard = ( state.current_shuffling_start_shard = (
state.current_shuffling_start_shard + state.current_shuffling_start_shard +
get_current_epoch_committee_count(state) % SHARD_COUNT get_current_epoch_committee_count(state)
) ) % SHARD_COUNT
state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch) state.current_shuffling_seed = generate_seed(state, state.current_shuffling_epoch)
else: else:
# If processing at least one crosslink keeps failing, then reshuffle every power of two, # If processing at least one crosslink keeps failing, then reshuffle every power of two,
@ -2315,7 +2316,7 @@ def process_block_header(state: BeaconState, block: BeaconBlock) -> None:
# Verify that the slots match # Verify that the slots match
assert block.slot == state.slot assert block.slot == state.slot
# Verify that the parent matches # Verify that the parent matches
assert block.previous_block_root == hash_tree_root(state.latest_block_header) assert block.previous_block_root == signed_root(state.latest_block_header)
# Save current block as the new latest block # Save current block as the new latest block
state.latest_block_header = get_temporary_block_header(block) state.latest_block_header = get_temporary_block_header(block)
# Verify proposer is not slashed # Verify proposer is not slashed

0
tests/phase0/__init__.py Normal file
View File

View File

@ -4,12 +4,14 @@ import pytest
import build.phase0.spec as spec import build.phase0.spec as spec
from build.phase0.spec import ( from build.phase0.spec import (
Deposit,
get_balance, get_balance,
ZERO_HASH,
process_deposit, process_deposit,
) )
from tests.phase0.helpers import ( from tests.phase0.helpers import (
build_deposit, build_deposit,
privkeys,
pubkeys,
) )
@ -17,8 +19,10 @@ from tests.phase0.helpers import (
pytestmark = pytest.mark.voluntary_exits pytestmark = pytest.mark.voluntary_exits
def test_success(state, deposit_data_leaves, pubkeys, privkeys): def test_success(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
# fill previous deposits with zero-hash
deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry)
index = len(deposit_data_leaves) index = len(deposit_data_leaves)
pubkey = pubkeys[index] pubkey = pubkeys[index]
@ -47,8 +51,9 @@ def test_success(state, deposit_data_leaves, pubkeys, privkeys):
return pre_state, deposit, post_state return pre_state, deposit, post_state
def test_success_top_up(state, deposit_data_leaves, pubkeys, privkeys): def test_success_top_up(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry)
validator_index = 0 validator_index = 0
amount = spec.MAX_DEPOSIT_AMOUNT // 4 amount = spec.MAX_DEPOSIT_AMOUNT // 4
@ -78,8 +83,9 @@ def test_success_top_up(state, deposit_data_leaves, pubkeys, privkeys):
return pre_state, deposit, post_state return pre_state, deposit, post_state
def test_wrong_index(state, deposit_data_leaves, pubkeys, privkeys): def test_wrong_index(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry)
index = len(deposit_data_leaves) index = len(deposit_data_leaves)
pubkey = pubkeys[index] pubkey = pubkeys[index]
@ -106,8 +112,9 @@ def test_wrong_index(state, deposit_data_leaves, pubkeys, privkeys):
return pre_state, deposit, None return pre_state, deposit, None
def test_bad_merkle_proof(state, deposit_data_leaves, pubkeys, privkeys): def test_bad_merkle_proof(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry)
index = len(deposit_data_leaves) index = len(deposit_data_leaves)
pubkey = pubkeys[index] pubkey = pubkeys[index]

View File

@ -10,6 +10,7 @@ from build.phase0.spec import (
) )
from tests.phase0.helpers import ( from tests.phase0.helpers import (
build_voluntary_exit, build_voluntary_exit,
pubkey_to_privkey,
) )
@ -17,7 +18,7 @@ from tests.phase0.helpers import (
pytestmark = pytest.mark.voluntary_exits pytestmark = pytest.mark.voluntary_exits
def test_success(state, pub_to_priv): def test_success(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
# #
# setup pre_state # setup pre_state
@ -30,7 +31,7 @@ def test_success(state, pub_to_priv):
# #
current_epoch = get_current_epoch(pre_state) current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pub_to_priv[pre_state.validator_registry[validator_index].pubkey] privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
voluntary_exit = build_voluntary_exit( voluntary_exit = build_voluntary_exit(
pre_state, pre_state,
@ -52,11 +53,11 @@ def test_success(state, pub_to_priv):
return pre_state, voluntary_exit, post_state return pre_state, voluntary_exit, post_state
def test_validator_not_active(state, pub_to_priv): def test_validator_not_active(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
current_epoch = get_current_epoch(pre_state) current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pub_to_priv[pre_state.validator_registry[validator_index].pubkey] privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
# #
# setup pre_state # setup pre_state
@ -79,7 +80,7 @@ def test_validator_not_active(state, pub_to_priv):
return pre_state, voluntary_exit, None return pre_state, voluntary_exit, None
def test_validator_already_exited(state, pub_to_priv): def test_validator_already_exited(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
# #
# setup pre_state # setup pre_state
@ -89,7 +90,7 @@ def test_validator_already_exited(state, pub_to_priv):
current_epoch = get_current_epoch(pre_state) current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pub_to_priv[pre_state.validator_registry[validator_index].pubkey] privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
# but validator already has exited # but validator already has exited
pre_state.validator_registry[validator_index].exit_epoch = current_epoch + 2 pre_state.validator_registry[validator_index].exit_epoch = current_epoch + 2
@ -110,7 +111,7 @@ def test_validator_already_exited(state, pub_to_priv):
return pre_state, voluntary_exit, None return pre_state, voluntary_exit, None
def test_validator_already_initiated_exit(state, pub_to_priv): def test_validator_already_initiated_exit(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
# #
# setup pre_state # setup pre_state
@ -120,7 +121,7 @@ def test_validator_already_initiated_exit(state, pub_to_priv):
current_epoch = get_current_epoch(pre_state) current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pub_to_priv[pre_state.validator_registry[validator_index].pubkey] privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
# but validator already has initiated exit # but validator already has initiated exit
pre_state.validator_registry[validator_index].initiated_exit = True pre_state.validator_registry[validator_index].initiated_exit = True
@ -141,14 +142,14 @@ def test_validator_already_initiated_exit(state, pub_to_priv):
return pre_state, voluntary_exit, None return pre_state, voluntary_exit, None
def test_validator_not_active_long_enough(state, pub_to_priv): def test_validator_not_active_long_enough(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
# #
# setup pre_state # setup pre_state
# #
current_epoch = get_current_epoch(pre_state) current_epoch = get_current_epoch(pre_state)
validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0] validator_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[0]
privkey = pub_to_priv[pre_state.validator_registry[validator_index].pubkey] privkey = pubkey_to_privkey[pre_state.validator_registry[validator_index].pubkey]
# but validator already has initiated exit # but validator already has initiated exit
pre_state.validator_registry[validator_index].initiated_exit = True pre_state.validator_registry[validator_index].initiated_exit = True

View File

@ -3,9 +3,6 @@ import pytest
from build.phase0 import spec from build.phase0 import spec
from tests.phase0.helpers import ( from tests.phase0.helpers import (
privkeys_list,
pubkeys_list,
pubkey_to_privkey,
create_genesis_state, create_genesis_state,
) )
@ -25,21 +22,6 @@ MINIMAL_CONFIG = {
} }
@pytest.fixture
def privkeys():
return privkeys_list
@pytest.fixture
def pubkeys():
return pubkeys_list
@pytest.fixture
def pub_to_priv():
return pubkey_to_privkey
def overwrite_spec_config(config): def overwrite_spec_config(config):
for field in config: for field in config:
setattr(spec, field, config[field]) setattr(spec, field, config[field])

View File

@ -35,18 +35,20 @@ from build.phase0.utils.merkle_minimal import (
) )
privkeys_list = [i + 1 for i in range(1000)] privkeys = [i + 1 for i in range(1000)]
pubkeys_list = [bls.privtopub(privkey) for privkey in privkeys_list] pubkeys = [bls.privtopub(privkey) for privkey in privkeys]
pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys_list, pubkeys_list)} pubkey_to_privkey = {pubkey: privkey for privkey, pubkey in zip(privkeys, pubkeys)}
def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves): def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves=None):
if not deposit_data_leaves:
deposit_data_leaves = []
deposit_timestamp = 0 deposit_timestamp = 0
proof_of_possession = b'\x33' * 96 proof_of_possession = b'\x33' * 96
deposit_data_list = [] deposit_data_list = []
for i in range(num_validators): for i in range(num_validators):
pubkey = pubkeys_list[i] pubkey = pubkeys[i]
deposit_data = DepositData( deposit_data = DepositData(
amount=spec.MAX_DEPOSIT_AMOUNT, amount=spec.MAX_DEPOSIT_AMOUNT,
timestamp=deposit_timestamp, timestamp=deposit_timestamp,
@ -75,7 +77,7 @@ def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves):
return genesis_validator_deposits, root return genesis_validator_deposits, root
def create_genesis_state(num_validators, deposit_data_leaves): def create_genesis_state(num_validators, deposit_data_leaves=None):
initial_deposits, deposit_root = create_mock_genesis_validator_deposits( initial_deposits, deposit_root = create_mock_genesis_validator_deposits(
num_validators, num_validators,
deposit_data_leaves, deposit_data_leaves,
@ -105,7 +107,7 @@ def build_empty_block_for_next_slot(state):
previous_block_header = deepcopy(state.latest_block_header) previous_block_header = deepcopy(state.latest_block_header)
if previous_block_header.state_root == spec.ZERO_HASH: if previous_block_header.state_root == spec.ZERO_HASH:
previous_block_header.state_root = state.hash_tree_root() previous_block_header.state_root = state.hash_tree_root()
empty_block.previous_block_root = previous_block_header.hash_tree_root() empty_block.previous_block_root = signed_root(previous_block_header)
return empty_block return empty_block

View File

@ -47,6 +47,8 @@ from tests.phase0.helpers import (
build_empty_block_for_next_slot, build_empty_block_for_next_slot,
force_registry_change_at_next_epoch, force_registry_change_at_next_epoch,
get_valid_proposer_slashing, get_valid_proposer_slashing,
privkeys,
pubkeys,
) )
@ -116,7 +118,7 @@ def test_empty_epoch_transition_not_finalizing(state):
return state, [block], test_state return state, [block], test_state
def test_proposer_slashing(state, pubkeys, privkeys): def test_proposer_slashing(state):
test_state = deepcopy(state) test_state = deepcopy(state)
proposer_slashing = get_valid_proposer_slashing(state) proposer_slashing = get_valid_proposer_slashing(state)
validator_index = proposer_slashing.proposer_index validator_index = proposer_slashing.proposer_index
@ -142,9 +144,9 @@ def test_proposer_slashing(state, pubkeys, privkeys):
return state, [block], test_state return state, [block], test_state
def test_deposit_in_block(state, deposit_data_leaves, pubkeys, privkeys): def test_deposit_in_block(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
test_deposit_data_leaves = deepcopy(deposit_data_leaves) test_deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry)
index = len(test_deposit_data_leaves) index = len(test_deposit_data_leaves)
pubkey = pubkeys[index] pubkey = pubkeys[index]
@ -179,9 +181,9 @@ def test_deposit_in_block(state, deposit_data_leaves, pubkeys, privkeys):
return pre_state, [block], post_state return pre_state, [block], post_state
def test_deposit_top_up(state, pubkeys, privkeys, deposit_data_leaves): def test_deposit_top_up(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
test_deposit_data_leaves = deepcopy(deposit_data_leaves) test_deposit_data_leaves = [ZERO_HASH] * len(pre_state.validator_registry)
validator_index = 0 validator_index = 0
amount = spec.MAX_DEPOSIT_AMOUNT // 4 amount = spec.MAX_DEPOSIT_AMOUNT // 4
@ -218,7 +220,7 @@ def test_deposit_top_up(state, pubkeys, privkeys, deposit_data_leaves):
return pre_state, [block], post_state return pre_state, [block], post_state
def test_attestation(state, pubkeys, privkeys): def test_attestation(state):
test_state = deepcopy(state) test_state = deepcopy(state)
slot = state.slot slot = state.slot
shard = state.current_shuffling_start_shard shard = state.current_shuffling_start_shard
@ -287,7 +289,7 @@ def test_attestation(state, pubkeys, privkeys):
return state, [attestation_block, epoch_block], test_state return state, [attestation_block, epoch_block], test_state
def test_voluntary_exit(state, pubkeys, privkeys): def test_voluntary_exit(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
validator_index = get_active_validator_indices( validator_index = get_active_validator_indices(
pre_state.validator_registry, pre_state.validator_registry,
@ -375,7 +377,7 @@ def test_no_exit_churn_too_long_since_change(state):
return pre_state, [block], post_state return pre_state, [block], post_state
def test_transfer(state, pubkeys, privkeys): def test_transfer(state):
pre_state = deepcopy(state) pre_state = deepcopy(state)
current_epoch = get_current_epoch(pre_state) current_epoch = get_current_epoch(pre_state)
sender_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[-1] sender_index = get_active_validator_indices(pre_state.validator_registry, current_epoch)[-1]

52
utils/phase0/jsonize.py Normal file
View File

@ -0,0 +1,52 @@
from .minimal_ssz import hash_tree_root
def jsonize(value, typ, include_hash_tree_roots=False):
if isinstance(typ, str) and typ[:4] == 'uint':
return value
elif typ == 'bool':
assert value in (True, False)
return value
elif isinstance(typ, list):
return [jsonize(element, typ[0], include_hash_tree_roots) for element in value]
elif isinstance(typ, str) and typ[:4] == 'byte':
return '0x' + value.hex()
elif hasattr(typ, 'fields'):
ret = {}
for field, subtype in typ.fields.items():
ret[field] = jsonize(getattr(value, field), subtype, include_hash_tree_roots)
if include_hash_tree_roots:
ret[field + "_hash_tree_root"] = '0x' + hash_tree_root(getattr(value, field), subtype).hex()
if include_hash_tree_roots:
ret["hash_tree_root"] = '0x' + hash_tree_root(value, typ).hex()
return ret
else:
print(value, typ)
raise Exception("Type not recognized")
def dejsonize(json, typ):
if isinstance(typ, str) and typ[:4] == 'uint':
return json
elif typ == 'bool':
assert json in (True, False)
return json
elif isinstance(typ, list):
return [dejsonize(element, typ[0]) for element in json]
elif isinstance(typ, str) and typ[:4] == 'byte':
return bytes.fromhex(json[2:])
elif hasattr(typ, 'fields'):
temp = {}
for field, subtype in typ.fields.items():
temp[field] = dejsonize(json[field], subtype)
if field + "_hash_tree_root" in json:
assert(json[field + "_hash_tree_root"][2:] ==
hash_tree_root(temp[field], subtype).hex())
ret = typ(**temp)
if "hash_tree_root" in json:
assert(json["hash_tree_root"][2:] ==
hash_tree_root(ret, typ).hex())
return ret
else:
print(json, typ)
raise Exception("Type not recognized")