Exemple #1
0
def test_get_beacon_proposer_index(monkeypatch, num_validators, epoch_length,
                                   committee, slot, success, sample_state,
                                   target_committee_size, shard_count):

    from eth2.beacon import helpers

    def mock_get_crosslink_committees_at_slot(state, slot, epoch_length,
                                              target_committee_size,
                                              shard_count):
        return ((
            committee,
            1,
        ), )

    monkeypatch.setattr(helpers, 'get_crosslink_committees_at_slot',
                        mock_get_crosslink_committees_at_slot)
    if success:
        proposer_index = get_beacon_proposer_index(
            sample_state,
            slot,
            epoch_length,
            target_committee_size,
            shard_count,
        )
        assert proposer_index == committee[slot % len(committee)]
    else:
        with pytest.raises(ValidationError):
            get_beacon_proposer_index(
                sample_state,
                slot,
                epoch_length,
                target_committee_size,
                shard_count,
            )
Exemple #2
0
def create_mock_block(
    state: BeaconState,
    config: BeaconConfig,
    block_class: Type[BaseBeaconBlock],
    parent_block: BaseBeaconBlock,
    keymap: Dict[BLSPubkey, int],
    slot: SlotNumber = None,
    attestations: Sequence[Attestation] = ()
) -> BaseBeaconBlock:
    """
    Create a mocking block with the given block parameters and ``keymap``.
    """
    proposer_index = get_beacon_proposer_index(
        state.copy(slot=slot, ),
        slot,
        config.EPOCH_LENGTH,
        config.TARGET_COMMITTEE_SIZE,
        config.SHARD_COUNT,
    )
    proposer_pubkey = state.validator_registry[proposer_index].pubkey
    proposer_privkey = keymap[proposer_pubkey]

    block = create_block_on_state(
        state,
        config,
        block_class,
        parent_block,
        slot,
        validator_index=proposer_index,
        privkey=proposer_privkey,
        attestations=attestations,
    )

    return block
Exemple #3
0
def validate_serenity_proposer_signature(
        state: BeaconState, block: BaseBeaconBlock,
        beacon_chain_shard_number: ShardNumber, epoch_length: int) -> 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,
                                                      epoch_length)
    proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey

    is_valid_signature = bls.verify(
        pubkey=proposer_pubkey,
        message=proposal_root,
        signature=block.signature,
        domain=get_domain(state.fork_data, state.slot,
                          SignatureDomain.DOMAIN_PROPOSAL),
    )

    if not is_valid_signature:
        raise ValidationError("Invalid Proposer Signature on block")
Exemple #4
0
def test_settle_penality_to_validator_and_whistleblower(
        monkeypatch, num_validators, committee, ten_validators_state,
        latest_penalized_exit_length, whistleblower_reward_quotient,
        epoch_length, max_deposit, target_committee_size, shard_count):
    from eth2.beacon import helpers

    def mock_get_crosslink_committees_at_slot(state, slot, epoch_length,
                                              target_committee_size,
                                              shard_count):
        return ((
            committee,
            1,
        ), )

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

    state = ten_validators_state
    validator_index = 5
    whistleblower_index = get_beacon_proposer_index(
        state,
        state.slot,
        epoch_length,
        target_committee_size,
        shard_count,
    )
    effective_balance = max_deposit * GWEI_PER_ETH

    # 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_penalized_exit_length=latest_penalized_exit_length,
        whistleblower_reward_quotient=whistleblower_reward_quotient,
        epoch_length=epoch_length,
        max_deposit=max_deposit,
        target_committee_size=target_committee_size,
        shard_count=shard_count,
    )

    # Check `state.latest_penalized_balances`
    latest_penalized_balances_list = list(state.latest_penalized_balances)
    last_penalized_epoch = (state.slot //
                            epoch_length) % latest_penalized_exit_length
    latest_penalized_balances_list[
        last_penalized_epoch] = max_deposit * GWEI_PER_ETH
    latest_penalized_balances = tuple(latest_penalized_balances_list)

    assert state.latest_penalized_balances == latest_penalized_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
Exemple #5
0
def create_block_on_state(state: BeaconState, config: BeaconConfig,
                          block_class: BaseBeaconBlock,
                          parent_block: BaseBeaconBlock, slot: SlotNumber,
                          validator_index: int, privkey: int,
                          attestations: Sequence[Attestation]):
    """
    Create a beacon block with the given parameters.
    """
    # Check proposer
    beacon_proposer_index = get_beacon_proposer_index(
        state.copy(slot=slot, ),
        slot,
        config.EPOCH_LENGTH,
        config.TARGET_COMMITTEE_SIZE,
        config.SHARD_COUNT,
    )

    if validator_index != beacon_proposer_index:
        raise ProposerIndexError

    # Prepare block: slot and parent_root
    block = block_class.from_parent(
        parent_block=parent_block,
        block_params=FromBlockParams(slot=slot),
    )

    # TODO: Add more operations
    randao_reveal = ZERO_HASH32
    eth1_data = Eth1Data.create_empty_data()
    body = BeaconBlockBody.create_empty_body().copy(
        attestations=attestations, )

    block = block.copy(
        randao_reveal=randao_reveal,
        eth1_data=eth1_data,
        body=body,
    )

    # Sign
    empty_signature_block_root = block.block_without_signature_root
    proposal_root = ProposalSignedData(
        slot,
        config.BEACON_CHAIN_SHARD_NUMBER,
        empty_signature_block_root,
    ).root
    domain = get_domain(
        state.fork,
        slot,
        SignatureDomain.DOMAIN_PROPOSAL,
    )
    block = block.copy(signature=bls.sign(
        message=proposal_root,
        privkey=privkey,
        domain=domain,
    ), )

    return block
def _settle_penality_to_validator_and_whistleblower(
        *, state: BeaconState, validator_index: ValidatorIndex,
        latest_penalized_exit_length: int, whistleblower_reward_quotient: int,
        epoch_length: int, max_deposit: Ether) -> BeaconState:
    """
    Apply penality/reward to validator and whistleblower and update the meta data

    More intuitive pseudo-code:
    current_epoch_penalization_index = (state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH
    state.latest_penalized_exit_balances[current_epoch_penalization_index] += (
        get_effective_balance(state, index)
    )
    whistleblower_index = get_beacon_proposer_index(state, state.slot)
    whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT
    state.validator_balances[whistleblower_index] += whistleblower_reward
    state.validator_balances[index] -= whistleblower_reward
    validator.penalized_slot = state.slot
    """
    # Update `state.latest_penalized_exit_balances`
    current_epoch_penalization_index = (
        state.slot // epoch_length) % latest_penalized_exit_length
    effective_balance = get_effective_balance(
        state.validator_balances,
        validator_index,
        max_deposit,
    )
    penalized_exit_balance = (
        state.latest_penalized_exit_balances[current_epoch_penalization_index]
        + effective_balance)
    latest_penalized_exit_balances = update_tuple_item(
        tuple_data=state.latest_penalized_exit_balances,
        index=current_epoch_penalization_index,
        new_value=penalized_exit_balance,
    )
    state = state.copy(
        latest_penalized_exit_balances=latest_penalized_exit_balances, )

    # Update whistleblower's balance
    whistleblower_reward = (effective_balance // whistleblower_reward_quotient)
    whistleblower_index = get_beacon_proposer_index(state, state.slot,
                                                    epoch_length)
    state = state.update_validator_balance(
        whistleblower_index,
        state.validator_balances[whistleblower_index] + whistleblower_reward,
    )

    # Update validator's balance and `penalized_slot` field
    validator = state.validator_registry[validator_index]
    validator = validator.copy(penalized_slot=state.slot, )
    state = state.update_validator(
        validator_index,
        validator,
        state.validator_balances[validator_index] - whistleblower_reward,
    )

    return state
Exemple #7
0
def test_get_beacon_proposer_index(
        monkeypatch,
        num_validators,
        epoch_length,
        committee,
        slot,
        success,
        sample_state):

    from eth2.beacon import helpers

    def mock_get_shard_committees_at_slot(state,
                                          slot,
                                          epoch_length):
        return (
            ShardCommittee(
                shard=1,
                committee=committee,
                total_validator_count=num_validators,
            ),
        )

    monkeypatch.setattr(
        helpers,
        'get_shard_committees_at_slot',
        mock_get_shard_committees_at_slot
    )
    if success:
        proposer_index = get_beacon_proposer_index(
            sample_state,
            slot,
            epoch_length
        )
        assert proposer_index == committee[slot % len(committee)]
    else:
        with pytest.raises(ValidationError):
            get_beacon_proposer_index(
                sample_state,
                slot,
                epoch_length
            )
Exemple #8
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
Exemple #9
0
def create_mock_block(
    *,
    state: BeaconState,
    config: BeaconConfig,
    state_machine: BaseBeaconStateMachine,
    block_class: Type[BaseBeaconBlock],
    parent_block: BaseBeaconBlock,
    keymap: Dict[BLSPubkey, int],
    slot: SlotNumber = None,
    attestations: Sequence[Attestation] = ()
) -> BaseBeaconBlock:
    """
    Create a mocking block with the given block parameters and ``keymap``.

    Note that it doesn't return the correct ``state_root``.
    """
    proposer_index = get_beacon_proposer_index(
        state.copy(slot=slot, ),
        slot,
        config.GENESIS_EPOCH,
        config.EPOCH_LENGTH,
        config.TARGET_COMMITTEE_SIZE,
        config.SHARD_COUNT,
    )
    proposer_pubkey = state.validator_registry[proposer_index].pubkey
    proposer_privkey = keymap[proposer_pubkey]

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

    return result_block
Exemple #10
0
def test_demo(base_db, sample_beacon_block_params, genesis_state,
              fixture_sm_class, config, privkeys, pubkeys):
    chaindb = BeaconChainDB(base_db)
    state = genesis_state
    block = SerenityBeaconBlock(**sample_beacon_block_params).copy(
        slot=state.slot + 2,
        state_root=state.root,
    )

    # Sign block
    beacon_proposer_index = get_beacon_proposer_index(
        state,
        block.slot,
        config.EPOCH_LENGTH,
    )
    index_in_privkeys = pubkeys.index(
        state.validator_registry[beacon_proposer_index].pubkey)
    beacon_proposer_privkey = privkeys[index_in_privkeys]
    empty_signature_block_root = block.block_without_signature_root
    proposal_root = ProposalSignedData(
        block.slot,
        config.BEACON_CHAIN_SHARD_NUMBER,
        empty_signature_block_root,
    ).root
    block = block.copy(signature=bls.sign(
        message=proposal_root,
        privkey=beacon_proposer_privkey,
        domain=SignatureDomain.DOMAIN_PROPOSAL,
    ), )

    # Store in chaindb
    chaindb.persist_block(block, SerenityBeaconBlock)
    chaindb.persist_state(state)

    # Get state machine instance
    sm = fixture_sm_class(chaindb, block.root, SerenityBeaconBlock)
    result_state, _ = sm.import_block(block)

    assert state.slot == 0
    assert result_state.slot == block.slot
    assert isinstance(sm.block, SerenityBeaconBlock)
Exemple #11
0
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock,
                                beacon_chain_shard_number: ShardNumber,
                                epoch_length: int, target_committee_size: int,
                                shard_count: int) -> 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,
        epoch_length,
        target_committee_size,
        shard_count,
    )
    proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey
    domain = get_domain(state.fork, state.slot,
                        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}")
Exemple #12
0
def test_per_slot_transition(base_db, genesis_block, genesis_state,
                             fixture_sm_class, config, state_slot, keymap):
    chaindb = BeaconChainDB(base_db)
    chaindb.persist_block(genesis_block, SerenityBeaconBlock)
    chaindb.persist_state(genesis_state)

    state = genesis_state

    # Create a block
    block = create_mock_block(
        state=state,
        config=config,
        state_machine=fixture_sm_class(
            chaindb,
            genesis_block,
        ),
        block_class=SerenityBeaconBlock,
        parent_block=genesis_block,
        keymap=keymap,
        slot=state_slot,
    )

    # Store in chaindb
    chaindb.persist_block(block, SerenityBeaconBlock)

    # Get state machine instance
    sm = fixture_sm_class(
        chaindb,
        block,
    )

    # Get state transition instance
    st = sm.state_transition_class(sm.config)

    updated_state = st.per_slot_transition(state, block.parent_root)

    # Ensure that slot gets increased by 1
    assert updated_state.slot == state.slot + 1

    # Validator Registry
    # Tweaking the slot, so that we get the correct proposer index
    beacon_proposer_index = get_beacon_proposer_index(
        state,
        state.slot + 1,
        st.config.GENESIS_EPOCH,
        st.config.EPOCH_LENGTH,
        st.config.TARGET_COMMITTEE_SIZE,
        st.config.SHARD_COUNT,
    )
    for validator_index, _ in enumerate(updated_state.validator_registry):
        if validator_index != beacon_proposer_index:
            # Validator Record shouldn't change if not proposer
            assert (updated_state.validator_registry[validator_index] ==
                    state.validator_registry[validator_index])
        else:
            # randao layers of proposer's record should increase by 1
            assert (
                updated_state.validator_registry[validator_index].randao_layers
                == state.validator_registry[validator_index].randao_layers + 1)

    # latest_randao_mixes
    assert (
        updated_state.latest_randao_mixes[updated_state.slot %
                                          st.config.LATEST_RANDAO_MIXES_LENGTH]
        == state.latest_randao_mixes[(state.slot) %
                                     st.config.LATEST_RANDAO_MIXES_LENGTH])

    # latest_block_roots
    latest_block_roots_index = (updated_state.slot -
                                1) % st.config.LATEST_BLOCK_ROOTS_LENGTH
    assert updated_state.latest_block_roots[
        latest_block_roots_index] == block.parent_root

    # batched_block_roots
    if updated_state.slot % st.config.LATEST_BLOCK_ROOTS_LENGTH == 0:
        assert updated_state.batched_block_roots[-1] == get_merkle_root(
            updated_state.latest_block_roots)
    else:
        assert updated_state.batched_block_roots == state.batched_block_roots