signatures in tests, most block-ops updated, still many to go

This commit is contained in:
protolambda 2019-05-11 21:31:37 +02:00
parent 680017f69c
commit 4f3f68bc12
No known key found for this signature in database
GPG Key ID: EC89FDBB2B4C7623
9 changed files with 206 additions and 108 deletions

View File

@ -3,17 +3,18 @@ from copy import deepcopy
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
state_transition_to,
)
from eth2spec.phase0.spec import (
get_current_epoch,
process_attestation
)
from eth2spec.test.helpers import (
build_empty_block_for_next_slot,
get_valid_attestation,
apply_empty_block,
next_epoch,
next_slot,
make_attestation_signature,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
@ -65,9 +66,8 @@ def test_success(state):
@spec_state_test
def test_success_previous_epoch(state):
attestation = get_valid_attestation(state)
block = build_empty_block_for_next_slot(state)
block.slot = state.slot + spec.SLOTS_PER_EPOCH
state_transition(state, block)
next_epoch(state)
apply_empty_block(state)
yield from run_attestation_processing(state, attestation)
@ -83,10 +83,9 @@ def test_before_inclusion_delay(state):
@spec_state_test
def test_after_epoch_slots(state):
attestation = get_valid_attestation(state)
block = build_empty_block_for_next_slot(state)
# increment past latest inclusion slot
block.slot = state.slot + spec.SLOTS_PER_EPOCH + 1
state_transition(state, block)
state_transition_to(state, state.slot + spec.SLOTS_PER_EPOCH + 1)
apply_empty_block(state)
yield from run_attestation_processing(state, attestation, False)
@ -105,6 +104,9 @@ def test_old_source_epoch(state):
# Now go beyond that, it will be invalid
attestation.data.source_epoch -= 1
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -115,6 +117,9 @@ def test_wrong_shard(state):
attestation.data.shard += 1
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -125,6 +130,9 @@ def test_new_source_epoch(state):
attestation.data.source_epoch += 1
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -135,6 +143,9 @@ def test_source_root_is_target_root(state):
attestation.data.source_root = attestation.data.target_root
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -159,6 +170,9 @@ def test_invalid_current_source_root(state):
# Make attestation source root invalid: should be previous justified, not current one
attestation.data.source_root = state.current_justified_root
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -169,6 +183,9 @@ def test_bad_source_root(state):
attestation.data.source_root = b'\x42' * 32
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@ -179,15 +196,21 @@ def test_non_zero_crosslink_data_root(state):
attestation.data.crosslink_data_root = b'\x42' * 32
# Re do signature
make_attestation_signature(state, attestation)
yield from run_attestation_processing(state, attestation, False)
@spec_state_test
def test_bad_previous_crosslink(state):
next_epoch(state)
apply_empty_block(state)
attestation = get_valid_attestation(state)
for _ in range(spec.MIN_ATTESTATION_INCLUSION_DELAY):
next_slot(state)
apply_empty_block(state)
state.current_crosslinks[attestation.data.shard].epoch += 10

View File

@ -3,14 +3,15 @@ from eth2spec.phase0.spec import (
get_beacon_proposer_index,
process_attester_slashing,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.helpers import (
get_balance,
get_valid_attester_slashing,
next_epoch,
apply_empty_block,
make_indexed_attestation_signature
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
def run_attester_slashing_processing(state, attester_slashing, valid=True):
"""
@ -47,14 +48,14 @@ def run_attester_slashing_processing(state, attester_slashing, valid=True):
# lost whistleblower reward
assert (
get_balance(state, slashed_index) <
pre_slashed_balance
get_balance(state, slashed_index) <
pre_slashed_balance
)
# gained whistleblower reward
assert (
get_balance(state, proposer_index) >
pre_proposer_balance
get_balance(state, proposer_index) >
pre_proposer_balance
)
yield 'post', state
@ -70,6 +71,8 @@ def test_success_double(state):
@spec_state_test
def test_success_surround(state):
next_epoch(state)
apply_empty_block(state)
state.current_justified_epoch += 1
attester_slashing = get_valid_attester_slashing(state)
@ -77,6 +80,9 @@ def test_success_surround(state):
attester_slashing.attestation_1.data.source_epoch = attester_slashing.attestation_2.data.source_epoch - 1
attester_slashing.attestation_1.data.target_epoch = attester_slashing.attestation_2.data.target_epoch + 1
# correct the signature of attestation 1
make_indexed_attestation_signature(state, attester_slashing.attestation_1)
yield from run_attester_slashing_processing(state, attester_slashing)

View File

@ -6,13 +6,13 @@ from eth2spec.phase0.spec import (
advance_slot,
process_block_header,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.helpers import (
build_empty_block_for_next_slot,
next_slot,
make_block_signature
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
def prepare_state_for_header_processing(state):
cache_state(state)
@ -43,7 +43,7 @@ def run_block_header_processing(state, block, valid=True):
@spec_state_test
def test_success(state):
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=True)
yield from run_block_header_processing(state, block)
@ -59,6 +59,7 @@ def test_invalid_slot(state):
def test_invalid_previous_block_root(state):
block = build_empty_block_for_next_slot(state)
block.previous_block_root = b'\12' * 32 # invalid prev root
make_block_signature(state, block)
yield from run_block_header_processing(state, block, valid=False)
@ -73,6 +74,6 @@ def test_proposer_slashed(state):
# set proposer to slashed
state.validator_registry[proposer_index].slashed = True
block = build_empty_block_for_next_slot(state)
block = build_empty_block_for_next_slot(state, signed=True)
yield from run_block_header_processing(state, block, valid=False)

View File

@ -1,18 +1,17 @@
import eth2spec.phase0.spec as spec
from eth2spec.phase0.spec import (
get_active_validator_indices,
get_beacon_proposer_index,
get_current_epoch,
process_transfer,
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
from eth2spec.test.helpers import (
get_valid_transfer,
next_epoch,
apply_empty_block
)
from eth2spec.test.context import spec_state_test, expect_assertion_error
def run_transfer_processing(state, transfer, valid=True):
"""
@ -58,6 +57,7 @@ def test_success_non_activated(state):
@spec_state_test
def test_success_withdrawable(state):
next_epoch(state)
apply_empty_block(state)
transfer = get_valid_transfer(state)
@ -97,7 +97,7 @@ def test_active_but_transfer_past_effective_balance(state):
@spec_state_test
def test_incorrect_slot(state):
transfer = get_valid_transfer(state, slot=state.slot+1)
transfer = get_valid_transfer(state, slot=state.slot + 1)
# un-activate so validator can transfer
state.validator_registry[transfer.sender].activation_epoch = spec.FAR_FUTURE_EPOCH

View File

@ -5,7 +5,7 @@ from .helpers import create_genesis_state
from .utils import spectest, with_args
# Provides a genesis state as first argument to the function decorated with this
with_state = with_args(lambda: [create_genesis_state(spec.SLOTS_PER_EPOCH * 8, list())])
with_state = with_args(lambda: [create_genesis_state(spec.SLOTS_PER_EPOCH * 8)])
# shorthand for decorating @with_state @spectest()

View File

@ -1,15 +1,15 @@
from copy import deepcopy
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.phase0.spec import (
cache_state,
get_crosslink_deltas,
process_crosslinks,
)
from eth2spec.phase0.state_transition import (
state_transition,
)
from eth2spec.test.context import spec_state_test
from eth2spec.test.helpers import (
add_attestation_to_state,
build_empty_block_for_next_slot,
@ -18,8 +18,8 @@ from eth2spec.test.helpers import (
get_valid_attestation,
next_epoch,
next_slot,
apply_empty_block
)
from eth2spec.test.context import spec_state_test
def run_process_crosslinks(state, valid=True):
@ -115,6 +115,8 @@ def test_double_late_crosslink(state):
if attestation_2.data.shard == attestation_1.data.shard:
break
next_slot(state)
apply_empty_block(state)
fill_aggregate_attestation(state, attestation_2)
# add attestation_2 in the next epoch after attestation_1 has
@ -126,7 +128,7 @@ def test_double_late_crosslink(state):
assert len(state.current_epoch_attestations) == 0
crosslink_deltas = get_crosslink_deltas(state)
yield from run_process_crosslinks(state)
shard = attestation_2.data.shard

View File

@ -2,20 +2,20 @@ from copy import deepcopy
from py_ecc import bls
from eth2spec.phase0.state_transition import (
state_transition,
)
from typing import List
import eth2spec.phase0.spec as spec
from eth2spec.utils.minimal_ssz import signing_root
from eth2spec.phase0.spec import (
# constants
ZERO_HASH,
# SSZ
Attestation,
IndexedAttestation,
AttestationData,
AttestationDataAndCustodyBit,
AttesterSlashing,
BeaconBlock,
BeaconState,
BeaconBlockHeader,
Deposit,
DepositData,
@ -33,7 +33,6 @@ from eth2spec.phase0.spec import (
get_current_epoch,
get_domain,
get_epoch_start_slot,
get_genesis_beacon_state,
get_previous_epoch,
get_shard_delta,
hash_tree_root,
@ -41,12 +40,15 @@ from eth2spec.phase0.spec import (
verify_merkle_branch,
hash,
)
from eth2spec.phase0.state_transition import (
state_transition, state_transition_to
)
from eth2spec.utils.merkle_minimal import (
calc_merkle_tree_from_leaves,
get_merkle_proof,
get_merkle_root,
)
from eth2spec.utils.minimal_ssz import signing_root
privkeys = [i + 1 for i in range(1024)]
pubkeys = [bls.privtopub(privkey) for privkey in privkeys]
@ -64,72 +66,109 @@ def set_bitfield_bit(bitfield, i):
byte_index = i // 8
bit_index = i % 8
return (
bitfield[:byte_index] +
bytes([bitfield[byte_index] | (1 << bit_index)]) +
bitfield[byte_index+1:]
bitfield[:byte_index] +
bytes([bitfield[byte_index] | (1 << bit_index)]) +
bitfield[byte_index + 1:]
)
def create_mock_genesis_validator_deposits(num_validators, deposit_data_leaves=None):
if not deposit_data_leaves:
deposit_data_leaves = []
signature = b'\x33' * 96
deposit_data_list = []
for i in range(num_validators):
pubkey = pubkeys[i]
deposit_data = DepositData(
pubkey=pubkey,
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials=spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(pubkey)[1:],
amount=spec.MAX_EFFECTIVE_BALANCE,
signature=signature,
)
item = deposit_data.hash_tree_root()
deposit_data_leaves.append(item)
tree = calc_merkle_tree_from_leaves(tuple(deposit_data_leaves))
root = get_merkle_root((tuple(deposit_data_leaves)))
proof = list(get_merkle_proof(tree, item_index=i))
assert verify_merkle_branch(item, proof, spec.DEPOSIT_CONTRACT_TREE_DEPTH, i, root)
deposit_data_list.append(deposit_data)
genesis_validator_deposits = []
for i in range(num_validators):
genesis_validator_deposits.append(Deposit(
proof=list(get_merkle_proof(tree, item_index=i)),
index=i,
data=deposit_data_list[i]
))
return genesis_validator_deposits, root
def create_genesis_state(num_validators, deposit_data_leaves=None):
initial_deposits, deposit_root = create_mock_genesis_validator_deposits(
num_validators,
deposit_data_leaves,
def build_mock_validator(i: int, balance: int):
pubkey = pubkeys[i]
# insecurely use pubkey as withdrawal key as well
withdrawal_credentials = spec.BLS_WITHDRAWAL_PREFIX_BYTE + hash(pubkey)[1:]
return spec.Validator(
pubkey=pubkeys[i],
withdrawal_credentials=withdrawal_credentials,
activation_eligibility_epoch=spec.FAR_FUTURE_EPOCH,
activation_epoch=spec.FAR_FUTURE_EPOCH,
exit_epoch=spec.FAR_FUTURE_EPOCH,
withdrawable_epoch=spec.FAR_FUTURE_EPOCH,
effective_balance=min(balance - balance % spec.EFFECTIVE_BALANCE_INCREMENT, spec.MAX_EFFECTIVE_BALANCE)
)
return get_genesis_beacon_state(
initial_deposits,
def create_genesis_state(num_validators):
deposit_root = b'\x42' * 32
state = spec.BeaconState(
genesis_time=0,
genesis_eth1_data=Eth1Data(
deposit_index=num_validators,
latest_eth1_data=Eth1Data(
deposit_root=deposit_root,
deposit_count=len(initial_deposits),
deposit_count=num_validators,
block_hash=spec.ZERO_HASH,
),
))
# We "hack" in the initial validators,
# as it is much faster than creating and processing genesis deposits for every single test case.
state.balances = [spec.MAX_EFFECTIVE_BALANCE] * num_validators
state.validator_registry = [build_mock_validator(i, state.balances[i]) for i in range(num_validators)]
# Process genesis activations
for validator in state.validator_registry:
if validator.effective_balance >= spec.MAX_EFFECTIVE_BALANCE:
validator.activation_eligibility_epoch = spec.GENESIS_EPOCH
validator.activation_epoch = spec.GENESIS_EPOCH
genesis_active_index_root = hash_tree_root(get_active_validator_indices(state, spec.GENESIS_EPOCH))
for index in range(spec.LATEST_ACTIVE_INDEX_ROOTS_LENGTH):
state.latest_active_index_roots[index] = genesis_active_index_root
return state
def make_block_signature(state, block):
assert block.slot == state.slot or block.slot == state.slot + 1
if block.slot == state.slot:
proposer_index = spec.get_beacon_proposer_index(state)
else:
# use stub state to get proposer index of next slot
stub_state = deepcopy(state)
next_slot(stub_state)
proposer_index = spec.get_beacon_proposer_index(stub_state)
privkey = privkeys[proposer_index]
block.body.randao_reveal = bls.sign(
privkey=privkey,
message_hash=hash_tree_root(slot_to_epoch(block.slot)),
domain=get_domain(
state,
message_epoch=slot_to_epoch(block.slot),
domain_type=spec.DOMAIN_RANDAO,
)
)
block.signature = bls.sign(
message_hash=signing_root(block),
privkey=privkey,
domain=get_domain(
state,
spec.DOMAIN_BEACON_PROPOSER,
slot_to_epoch(block.slot)))
return block
def build_empty_block_for_next_slot(state):
def build_empty_block(state, slot=None, signed=False):
if slot is None:
slot = state.slot
empty_block = BeaconBlock()
empty_block.slot = state.slot + 1
empty_block.slot = slot
empty_block.body.eth1_data.deposit_count = state.deposit_index
previous_block_header = deepcopy(state.latest_block_header)
if previous_block_header.state_root == spec.ZERO_HASH:
previous_block_header.state_root = state.hash_tree_root()
empty_block.previous_block_root = signing_root(previous_block_header)
if signed:
make_block_signature(state, empty_block)
return empty_block
def build_empty_block_for_next_slot(state, signed=False):
return build_empty_block(state, state.slot + 1, signed=signed)
def build_deposit_data(state, pubkey, privkey, amount):
deposit_data = DepositData(
pubkey=pubkey,
@ -172,7 +211,8 @@ def build_attestation_data(state, slot, shard):
justified_epoch = state.current_justified_epoch
justified_block_root = state.current_justified_root
crosslinks = state.current_crosslinks if slot_to_epoch(slot) == get_current_epoch(state) else state.previous_crosslinks
crosslinks = state.current_crosslinks if slot_to_epoch(slot) == get_current_epoch(
state) else state.previous_crosslinks
return AttestationData(
shard=shard,
beacon_block_root=block_root,
@ -270,6 +310,8 @@ def get_valid_attester_slashing(state):
attestation_2 = deepcopy(attestation_1)
attestation_2.data.target_root = b'\x01' * 32
make_attestation_signature(state, attestation_2)
return AttesterSlashing(
attestation_1=convert_to_indexed(state, attestation_1),
attestation_2=convert_to_indexed(state, attestation_2),
@ -299,26 +341,38 @@ def get_valid_attestation(state, slot=None):
data=attestation_data,
custody_bitfield=custody_bitfield,
)
participants = get_attesting_indices(
state,
attestation.data,
attestation.aggregation_bitfield,
)
assert len(participants) == 2
make_attestation_signature(state, attestation)
return attestation
def make_aggregate_attestation_signature(state: BeaconState, data: AttestationData, participants: List[int]):
signatures = []
for validator_index in participants:
privkey = privkeys[validator_index]
signatures.append(
get_attestation_signature(
state,
attestation.data,
data,
privkey
)
)
attestation.aggregation_signature = bls.aggregate_signatures(signatures)
return attestation
return bls.aggregate_signatures(signatures)
def make_indexed_attestation_signature(state, indexed_attestation: IndexedAttestation):
participants = indexed_attestation.custody_bit_0_indices + indexed_attestation.custody_bit_1_indices
indexed_attestation.signature = make_aggregate_attestation_signature(state, indexed_attestation.data, participants)
def make_attestation_signature(state, attestation: Attestation):
participants = get_attesting_indices(
state,
attestation.data,
attestation.aggregation_bitfield,
)
attestation.signature = make_aggregate_attestation_signature(state, attestation.data, participants)
def get_valid_transfer(state, slot=None, sender_index=None, amount=None, fee=None):
@ -357,7 +411,7 @@ def get_valid_transfer(state, slot=None, sender_index=None, amount=None, fee=Non
# ensure withdrawal_credentials reproducable
state.validator_registry[transfer.sender].withdrawal_credentials = (
spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:]
spec.BLS_WITHDRAWAL_PREFIX_BYTE + spec.hash(transfer.pubkey)[1:]
)
return transfer
@ -390,26 +444,32 @@ def add_attestation_to_state(state, attestation, slot):
block = build_empty_block_for_next_slot(state)
block.slot = slot
block.body.attestations.append(attestation)
state_transition_to(state, block.slot)
make_block_signature(state, block)
state_transition(state, block)
def next_slot(state):
"""
Transition to the next slot via an empty block.
Return the empty block that triggered the transition.
Transition to the next slot.
"""
block = build_empty_block_for_next_slot(state)
state_transition(state, block)
return block
state_transition_to(state, state.slot + 1)
def next_epoch(state):
"""
Transition to the start slot of the next epoch via an empty block.
Return the empty block that triggered the transition.
Transition to the start slot of the next epoch
"""
block = build_empty_block_for_next_slot(state)
block.slot += spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)
slot = state.slot + spec.SLOTS_PER_EPOCH - (state.slot % spec.SLOTS_PER_EPOCH)
state_transition_to(state, slot)
def apply_empty_block(state):
"""
Transition via an empty block (on current slot, assuming no block has been applied yet).
:return: the empty block that triggered the transition.
"""
block = build_empty_block(state)
state_transition(state, block)
return block

View File

@ -1,10 +1,10 @@
from copy import deepcopy
import eth2spec.phase0.spec as spec
from eth2spec.phase0.state_transition import (
state_transition,
)
from .context import spec_state_test
from .helpers import (
build_empty_block_for_next_slot,
fill_aggregate_attestation,
@ -12,10 +12,9 @@ from .helpers import (
get_epoch_start_slot,
get_valid_attestation,
next_epoch,
apply_empty_block
)
from .context import spec_state_test
def check_finality(state,
prev_state,
@ -101,7 +100,9 @@ def test_finality_rule_4(state):
def test_finality_rule_1(state):
# get past first two epochs that finality does not run on
next_epoch(state)
apply_empty_block(state)
next_epoch(state)
apply_empty_block(state)
yield 'pre', state
@ -128,7 +129,9 @@ def test_finality_rule_1(state):
def test_finality_rule_2(state):
# get past first two epochs that finality does not run on
next_epoch(state)
apply_empty_block(state)
next_epoch(state)
apply_empty_block(state)
yield 'pre', state
@ -161,7 +164,9 @@ def test_finality_rule_3(state):
"""
# get past first two epochs that finality does not run on
next_epoch(state)
apply_empty_block(state)
next_epoch(state)
apply_empty_block(state)
yield 'pre', state

View File

@ -1,12 +1,13 @@
from py_ecc import bls
def bls_verify(pubkey, message_hash, signature, domain):
return True
return bls.verify(message_hash=message_hash, pubkey=pubkey, signature=signature, domain=domain)
def bls_verify_multiple(pubkeys, message_hashes, signature, domain):
return True
return bls.verify_multiple(pubkeys, message_hashes, signature, domain)
def bls_aggregate_pubkeys(pubkeys):
return b'\x42' * 96
return bls.aggregate_pubkeys(pubkeys)