Add some basic tests for Altair validator guide

This commit is contained in:
Alex Stokes 2021-04-05 18:31:05 -07:00
parent ed3c8d2755
commit 5e43ad69cf
No known key found for this signature in database
GPG Key ID: 99B3D88FD6C55A69
2 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,155 @@
import random
from eth2spec.utils.ssz.ssz_typing import Bitvector
from eth2spec.test.helpers.block import build_empty_block
from eth2spec.test.helpers.keys import pubkey_to_privkey
from eth2spec.test.helpers.state import transition_to
from eth2spec.utils import bls
from eth2spec.utils.bls import only_with_bls
from eth2spec.test.context import (
PHASE0,
with_all_phases_except,
with_state,
)
rng = random.Random(1337)
def ensure_assignments_in_sync_committee(
spec, state, epoch, sync_committee, active_pubkeys
):
assert len(sync_committee.pubkeys) >= 3
some_pubkeys = rng.sample(sync_committee.pubkeys, 3)
for pubkey in some_pubkeys:
validator_index = active_pubkeys.index(pubkey)
assert spec.is_assigned_to_sync_committee(state, epoch, validator_index)
@with_all_phases_except([PHASE0])
@with_state
def test_is_assigned_to_sync_committee(phases, spec, state):
epoch = spec.get_current_epoch(state)
validator_indices = spec.get_active_validator_indices(state, epoch)
validator_count = len(validator_indices)
query_epoch = epoch + 1
next_query_epoch = query_epoch + spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD
active_pubkeys = [state.validators[index].pubkey for index in validator_indices]
ensure_assignments_in_sync_committee(
spec, state, query_epoch, state.current_sync_committee, active_pubkeys
)
ensure_assignments_in_sync_committee(
spec, state, next_query_epoch, state.next_sync_committee, active_pubkeys
)
assert validator_count >= 3
sync_committee_pubkeys = set(
list(state.current_sync_committee.pubkeys)
+ list(state.next_sync_committee.pubkeys)
)
disqualified_pubkeys = list(
filter(lambda key: key not in sync_committee_pubkeys, active_pubkeys)
)
some_pubkeys = rng.sample(disqualified_pubkeys, 3)
for pubkey in some_pubkeys:
validator_index = active_pubkeys.index(pubkey)
is_current = spec.is_assigned_to_sync_committee(
state, query_epoch, validator_index
)
is_next = spec.is_assigned_to_sync_committee(
state, next_query_epoch, validator_index
)
is_current_or_next = is_current or is_next
assert not is_current_or_next
def _get_sync_committee_signature(
spec,
state,
target_slot,
target_block_root,
subcommittee_index,
index_in_subcommittee,
):
subcommittee_size = spec.SYNC_COMMITTEE_SIZE // spec.SYNC_COMMITTEE_SUBNET_COUNT
sync_committee_index = (
subcommittee_index * subcommittee_size + index_in_subcommittee
)
pubkey = state.current_sync_committee.pubkeys[sync_committee_index]
privkey = pubkey_to_privkey[pubkey]
domain = spec.get_domain(
state,
spec.DOMAIN_SYNC_COMMITTEE,
)
signing_data = spec.compute_signing_root(target_block_root, domain)
return bls.Sign(privkey, spec.hash_tree_root(signing_data))
@only_with_bls()
@with_all_phases_except([PHASE0])
@with_state
def test_process_sync_committee_contributions(phases, spec, state):
# skip over slots at genesis
transition_to(spec, state, state.slot + 3)
# build a block and attempt to assemble a sync aggregate
# from some sync committee contributions
block = build_empty_block(spec, state)
previous_slot = state.slot - 1
target_block_root = spec.get_block_root_at_slot(state, previous_slot)
aggregation_bits = Bitvector[
spec.SYNC_COMMITTEE_SIZE // spec.SYNC_COMMITTEE_SUBNET_COUNT
]()
aggregation_index = 0
aggregation_bits[aggregation_index] = True
contributions = [
spec.SyncCommitteeContribution(
slot=block.slot,
beacon_block_root=target_block_root,
subcommittee_index=i,
aggregation_bits=aggregation_bits,
signature=_get_sync_committee_signature(
spec, state, previous_slot, target_block_root, i, aggregation_index
),
)
for i in range(spec.SYNC_COMMITTEE_SIZE // spec.SYNC_COMMITTEE_SUBNET_COUNT)
]
# ensure the block has an empty sync aggregate...
empty_sync_aggregate = spec.SyncAggregate()
empty_sync_aggregate.sync_committee_signature = spec.G2_POINT_AT_INFINITY
assert block.body.sync_aggregate == empty_sync_aggregate
spec.process_sync_committee_contributions(block, set(contributions))
# and that after processing, it is no longer empty
assert len(block.body.sync_aggregate.sync_committee_bits) != 0
assert (
block.body.sync_aggregate.sync_committee_signature != spec.G2_POINT_AT_INFINITY
)
# moreover, ensure the sync aggregate is valid if the block is accepted
spec.process_block(state, block)
@with_all_phases_except([PHASE0])
@with_state
def test_compute_subnets_for_sync_committee(state, spec, phases):
k = max(spec.SYNC_COMMITTEE_SIZE // 4, 1)
some_sync_committee_members = rng.sample(
list(
(i, pubkey) for i, pubkey in enumerate(state.current_sync_committee.pubkeys)
),
k,
)
validator_indices = [
list(map(lambda v: v.pubkey, state.validators)).index(pubkey)
for pubkey in map(lambda t: t[1], some_sync_committee_members)
]
expected_subnets = [
index // (spec.SYNC_COMMITTEE_SIZE // spec.SYNC_COMMITTEE_SUBNET_COUNT)
for index in map(lambda t: t[0], some_sync_committee_members)
]
for validator_index, expected_subnet in zip(validator_indices, expected_subnets):
subnet = spec.compute_subnets_for_sync_committee(state, validator_index)
assert subnet == [expected_subnet]