예제 #1
0
 def _get_fork_choice_context(self) -> LMDGHOSTContext:
     try:
         fork_choice_context_data = self.chain_db.get_fork_choice_context_data_for(
             self.fork)
     except MissingForkChoiceContext:
         # NOTE: ``MissingForkChoiceContext`` here implies that we are missing the
         # fork choice context for this fork, which happens to be the genesis fork.
         # In this situation (possibly uniquely), we want to build a new
         # fork choice context from the genesis data.
         genesis_root = self.chain_db.get_genesis_block_root()
         genesis_block = self.chain_db.get_block_by_root(
             genesis_root, self.block_class)
         genesis_state = self.chain_db.get_state_by_root(
             genesis_block.message.state_root, self.state_class)
         return LMDGHOSTContext.from_genesis(genesis_state, genesis_block)
     else:
         return LMDGHOSTContext.from_bytes(fork_choice_context_data)
예제 #2
0
def genesis_fork_choice_context(genesis_state, genesis_block):
    return LMDGHOSTContext.from_genesis(genesis_state, genesis_block)
예제 #3
0
def test_lmd_ghost_fork_choice_scoring(
    sample_beacon_block_params,
    chaindb_at_genesis,
    # see note below on how this is used
    fork_choice_scoring,
    forking_descriptor,
    forking_asymmetry,
    genesis_state,
    genesis_block,
    config,
):
    """
    Given some blocks and some attestations, can we score them correctly?
    """
    chain_db = chaindb_at_genesis
    root_block = chain_db.get_canonical_head(SignedBeaconBlock)

    some_epoch = 3
    some_slot_offset = 10

    state = genesis_state.mset(
        "slot",
        compute_start_slot_at_epoch(some_epoch, config.SLOTS_PER_EPOCH) +
        some_slot_offset,
        "current_justified_checkpoint",
        Checkpoint.create(epoch=some_epoch,
                          root=root_block.message.hash_tree_root),
    )
    assert some_epoch >= state.current_justified_checkpoint.epoch

    # NOTE: the attestations have to be aligned to the blocks which start from ``base_slot``.
    base_slot = compute_start_slot_at_epoch(some_epoch,
                                            config.SLOTS_PER_EPOCH) + 1
    block_tree = _build_block_tree(
        sample_beacon_block_params,
        root_block,
        base_slot,
        forking_descriptor,
        forking_asymmetry,
        config,
    )

    slot_count = len(forking_descriptor)
    committee_sampling_fraction = 1
    committees_by_slot = tuple(
        _get_committees(state, base_slot +
                        slot_offset, config, committee_sampling_fraction)
        for slot_offset in range(slot_count))

    _attach_committees_to_block_tree(state, block_tree, committees_by_slot,
                                     config, forking_asymmetry)

    _attach_attestations_to_block_tree_with_committees(block_tree, config)

    context = Context.from_genesis(genesis_state, genesis_block)
    store = Store(chain_db, SignedBeaconBlock, config, context)

    score_index = _build_score_index_from_decorated_block_tree(
        block_tree, store, state, config)

    for block in _iter_block_tree_by_block(block_tree):
        # NOTE: we use the ``fork_choice_scoring`` fixture, it doesn't matter for this test
        chain_db.persist_block(block, SignedBeaconBlock, fork_choice_scoring)

    for block in _iter_block_tree_by_block(block_tree):
        score = store.scoring(block)
        expected_score = score_index[block.message.hash_tree_root]
        assert score == expected_score
예제 #4
0
def test_store_get_latest_attestation(genesis_state, genesis_block, config,
                                      collisions_from_another_epoch):
    """
    Given some attestations across the various sources, can we
    find the latest ones for each validator?
    """
    some_epoch = 3
    state = genesis_state.set(
        "slot", compute_start_slot_at_epoch(some_epoch,
                                            config.SLOTS_PER_EPOCH))
    some_time = (_compute_seconds_since_genesis_for_epoch(some_epoch, config) +
                 state.genesis_time)
    previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH,
                                          config.GENESIS_EPOCH)
    previous_epoch_committee_count = _get_committee_count(
        state, previous_epoch, config)

    current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH)
    current_epoch_committee_count = _get_committee_count(
        state, current_epoch, config)
    number_of_committee_samples = 4

    assert number_of_committee_samples <= previous_epoch_committee_count
    assert number_of_committee_samples <= current_epoch_committee_count

    block_producer = _mk_block_at_slot(genesis_block)

    # prepare samples from previous epoch
    previous_epoch_attestations_by_index = _mk_attestations_for_epoch_by_count(
        number_of_committee_samples, previous_epoch, block_producer, state,
        config)
    previous_epoch_attestations = _extract_attestations_from_index_keying(
        previous_epoch_attestations_by_index.values())

    # prepare samples from current epoch
    current_epoch_attestations_by_index = _mk_attestations_for_epoch_by_count(
        number_of_committee_samples, current_epoch, block_producer, state,
        config)
    current_epoch_attestations_by_index = keyfilter(
        lambda index: index not in previous_epoch_attestations_by_index,
        current_epoch_attestations_by_index,
    )
    current_epoch_attestations = _extract_attestations_from_index_keying(
        current_epoch_attestations_by_index.values())

    pool_attestations_by_index = _mk_attestations_for_epoch_by_count(
        number_of_committee_samples, current_epoch, block_producer, state,
        config)
    pool_attestations_by_index = keyfilter(
        lambda index: (index not in previous_epoch_attestations_by_index or
                       index not in current_epoch_attestations_by_index),
        pool_attestations_by_index,
    )
    pool_attestations = _extract_attestations_from_index_keying(
        pool_attestations_by_index.values())

    all_attestations_by_index = (
        previous_epoch_attestations_by_index,
        current_epoch_attestations_by_index,
        pool_attestations_by_index,
    )

    if collisions_from_another_epoch:
        (
            previous_epoch_attestations_by_index,
            current_epoch_attestations_by_index,
            pool_attestations_by_index,
        ) = _introduce_collisions(all_attestations_by_index, block_producer,
                                  state, config)

        previous_epoch_attestations = _extract_attestations_from_index_keying(
            previous_epoch_attestations_by_index.values())
        current_epoch_attestations = _extract_attestations_from_index_keying(
            current_epoch_attestations_by_index.values())
        pool_attestations = _extract_attestations_from_index_keying(
            pool_attestations_by_index.values())

    # build expected results
    expected_index = merge_with(
        _keep_by_latest_slot,
        previous_epoch_attestations_by_index,
        current_epoch_attestations_by_index,
        pool_attestations_by_index,
    )

    chain_db = None  # not relevant for this test
    context = Context.from_genesis(genesis_state, genesis_block)
    context.time = some_time
    store = Store(chain_db, SignedBeaconBlock, config, context)

    for attestations in (
            previous_epoch_attestations,
            current_epoch_attestations,
            pool_attestations,
    ):
        for attestation in attestations:
            # NOTE: we need to synchronize the context w/ chain data used to construct
            # attestations above; this synchronization takes advantage of some of the
            # internals of ``on_attestation`` to shortcut constructing the complete network
            # state needed to test the function of the ``Store``.
            block = block_producer(attestation.data.slot)
            context.blocks[block.message.hash_tree_root] = block
            context.block_states[block.message.hash_tree_root] = genesis_state

            store.on_attestation(attestation, validate_signature=False)

    # sanity check
    assert expected_index.keys() == store._context.latest_messages.keys()

    for validator_index in range(len(state.validators)):
        expected_attestation_data = expected_index.get(validator_index, None)
        target = expected_attestation_data.target
        expected_message = LatestMessage(epoch=target.epoch, root=target.root)
        stored_message = store._context.latest_messages.get(
            validator_index, None)
        assert expected_message == stored_message