Merge pull request #2311 from ralexstokes/add-altair-val-tests
Add some basic tests for Altair validator guide
This commit is contained in:
commit
18fc7c0498
2
setup.py
2
setup.py
|
@ -695,7 +695,7 @@ setup(
|
||||||
"py_ecc==5.2.0",
|
"py_ecc==5.2.0",
|
||||||
"milagro_bls_binding==1.6.3",
|
"milagro_bls_binding==1.6.3",
|
||||||
"dataclasses==0.6",
|
"dataclasses==0.6",
|
||||||
"remerkleable==0.1.18",
|
"remerkleable==0.1.19",
|
||||||
"ruamel.yaml==0.16.5",
|
"ruamel.yaml==0.16.5",
|
||||||
"lru-dict==1.1.6",
|
"lru-dict==1.1.6",
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,166 @@
|
||||||
|
import random
|
||||||
|
from collections import defaultdict
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
||||||
|
sync_committee_pubkeys = set(
|
||||||
|
list(state.current_sync_committee.pubkeys)
|
||||||
|
+ list(state.next_sync_committee.pubkeys)
|
||||||
|
)
|
||||||
|
disqualified_pubkeys = set(
|
||||||
|
filter(lambda key: key not in sync_committee_pubkeys, active_pubkeys)
|
||||||
|
)
|
||||||
|
# NOTE: only check `disqualified_pubkeys` if SYNC_COMMITEE_SIZE < validator count
|
||||||
|
if disqualified_pubkeys:
|
||||||
|
sample_size = 3
|
||||||
|
assert validator_count >= sample_size
|
||||||
|
some_pubkeys = rng.sample(disqualified_pubkeys, sample_size)
|
||||||
|
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_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)
|
||||||
|
|
||||||
|
|
||||||
|
def _validator_index_for_pubkey(state, pubkey):
|
||||||
|
return list(map(lambda v: v.pubkey, state.validators)).index(pubkey)
|
||||||
|
|
||||||
|
|
||||||
|
def _subnet_for_sync_committee_index(spec, i):
|
||||||
|
return i // (spec.SYNC_COMMITTEE_SIZE // spec.SYNC_COMMITTEE_SUBNET_COUNT)
|
||||||
|
|
||||||
|
|
||||||
|
@with_all_phases_except([PHASE0])
|
||||||
|
@with_state
|
||||||
|
def test_compute_subnets_for_sync_committee(state, spec, phases):
|
||||||
|
some_sync_committee_members = list(
|
||||||
|
(
|
||||||
|
_subnet_for_sync_committee_index(spec, i),
|
||||||
|
pubkey,
|
||||||
|
)
|
||||||
|
for i, pubkey in enumerate(state.current_sync_committee.pubkeys)
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_subnets_by_pubkey = defaultdict(list)
|
||||||
|
for (subnet, pubkey) in some_sync_committee_members:
|
||||||
|
expected_subnets_by_pubkey[pubkey].append(subnet)
|
||||||
|
|
||||||
|
for _, pubkey in some_sync_committee_members:
|
||||||
|
validator_index = _validator_index_for_pubkey(state, pubkey)
|
||||||
|
subnets = spec.compute_subnets_for_sync_committee(state, validator_index)
|
||||||
|
expected_subnets = expected_subnets_by_pubkey[pubkey]
|
||||||
|
assert subnets == expected_subnets
|
Loading…
Reference in New Issue