Ejemplo n.º 1
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)
Ejemplo n.º 2
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()
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
Ejemplo n.º 4
0
    async def propose_block(
        self,
        proposer_index: ValidatorIndex,
        slot: Slot,
        state: BeaconState,
        state_machine: BaseBeaconStateMachine,
        head_block: BaseBeaconBlock,
    ) -> BaseBeaconBlock:
        """
        Propose a block and broadcast it.
        """
        eth1_vote = await self._get_eth1_vote(slot, state, state_machine)
        # deposits = await self._get_deposit_data(state, state_machine, eth1_vote)
        # TODO(hwwhww): Check if need to aggregate and if they are overlapping.
        aggregated_attestations = self.get_ready_attestations(slot, True)
        unaggregated_attestations = self.get_ready_attestations(slot, False)
        ready_attestations = aggregated_attestations + unaggregated_attestations
        private_key = self.validator_privkeys[proposer_index]
        randao_reveal = generate_randao_reveal(
            private_key, slot, state, state_machine.config
        )

        block = create_block_proposal(
            slot,
            head_block.message.hash_tree_root,
            randao_reveal,
            eth1_vote,
            ready_attestations,
            state,
            state_machine,
        )

        block = sign_block(state, block, private_key, self.slots_per_epoch)
        self.logger.debug(
            bold_green("validator %s is proposing a block %s with attestations %s"),
            proposer_index,
            block,
            block.body.attestations,
        )
        self.chain.import_block(block)
        self.logger.debug("broadcasting block %s", block)
        await self.p2p_node.broadcast_beacon_block(block)
        metrics.validator_proposed_blocks.inc()
        return block
Ejemplo n.º 5
0
def test_get_attestation_root(valid_chain, genesis_block, genesis_state,
                              keymap, min_attestation_inclusion_delay):
    state_machine = valid_chain.get_state_machine()
    config = state_machine.config
    attestations = create_mock_signed_attestations_at_slot(
        state=genesis_state,
        config=config,
        state_machine=state_machine,
        attestation_slot=genesis_block.slot,
        beacon_block_root=genesis_block.message.hash_tree_root,
        keymap=keymap,
    )

    state = genesis_state
    slot = genesis_state.slot + 1
    future_state, _ = state_machine.apply_state_transition(state,
                                                           future_slot=slot)
    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,
        genesis_block.message.hash_tree_root,
        randao_reveal,
        state.eth1_data,
        attestations,
        state,
        state_machine,
        private_key,
    )
    valid_chain.import_block(block)
    # Only one attestation in attestations, so just check that one
    a0 = attestations[0]
    assert valid_chain.get_attestation_by_root(a0.hash_tree_root) == a0
    assert valid_chain.attestation_exists(a0.hash_tree_root)
    fake_attestation = a0.set("signature", b"\x78" * 96)
    with pytest.raises(AttestationRootNotFound):
        valid_chain.get_attestation_by_root(fake_attestation.hash_tree_root)
    assert not valid_chain.attestation_exists(fake_attestation.hash_tree_root)
Ejemplo n.º 6
0
def test_demo(base_db, validator_count, keymap, pubkeys, fork_choice_scoring):
    bls.use_noop_backend()
    config = MINIMAL_SERENITY_CONFIG
    override_lengths(config)

    genesis_slot = GENESIS_SLOT
    genesis_epoch = GENESIS_EPOCH

    genesis_state, genesis_block = create_mock_genesis(
        pubkeys=pubkeys[:validator_count],
        config=config,
        keymap=keymap,
        genesis_block_class=SerenityBeaconBlock,
    )

    chaindb = BeaconChainDB.from_genesis(
        base_db, genesis_state, SerenitySignedBeaconBlock, fork_choice_scoring
    )
    fixture_sm = SkeletonLakeStateMachine(chaindb)

    for i in range(validator_count):
        assert genesis_state.validators[i].is_active(genesis_slot)

    state = genesis_state
    block = SerenitySignedBeaconBlock.create(message=genesis_block)

    chain_length = 4 * config.SLOTS_PER_EPOCH
    blocks = (block,)

    attestations_map = {}  # Dict[Slot, Sequence[Attestation]]

    for current_slot in range(genesis_slot + 1, genesis_slot + chain_length + 1):
        if current_slot > genesis_slot + config.MIN_ATTESTATION_INCLUSION_DELAY:
            attestations = attestations_map[
                current_slot - config.MIN_ATTESTATION_INCLUSION_DELAY
            ]
        else:
            attestations = ()

        future_state, _ = fixture_sm.apply_state_transition(
            state, future_slot=current_slot
        )
        proposer_index = get_beacon_proposer_index(future_state, config)
        proposer_pubkey = state.validators[proposer_index].pubkey
        private_key = keymap[proposer_pubkey]
        randao_reveal = generate_randao_reveal(private_key, current_slot, state, config)
        block_proposal = create_block_proposal(
            current_slot,
            block.message.hash_tree_root,
            randao_reveal,
            state.eth1_data,
            attestations,
            state,
            fixture_sm,
        )
        block = sign_block(state, block_proposal, private_key, config.SLOTS_PER_EPOCH)

        state, block = fixture_sm.apply_state_transition(state, block)

        chaindb.persist_state(state)
        chaindb.persist_block(block, SerenitySignedBeaconBlock, fork_choice_scoring)

        blocks += (block,)

        # Mock attestations
        attestation_slot = current_slot
        attestations = create_mock_signed_attestations_at_slot(
            state=state,
            config=config,
            state_machine=fixture_sm,
            attestation_slot=attestation_slot,
            beacon_block_root=block.message.hash_tree_root,
            keymap=keymap,
            voted_attesters_ratio=1.0,
        )
        attestations_map[attestation_slot] = attestations

    assert state.slot == chain_length + genesis_slot

    # Justification assertions
    # NOTE: why are the number `2` or `3` used in the checks below?
    # Answer:
    # "We do not check any justification and finality during epochs 0 or 1. We do check for
    # justification and finality from epoch 2 onward."
    # [epoch 0]------[epoch 1]------>
    #
    # "In epoch 2, we justify the current epoch. This epoch is in fact justified but we do not
    # recognize it in the protocol due to an artifact of the construction of the genesis state
    # (using the `zero` value for `Checkpoint` type)."
    # [epoch 0]------[epoch 1]------[epoch 2]*------>
    # []*: checkpoint justified
    # []**: checkpoint finalized
    #
    # "In epoch 3, we have the previous justified checkpoint at the prior current justified
    # checkpoint (so `GENESIS_EPOCH + 2`) and we justify this current epoch. we check finality here
    # and see that we finalize the prior justified checkpoint at epoch 2."
    # [epoch 0]------[epoch 1]------[epoch 2]**------[epoch 3]*------>
    #
    # "Given the way we handle epoch processing (i.e. process a given epoch at the start of
    # the next epoch), we need to transition through `4 * SLOTS_PER_EPOCH` worth of slots to
    # include the processing of epoch 3."
    #
    # source: https://github.com/ethereum/trinity/pull/1214#issuecomment-546184080
    #
    # epoch | prev_justified_checkpoint | cur_justified_checkpoint | finalized_checkpoint
    # ------|---------------------------|--------------------------|---------------------
    # 0     | 0                         | 0                        | 0
    # 1     | 0                         | 0                        | 0
    # 2     | 0                         | 0                        | 0
    # 3     | 0                         | 2                        | 0
    # 4     | 2                         | 3                        | 2
    assert state.previous_justified_checkpoint.epoch == 2 + genesis_epoch
    assert state.current_justified_checkpoint.epoch == 3 + genesis_epoch
    assert state.finalized_checkpoint.epoch == 2 + genesis_epoch