Exemplo n.º 1
0
def test_get_beacon_proposer_index(monkeypatch, num_validators,
                                   slots_per_epoch, committee, slot,
                                   registry_change, success, sample_state,
                                   genesis_epoch, target_committee_size,
                                   shard_count, committee_config):

    from eth2.beacon import committee_helpers

    def mock_get_crosslink_committees_at_slot(state,
                                              slot,
                                              committee_config,
                                              registry_change=False):
        return ((
            committee,
            1,
        ), )

    monkeypatch.setattr(committee_helpers, 'get_crosslink_committees_at_slot',
                        mock_get_crosslink_committees_at_slot)
    if success:
        proposer_index = get_beacon_proposer_index(
            sample_state,
            slot,
            committee_config,
            registry_change=registry_change,
        )
        assert proposer_index == committee[slot % len(committee)]
    else:
        with pytest.raises(ValidationError):
            get_beacon_proposer_index(
                sample_state,
                slot,
                committee_config,
                registry_change=registry_change,
            )
Exemplo n.º 2
0
def process_attestations(state: BeaconState, block: BaseBeaconBlock,
                         config: Eth2Config) -> BeaconState:
    if len(block.body.attestations) > config.MAX_ATTESTATIONS:
        raise ValidationError(
            f"The block has too many attestations:\n"
            f"\tFound {len(block.body.attestations)} attestations, "
            f"maximum: {config.MAX_ATTESTATIONS}")

    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    current_epoch_attestations = state.current_epoch_attestations
    previous_epoch_attestations = state.previous_epoch_attestations

    for attestation in block.body.attestations:
        validate_attestation(state, attestation, config)
        proposer_index = get_beacon_proposer_index(state, config)
        pending_attestation = PendingAttestation.create(
            aggregation_bits=attestation.aggregation_bits,
            data=attestation.data,
            inclusion_delay=state.slot - attestation.data.slot,
            proposer_index=proposer_index,
        )

        if attestation.data.target.epoch == current_epoch:
            current_epoch_attestations = current_epoch_attestations.append(
                pending_attestation)
        else:
            previous_epoch_attestations = previous_epoch_attestations.append(
                pending_attestation)

    return state.mset(
        "current_epoch_attestations",
        current_epoch_attestations,
        "previous_epoch_attestations",
        previous_epoch_attestations,
    )
Exemplo n.º 3
0
def is_proposer(state: BeaconState, validator_index: ValidatorIndex,
                config: Eth2Config) -> bool:
    """
    Return if the validator is proposer of `state.slot`.
    """
    return get_beacon_proposer_index(
        state, CommitteeConfig(config)) == validator_index
Exemplo n.º 4
0
def create_block_proposal(
    slot: Slot,
    parent_root: Root,
    randao_reveal: BLSSignature,
    eth1_data: Eth1Data,
    attestations: Sequence[Attestation],
    state: BeaconState,
    state_machine: BaseBeaconStateMachine,
) -> BeaconBlock:
    config = state_machine.config
    state_at_slot, _ = state_machine.apply_state_transition(state,
                                                            future_slot=slot)
    proposer_index = get_beacon_proposer_index(state_at_slot, config)

    block_body = BeaconBlockBody.create(randao_reveal=randao_reveal,
                                        eth1_data=eth1_data,
                                        attestations=attestations)
    proposal = BeaconBlock.create(
        slot=slot,
        parent_root=parent_root,
        body=block_body,
        proposer_index=proposer_index,
    )
    block_with_empty_signature = SignedBeaconBlock.create(
        message=proposal, signature=EMPTY_SIGNATURE)
    post_state, block_with_state_root = state_machine.apply_state_transition(
        state, block_with_empty_signature, check_proposer_signature=False)
    return block_with_state_root.message
Exemplo n.º 5
0
def validate_proposer_is_not_slashed(state: BeaconState, block_root: Hash32,
                                     config: CommitteeConfig) -> None:
    proposer_index = get_beacon_proposer_index(state, config)
    proposer = state.validators[proposer_index]
    if proposer.slashed:
        raise ValidationError(
            f"Proposer for block {encode_hex(block_root)} is slashed")
Exemplo n.º 6
0
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock,
                                committee_config: CommitteeConfig) -> None:
    message_hash = block.signing_root

    # Get the public key of proposer
    beacon_proposer_index = get_beacon_proposer_index(
        state,
        committee_config,
    )
    proposer_pubkey = state.validators[beacon_proposer_index].pubkey
    domain = get_domain(
        state,
        SignatureDomain.DOMAIN_BEACON_PROPOSER,
        committee_config.SLOTS_PER_EPOCH,
    )

    try:
        bls.validate(
            pubkey=proposer_pubkey,
            message_hash=message_hash,
            signature=block.signature,
            domain=domain,
        )
    except SignatureError as error:
        raise ValidationError(
            f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}",
            error,
        )
Exemplo n.º 7
0
def process_randao(state: BeaconState, block: BaseBeaconBlock,
                   config: Eth2Config) -> BeaconState:
    proposer_index = get_beacon_proposer_index(
        state=state,
        slot=state.slot,
        committee_config=CommitteeConfig(config),
    )
    proposer = state.validator_registry[proposer_index]

    epoch = state.current_epoch(config.SLOTS_PER_EPOCH)

    validate_randao_reveal(
        randao_reveal=block.randao_reveal,
        proposer_index=proposer_index,
        proposer_pubkey=proposer.pubkey,
        epoch=epoch,
        fork=state.fork,
    )

    randao_mix_index = epoch % config.LATEST_RANDAO_MIXES_LENGTH
    new_randao_mix = bitwise_xor(
        get_randao_mix(
            state=state,
            epoch=epoch,
            slots_per_epoch=config.SLOTS_PER_EPOCH,
            latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH,
        ),
        hash_eth2(block.randao_reveal),
    )

    return state.copy(latest_randao_mixes=update_tuple_item(
        state.latest_randao_mixes,
        randao_mix_index,
        new_randao_mix,
    ), )
Exemplo n.º 8
0
def process_attestations(state: BeaconState, block: BaseBeaconBlock,
                         config: Eth2Config) -> BeaconState:
    if len(block.body.attestations) > config.MAX_ATTESTATIONS:
        raise ValidationError(
            f"The block has too many attestations:\n"
            f"\tFound {len(block.body.attestations)} attestations, "
            f"maximum: {config.MAX_ATTESTATIONS}")

    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    new_current_epoch_attestations: Tuple[PendingAttestation, ...] = tuple()
    new_previous_epoch_attestations: Tuple[PendingAttestation, ...] = tuple()
    for attestation in block.body.attestations:
        validate_attestation(state, attestation, config)
        proposer_index = get_beacon_proposer_index(state,
                                                   CommitteeConfig(config))
        pending_attestation = PendingAttestation(
            aggregation_bits=attestation.aggregation_bits,
            data=attestation.data,
            inclusion_delay=state.slot - attestation.data.slot,
            proposer_index=proposer_index,
        )

        if attestation.data.target.epoch == current_epoch:
            new_current_epoch_attestations += (pending_attestation, )
        else:
            new_previous_epoch_attestations += (pending_attestation, )

    return state.copy(
        current_epoch_attestations=(state.current_epoch_attestations +
                                    new_current_epoch_attestations),
        previous_epoch_attestations=(state.previous_epoch_attestations +
                                     new_previous_epoch_attestations),
    )
Exemplo n.º 9
0
def _get_proposer_index(state: BeaconState,
                        config: Eth2Config) -> ValidatorIndex:
    proposer_index = get_beacon_proposer_index(
        state,
        CommitteeConfig(config),
    )
    return proposer_index
Exemplo n.º 10
0
def validate_proposer_signature(state: BeaconState,
                                block: BaseBeaconBlock,
                                beacon_chain_shard_number: Shard,
                                committee_config: CommitteeConfig) -> None:

    # TODO: Replace this with real signed_root
    message_hash = block.signed_root

    # Get the public key of proposer
    beacon_proposer_index = get_beacon_proposer_index(
        state,
        state.slot,
        committee_config,
    )
    proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey
    domain = get_domain(
        state.fork,
        state.current_epoch(committee_config.SLOTS_PER_EPOCH),
        SignatureDomain.DOMAIN_BEACON_BLOCK
    )

    is_valid_signature = bls.verify(
        pubkey=proposer_pubkey,
        message_hash=message_hash,
        signature=block.signature,
        domain=domain,
    )

    if not is_valid_signature:
        raise ValidationError(
            f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}, "
            f"pubkey={proposer_pubkey}, message_hash={message_hash}, "
            f"block.signature={block.signature}, domain={domain}"
        )
Exemplo n.º 11
0
def test_get_beacon_proposer_index(genesis_state, config):
    # TODO(hwwhww) find a way to normalize validator effective balance distribution.
    state = genesis_state
    validators = tuple([
        state.validators[index].set("effective_balance",
                                    config.MAX_EFFECTIVE_BALANCE)
        for index in range(len(state.validators))
    ])
    for slot in range(0, config.SLOTS_PER_EPOCH):
        state = state.mset("slot", slot, "validators", validators)
        proposer_index = get_beacon_proposer_index(state, config)
        assert proposer_index

        current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
        domain_type = signature_domain_to_domain_type(
            SignatureDomain.DOMAIN_BEACON_PROPOSER)
        seed = hash_eth2(
            get_seed(state, current_epoch, domain_type, config) +
            state.slot.to_bytes(8, "little"))
        random_byte = hash_eth2(seed +
                                (proposer_index //
                                 32).to_bytes(8, "little"))[proposer_index %
                                                            32]
        # Verify if proposer_index matches the condition.
        assert (state.validators[proposer_index].effective_balance *
                MAX_RANDOM_BYTE >= config.MAX_EFFECTIVE_BALANCE * random_byte)
Exemplo n.º 12
0
def validate_proposer_index(state: BeaconState, config: Eth2Config, slot: Slot,
                            validator_index: ValidatorIndex) -> None:
    beacon_proposer_index = get_beacon_proposer_index(state.copy(slot=slot),
                                                      config)

    if validator_index != beacon_proposer_index:
        raise ProposerIndexError
Exemplo n.º 13
0
def process_randao(state: BeaconState, block: BaseBeaconBlock,
                   config: Eth2Config) -> BeaconState:
    proposer_index = get_beacon_proposer_index(
        state=state, committee_config=CommitteeConfig(config))

    epoch = state.current_epoch(config.SLOTS_PER_EPOCH)

    validate_randao_reveal(
        state=state,
        proposer_index=proposer_index,
        epoch=epoch,
        randao_reveal=block.body.randao_reveal,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )

    randao_mix_index = epoch % config.EPOCHS_PER_HISTORICAL_VECTOR
    new_randao_mix = bitwise_xor(
        get_randao_mix(
            state=state,
            epoch=epoch,
            epochs_per_historical_vector=config.EPOCHS_PER_HISTORICAL_VECTOR,
        ),
        hash_eth2(block.body.randao_reveal),
    )

    return state.transform(("randao_mixes", randao_mix_index), new_randao_mix)
Exemplo n.º 14
0
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock,
                                beacon_chain_shard_number: ShardNumber,
                                committee_config: CommitteeConfig) -> None:
    block_without_signature_root = block.block_without_signature_root

    # TODO: Replace this root with tree hash root
    proposal_root = ProposalSignedData(
        state.slot,
        beacon_chain_shard_number,
        block_without_signature_root,
    ).root

    # Get the public key of proposer
    beacon_proposer_index = get_beacon_proposer_index(
        state,
        state.slot,
        committee_config,
    )
    proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey
    domain = get_domain(state.fork,
                        state.current_epoch(committee_config.EPOCH_LENGTH),
                        SignatureDomain.DOMAIN_PROPOSAL)

    is_valid_signature = bls.verify(
        pubkey=proposer_pubkey,
        message=proposal_root,
        signature=block.signature,
        domain=domain,
    )

    if not is_valid_signature:
        raise ValidationError(
            f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}, "
            f"pubkey={proposer_pubkey}, message={proposal_root},"
            f"block.signature={block.signature}, domain={domain}")
Exemplo n.º 15
0
def process_transfers(state: BeaconState, block: BaseBeaconBlock,
                      config: Eth2Config) -> BeaconState:
    if len(block.body.transfers) > config.MAX_TRANSFERS:
        raise ValidationError(
            f"The block ({block}) has too many transfers:\n"
            f"\tFound {len(block.body.transfers)} transfers, "
            f"maximum: {config.MAX_TRANSFERS}")

    for transfer in block.body.transfers:
        validate_transfer(
            state,
            transfer,
            config,
        )
        state = decrease_balance(
            state,
            transfer.sender,
            transfer.amount + transfer.fee,
        )
        state = increase_balance(
            state,
            transfer.recipient,
            transfer.amount,
        )
        state = increase_balance(
            state,
            get_beacon_proposer_index(
                state,
                CommitteeConfig(config),
            ),
            transfer.fee,
        )

    return state
Exemplo n.º 16
0
def create_mock_block(
        *,
        state: BeaconState,
        config: Eth2Config,
        state_machine: BaseBeaconStateMachine,
        signed_block_class: Type[BaseSignedBeaconBlock],
        parent_block: BaseSignedBeaconBlock,
        keymap: Dict[BLSPubkey, int],
        slot: Slot = None,
        attestations: Sequence[Attestation] = (),
) -> BaseSignedBeaconBlock:
    """
    Create a mocking block at ``slot`` with the given block parameters and ``keymap``.

    Note that it doesn't return the correct ``state_root``.
    """
    future_state = advance_to_slot(state_machine, state, slot)
    proposer_index = get_beacon_proposer_index(future_state, config)
    proposer_pubkey = state.validators[proposer_index].pubkey
    proposer_privkey = keymap[proposer_pubkey]

    result_block = create_block_on_state(
        state=future_state,
        config=config,
        state_machine=state_machine,
        signed_block_class=signed_block_class,
        parent_block=parent_block,
        slot=slot,
        validator_index=proposer_index,
        privkey=proposer_privkey,
        attestations=attestations,
        check_proposer_index=False,
    )

    return result_block
Exemplo n.º 17
0
def test_get_state_by_slot(valid_chain, genesis_block, genesis_state, keymap):
    # First, skip block and check if `get_state_by_slot` returns the expected state
    state_machine = valid_chain.get_state_machine(genesis_block.slot)
    config = state_machine.config
    state = valid_chain.get_head_state()
    block_skipped_slot = genesis_block.slot + 1
    block_skipped_state, _ = state_machine.apply_state_transition(
        state, future_slot=block_skipped_slot)
    valid_chain.chaindb.persist_state(block_skipped_state)
    with pytest.raises(StateNotFound):
        valid_chain.get_state_by_slot(block_skipped_slot)

    # Next, import proposed block and check if `get_state_by_slot` returns the expected state
    proposed_slot = block_skipped_slot + 1
    future_state, _ = state_machine.apply_state_transition(
        block_skipped_state, future_slot=proposed_slot)
    proposer_index = get_beacon_proposer_index(future_state, config)
    proposer = block_skipped_state.validators[proposer_index].pubkey
    private_key = keymap[proposer]
    randao_reveal = generate_randao_reveal(private_key, proposed_slot,
                                           block_skipped_state, config)
    block = create_block(
        proposed_slot,
        genesis_block.message.hash_tree_root,
        randao_reveal,
        state.eth1_data,
        (),
        block_skipped_state,
        state_machine,
        private_key,
    )
    valid_chain.import_block(block)
    state = valid_chain.get_head_state()
    assert (valid_chain.get_state_by_slot(proposed_slot).hash_tree_root ==
            state.hash_tree_root)
Exemplo n.º 18
0
def test_settle_penality_to_validator_and_whistleblower(
        monkeypatch, num_validators, committee, n_validators_state,
        latest_slashed_exit_length, whistleblower_reward_quotient,
        max_deposit_amount, committee_config):
    from eth2.beacon import committee_helpers

    def mock_get_crosslink_committees_at_slot(state,
                                              slot,
                                              committee_config,
                                              registry_change=False):
        return ((
            committee,
            1,
        ), )

    monkeypatch.setattr(committee_helpers, 'get_crosslink_committees_at_slot',
                        mock_get_crosslink_committees_at_slot)

    state = n_validators_state
    validator_index = 5
    whistleblower_index = get_beacon_proposer_index(
        state,
        state.slot,
        committee_config,
    )
    effective_balance = max_deposit_amount

    # Check the initial balance
    assert (state.validator_balances[validator_index] ==
            state.validator_balances[whistleblower_index] == effective_balance)

    state = _settle_penality_to_validator_and_whistleblower(
        state=state,
        validator_index=validator_index,
        latest_slashed_exit_length=latest_slashed_exit_length,
        whistleblower_reward_quotient=whistleblower_reward_quotient,
        max_deposit_amount=max_deposit_amount,
        committee_config=committee_config,
    )

    # Check `state.latest_slashed_balances`
    latest_slashed_balances_list = list(state.latest_slashed_balances)
    last_slashed_epoch = (
        state.current_epoch(committee_config.SLOTS_PER_EPOCH) %
        latest_slashed_exit_length)
    latest_slashed_balances_list[last_slashed_epoch] = max_deposit_amount
    latest_slashed_balances = tuple(latest_slashed_balances_list)

    assert state.latest_slashed_balances == latest_slashed_balances

    # Check penality and reward
    whistleblower_reward = (effective_balance // whistleblower_reward_quotient)
    whistleblower_balance = state.validator_balances[whistleblower_index]
    validator_balance = state.validator_balances[validator_index]
    balance_difference = whistleblower_balance - validator_balance
    assert balance_difference == whistleblower_reward * 2
Exemplo n.º 19
0
def validate_proposer_index(state: BeaconState, config: BeaconConfig,
                            slot: SlotNumber, validator_index: ValidatorIndex):
    beacon_proposer_index = get_beacon_proposer_index(
        state.copy(slot=slot, ),
        slot,
        CommitteeConfig(config),
    )

    if validator_index != beacon_proposer_index:
        raise ProposerIndexError
Exemplo n.º 20
0
def validate_proposer_index(
    state: BeaconState, block: BaseBeaconBlock, config: Eth2Config
) -> None:
    expected_proposer = get_beacon_proposer_index(state, config)
    if block.proposer_index != expected_proposer:
        raise ValidationError(
            f"block.proposer_index "
            f"({block.proposer_index}) does not equal expected_proposer ({expected_proposer}) "
            f"at block.slot {state.slot}"
        )
Exemplo n.º 21
0
def test_process_proposer_slashings(genesis_state,
                                    sample_beacon_block_params,
                                    sample_beacon_block_body_params,
                                    config,
                                    keymap,
                                    block_root_1,
                                    block_root_2,
                                    success):
    current_slot = config.GENESIS_SLOT + 1
    state = genesis_state.copy(
        slot=current_slot,
    )
    whistleblower_index = get_beacon_proposer_index(
        state,
        CommitteeConfig(config),
    )
    slashing_proposer_index = (whistleblower_index + 1) % len(state.validators)
    proposer_slashing = create_mock_proposer_slashing_at_block(
        state,
        config,
        keymap,
        block_root_1=block_root_1,
        block_root_2=block_root_2,
        proposer_index=slashing_proposer_index,
    )
    proposer_slashings = (proposer_slashing,)

    block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy(
        proposer_slashings=proposer_slashings,
    )
    block = SerenityBeaconBlock(**sample_beacon_block_params).copy(
        slot=current_slot,
        body=block_body,
    )

    if success:
        new_state = process_proposer_slashings(
            state,
            block,
            config,
        )
        # Check if slashed
        assert (
            new_state.balances[slashing_proposer_index] <
            state.balances[slashing_proposer_index]
        )
    else:
        with pytest.raises(ValidationError):
            process_proposer_slashings(
                state,
                block,
                config,
            )
Exemplo n.º 22
0
def get_committee_assignment(
        state: BeaconState,
        config: BeaconConfig,
        epoch: Epoch,
        validator_index: ValidatorIndex,
        registry_change: bool = False) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``
    and ``registry_change``.
    ``CommitteeAssignment.committee`` is the tuple array of validators in the committee
    ``CommitteeAssignment.shard`` is the shard to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to
        propose a beacon block at the assigned slot.
    """
    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)
    next_epoch = Epoch(current_epoch + 1)

    validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch)

    epoch_start_slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH)

    committee_config = CommitteeConfig(config)

    for slot in range(epoch_start_slot,
                      epoch_start_slot + config.SLOTS_PER_EPOCH):
        crosslink_committees = get_crosslink_committees_at_slot(
            state,
            slot,
            committee_config,
            registry_change=registry_change,
        )
        selected_committees = [
            committee for committee in crosslink_committees
            if validator_index in committee[0]
        ]
        if len(selected_committees) > 0:
            validators = selected_committees[0][0]
            shard = selected_committees[0][1]
            is_proposer = validator_index == get_beacon_proposer_index(
                state,
                Slot(slot),
                committee_config,
                registry_change=registry_change,
            )

            return CommitteeAssignment(validators, shard, Slot(slot),
                                       is_proposer)

    raise NoCommitteeAssignment
Exemplo n.º 23
0
def validate_proposer_index(state: BeaconState, config: BeaconConfig,
                            slot: SlotNumber, validator_index: ValidatorIndex):
    beacon_proposer_index = get_beacon_proposer_index(
        state.copy(slot=slot, ),
        slot,
        config.GENESIS_EPOCH,
        config.EPOCH_LENGTH,
        config.TARGET_COMMITTEE_SIZE,
        config.SHARD_COUNT,
    )

    if validator_index != beacon_proposer_index:
        raise ProposerIndexError
Exemplo n.º 24
0
def slash_validator(state: BeaconState,
                    index: ValidatorIndex,
                    config: Eth2Config,
                    whistleblower_index: ValidatorIndex = None) -> BeaconState:
    """
    Slash the validator with index ``index``.

    Exit the validator, penalize the validator, and reward the whistleblower.
    """
    # NOTE: remove in phase 1
    assert whistleblower_index is None

    slots_per_epoch = config.SLOTS_PER_EPOCH

    current_epoch = state.current_epoch(slots_per_epoch)

    state = initiate_validator_exit(state, index, config)
    state = state.update_validator_with_fn(
        index,
        _set_validator_slashed,
        current_epoch,
        config.EPOCHS_PER_SLASHINGS_VECTOR,
    )

    slashed_balance = state.validators[index].effective_balance
    slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR
    state = state.copy(slashings=update_tuple_item_with_fn(
        state.slashings,
        slashed_epoch,
        lambda balance, slashed_balance: Gwei(balance + slashed_balance),
        slashed_balance,
    ))
    state = decrease_balance(
        state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT)

    proposer_index = get_beacon_proposer_index(state, CommitteeConfig(config))
    if whistleblower_index is None:
        whistleblower_index = proposer_index
    whistleblower_reward = Gwei(slashed_balance //
                                config.WHISTLEBLOWER_REWARD_QUOTIENT)
    proposer_reward = Gwei(whistleblower_reward //
                           config.PROPOSER_REWARD_QUOTIENT)
    state = increase_balance(state, proposer_index, proposer_reward)
    state = increase_balance(
        state,
        whistleblower_index,
        Gwei(whistleblower_reward - proposer_reward),
    )

    return state
Exemplo n.º 25
0
def get_committee_assignment(
    state: BeaconState,
    config: Eth2Config,
    epoch: Epoch,
    validator_index: ValidatorIndex,
) -> CommitteeAssignment:
    """
    Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``.
    ``CommitteeAssignment.committee`` is the tuple array of validators in the committee
    ``CommitteeAssignment.shard`` is the shard to which the committee is assigned
    ``CommitteeAssignment.slot`` is the slot at which the committee is assigned
    ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to
        propose a beacon block at the assigned slot.
    """
    next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH)
    if epoch > next_epoch:
        raise ValidationError(
            f"Epoch for committee assignment ({epoch}) must not be after next epoch {next_epoch}."
        )

    active_validators = get_active_validator_indices(state.validators, epoch)
    committees_per_slot = (
        get_committee_count(
            len(active_validators),
            config.SHARD_COUNT,
            config.SLOTS_PER_EPOCH,
            config.TARGET_COMMITTEE_SIZE,
        )
        // config.SLOTS_PER_EPOCH
    )
    epoch_start_slot = compute_start_slot_of_epoch(epoch, config.SLOTS_PER_EPOCH)
    epoch_start_shard = get_start_shard(state, epoch, CommitteeConfig(config))

    for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH):
        offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH)
        slot_start_shard = (epoch_start_shard + offset) % config.SHARD_COUNT
        for i in range(committees_per_slot):
            shard = Shard((slot_start_shard + i) % config.SHARD_COUNT)
            committee = get_crosslink_committee(
                state, epoch, shard, CommitteeConfig(config)
            )
            if validator_index in committee:
                is_proposer = validator_index == get_beacon_proposer_index(
                    state.copy(slot=slot), CommitteeConfig(config)
                )
                return CommitteeAssignment(
                    committee, Shard(shard), Slot(slot), is_proposer
                )

    raise NoCommitteeAssignment
Exemplo n.º 26
0
def _get_proposer_index(state_machine: BaseBeaconStateMachine,
                        state: BeaconState, slot: Slot,
                        previous_block_root: Hash32,
                        config: Eth2Config) -> ValidatorIndex:
    # advance the state to the ``slot``.
    state_transition = state_machine.state_transition
    state = state_transition.apply_state_transition_without_block(
        state, slot, previous_block_root)

    proposer_index = get_beacon_proposer_index(
        state,
        slot,
        CommitteeConfig(config),
    )
    return proposer_index
Exemplo n.º 27
0
def _mk_minimum_viable_signed_beacon_blocks(slots, state_machine_provider,
                                            state, block, config):
    for slot in slots:
        future_state, _ = state_machine_provider(slot).apply_state_transition(
            state, future_slot=block.slot + 1)
        proposer_index = get_beacon_proposer_index(future_state, config)
        message = BeaconBlock.create(
            slot=slot,
            parent_root=block.message.hash_tree_root,
            proposer_index=proposer_index,
        )
        block = SignedBeaconBlock.create(message=message)
        state, block = state_machine_provider(slot).apply_state_transition(
            state, block)
        yield block
Exemplo n.º 28
0
def slash_validator(
    state: BeaconState,
    index: ValidatorIndex,
    config: Eth2Config,
    whistleblower_index: ValidatorIndex = None,
) -> BeaconState:
    """
    Slash the validator with index ``index``.

    Exit the validator, penalize the validator, and reward the whistleblower.
    """
    # NOTE: remove in phase 1
    assert whistleblower_index is None

    slots_per_epoch = config.SLOTS_PER_EPOCH

    current_epoch = state.current_epoch(slots_per_epoch)

    state = initiate_validator_exit(state, index, config)

    state = state.transform(
        ("validators", index),
        partial(
            _set_validator_slashed,
            current_epoch=current_epoch,
            epochs_per_slashings_vector=config.EPOCHS_PER_SLASHINGS_VECTOR,
        ),
    )

    slashed_balance = state.validators[index].effective_balance
    slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR
    state = state.transform(("slashings", slashed_epoch),
                            lambda balance: Gwei(balance + slashed_balance))
    state = decrease_balance(
        state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT)

    proposer_index = get_beacon_proposer_index(state, config)
    if whistleblower_index is None:
        whistleblower_index = proposer_index
    whistleblower_reward = Gwei(slashed_balance //
                                config.WHISTLEBLOWER_REWARD_QUOTIENT)
    proposer_reward = Gwei(whistleblower_reward //
                           config.PROPOSER_REWARD_QUOTIENT)
    state = increase_balance(state, proposer_index, proposer_reward)
    state = increase_balance(state, whistleblower_index,
                             Gwei(whistleblower_reward - proposer_reward))

    return state
Exemplo n.º 29
0
def test_import_blocks(valid_chain, genesis_block, genesis_state, config,
                       keymap):
    state = genesis_state
    blocks = (genesis_block, )
    valid_chain_2 = copy.deepcopy(valid_chain)
    for _ in range(3):
        state_machine = valid_chain.get_state_machine(blocks[-1].slot)
        parent_block = blocks[-1]
        slot = state.slot + 2

        future_state, _ = state_machine.apply_state_transition(
            state, future_slot=state.slot + 2)
        proposer_index = get_beacon_proposer_index(future_state, config)
        proposer = state.validators[proposer_index].pubkey
        private_key = keymap[proposer]
        randao_reveal = generate_randao_reveal(private_key, slot, state,
                                               config)
        block = create_block(
            slot,
            parent_block.message.hash_tree_root,
            randao_reveal,
            state.eth1_data,
            (),
            state,
            state_machine,
            private_key,
        )

        valid_chain.import_block(block)
        assert valid_chain.get_canonical_head() == block

        state = valid_chain.get_head_state()

        assert block == valid_chain.get_canonical_block_by_slot(block.slot)
        assert block.message.hash_tree_root == valid_chain.get_canonical_block_root(
            block.slot)
        blocks += (block, )

    assert valid_chain.get_canonical_head(
    ) != valid_chain_2.get_canonical_head()

    for block in blocks[1:]:
        valid_chain_2.import_block(block)

    assert valid_chain.get_canonical_head(
    ) == valid_chain_2.get_canonical_head()
    assert valid_chain.get_head_state().slot != 0
    assert valid_chain.get_head_state() == valid_chain_2.get_head_state()
Exemplo n.º 30
0
def _build_chain_of_blocks_with_states(
    chain,
    state,
    parent_block,
    slots,
    config,
    keymap,
    attestation_participation=1.0,
    eth1_block_hash=ZERO_HASH32,
):
    blocks = ()
    states = ()
    for slot in range(parent_block.slot + 1, parent_block.slot + 1 + slots):
        sm = chain.get_state_machine(state.slot)
        pre_state, _ = sm.apply_state_transition(state, future_slot=slot)
        proposer_index = get_beacon_proposer_index(pre_state, config)
        public_key = state.validators[proposer_index].pubkey
        private_key = keymap[public_key]
        randao_reveal = generate_randao_reveal(private_key, slot, pre_state,
                                               config)

        attestations = create_mock_signed_attestations_at_slot(
            state,
            config,
            sm,
            slot - 1,
            parent_block.hash_tree_root,
            keymap,
            voted_attesters_ratio=attestation_participation,
        )
        block = create_block(
            slot,
            parent_block.hash_tree_root,
            randao_reveal,
            Eth1Data.create(block_hash=eth1_block_hash),
            attestations,
            state,
            sm,
            private_key,
        )

        parent_block = block.message
        state, block = sm.apply_state_transition(state, block)

        blocks += (block, )
        states += (state, )
    return blocks, states