def test_proposer_in_committee_with_participation(spec, state):
    committee_indices = compute_committee_indices(spec, state, state.current_sync_committee)
    participation = [True for _ in committee_indices]

    # NOTE: seem to reliably be getting a matching proposer in the first epoch w/ ``MINIMAL`` preset.
    for _ in range(spec.SLOTS_PER_EPOCH):
        block = build_empty_block_for_next_slot(spec, state)
        proposer_index = block.proposer_index
        proposer_pubkey = state.validators[proposer_index].pubkey
        proposer_is_in_sync_committee = proposer_pubkey in state.current_sync_committee.pubkeys

        # Valid sync committee signature here...
        block.body.sync_aggregate = spec.SyncAggregate(
            sync_committee_bits=participation,
            sync_committee_signature=compute_aggregate_sync_committee_signature(
                spec,
                state,
                block.slot - 1,
                committee_indices,
                block_root=block.parent_root,
            )
        )

        if proposer_is_in_sync_committee:
            assert state.validators[block.proposer_index].pubkey in state.current_sync_committee.pubkeys
            yield from run_sync_committee_processing(spec, state, block)
            return
        else:
            state_transition_and_sign_block(spec, state, block)
    raise AssertionError("failed to find a proposer in the sync committee set; check test setup")
def test_sync_committee_with_participating_withdrawable_member(spec, state):
    # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
    state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

    # move forward via some blocks
    for _ in range(3):
        next_epoch_via_block(spec, state)

    committee_indices = compute_committee_indices(spec, state)
    rng = random.Random(1010)

    exited_index = _exit_validator_from_committee_and_transition_state(
        spec,
        state,
        committee_indices,
        rng,
        lambda v: v.withdrawable_epoch + 1,
    )

    current_epoch = spec.get_current_epoch(state)
    assert current_epoch > state.validators[exited_index].withdrawable_epoch

    block = build_empty_block_for_next_slot(spec, state)
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[True] * len(committee_indices),
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            block.slot - 1,
            committee_indices,  # full committee signs
            block_root=block.parent_root,
        )
    )
    yield from run_sync_committee_processing(spec, state, block)
def test_invalid_signature_previous_committee(spec, state):
    # NOTE: the `state` provided is at genesis and the process to select
    # sync committees currently returns the same committee for the first and second
    # periods at genesis.
    # To get a distinct committee so we can generate an "old" signature, we need to advance
    # 2 EPOCHS_PER_SYNC_COMMITTEE_PERIOD periods.
    current_epoch = spec.get_current_epoch(state)
    old_sync_committee = state.next_sync_committee

    epoch_in_future_sync_commitee_period = current_epoch + 2 * spec.EPOCHS_PER_SYNC_COMMITTEE_PERIOD
    slot_in_future_sync_committee_period = epoch_in_future_sync_commitee_period * spec.SLOTS_PER_EPOCH
    transition_to(spec, state, slot_in_future_sync_committee_period)

    # Use the previous sync committee to produce the signature.
    # Ensure that the pubkey sets are different.
    assert set(old_sync_committee.pubkeys) != set(state.current_sync_committee.pubkeys)
    committee_indices = compute_committee_indices(spec, state, old_sync_committee)

    block = build_empty_block_for_next_slot(spec, state)
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[True] * len(committee_indices),
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            block.slot - 1,
            committee_indices,
            block_root=block.parent_root,
        )
    )

    yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_past_block(spec, state):
    committee_indices = compute_committee_indices(spec, state)

    for _ in range(2):
        # NOTE: need to transition twice to move beyond the degenerate case at genesis
        block = build_empty_block_for_next_slot(spec, state)
        # Valid sync committee signature here...
        block.body.sync_aggregate = spec.SyncAggregate(
            sync_committee_bits=[True] * len(committee_indices),
            sync_committee_signature=compute_aggregate_sync_committee_signature(
                spec,
                state,
                block.slot - 1,
                committee_indices,
                block_root=block.parent_root,
            )
        )

        state_transition_and_sign_block(spec, state, block)

    invalid_block = build_empty_block_for_next_slot(spec, state)
    # Invalid signature from a slot other than the previous
    invalid_block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[True] * len(committee_indices),
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            invalid_block.slot - 2,
            committee_indices,
        )
    )

    yield from run_sync_committee_processing(spec, state, invalid_block, expect_exception=True)
def test_invalid_signature_infinite_signature_with_all_participants(spec, state):
    block = build_empty_block_for_next_slot(spec, state)
    # Include all participants, try the special-case signature for no-participants
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[True] * len(block.body.sync_aggregate.sync_committee_bits),
        sync_committee_signature=spec.G2_POINT_AT_INFINITY
    )
    yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_no_participants(spec, state):
    block = build_empty_block_for_next_slot(spec, state)
    # No participants is an allowed case, but needs a specific signature, not the full-zeroed signature.
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[False] * len(block.body.sync_aggregate.sync_committee_bits),
        sync_committee_signature=b'\x00' * 96
    )
    yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_bad_domain(spec, state):
    committee_indices = compute_committee_indices(spec, state)

    block = build_empty_block_for_next_slot(spec, state)
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[True] * len(committee_indices),
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            block.slot - 1,
            committee_indices,  # full committee signs
            block_root=block.parent_root,
            domain_type=spec.DOMAIN_BEACON_ATTESTER,  # Incorrect domain
        )
    )
    yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_missing_participant(spec, state):
    committee_indices = compute_committee_indices(spec, state)
    rng = random.Random(2020)
    random_participant = rng.choice(committee_indices)

    block = build_empty_block_for_next_slot(spec, state)
    # Exclude one participant whose signature was included.
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[index != random_participant for index in committee_indices],
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            block.slot - 1,
            committee_indices,  # full committee signs
            block_root=block.parent_root,
        )
    )
    yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_invalid_signature_extra_participant(spec, state):
    committee_indices = compute_committee_indices(spec, state)
    rng = random.Random(3030)
    random_participant = rng.choice(committee_indices)

    block = build_empty_block_for_next_slot(spec, state)
    # Exclude one signature even though the block claims the entire committee participated.
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=[True] * len(committee_indices),
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            block.slot - 1,
            [index for index in committee_indices if index != random_participant],
            block_root=block.parent_root,
        )
    )

    yield from run_sync_committee_processing(spec, state, block, expect_exception=True)
def test_sync_committee_with_nonparticipating_exited_member(spec, state):
    # move state forward SHARD_COMMITTEE_PERIOD epochs to allow for exit
    state.slot += spec.config.SHARD_COMMITTEE_PERIOD * spec.SLOTS_PER_EPOCH

    # move forward via some blocks
    for _ in range(3):
        next_epoch_via_block(spec, state)

    committee_indices = compute_committee_indices(spec, state)
    rng = random.Random(1010)

    exited_index = _exit_validator_from_committee_and_transition_state(
        spec,
        state,
        committee_indices,
        rng,
        lambda v: v.exit_epoch,
    )
    exited_pubkey = state.validators[exited_index].pubkey

    current_epoch = spec.get_current_epoch(state)
    assert current_epoch < state.validators[exited_index].withdrawable_epoch

    exited_committee_index = state.current_sync_committee.pubkeys.index(exited_pubkey)
    block = build_empty_block_for_next_slot(spec, state)
    committee_bits = [i != exited_committee_index for i in committee_indices]
    committee_indices = [index for index in committee_indices if index != exited_committee_index]
    block.body.sync_aggregate = spec.SyncAggregate(
        sync_committee_bits=committee_bits,
        sync_committee_signature=compute_aggregate_sync_committee_signature(
            spec,
            state,
            block.slot - 1,
            committee_indices,  # with exited validator removed
            block_root=block.parent_root,
        )
    )
    yield from run_sync_committee_processing(spec, state, block)