Exemplo n.º 1
0
def get_consensus_state_for_block_id(block_id, block_cache, state_view_factory,
                                     consensus_state_store,
                                     poet_enclave_module):
    """Returns the consensus state for the block referenced by block ID,
        creating it from the consensus state history if necessary.

    Args:
        block_id (str): The ID of the block for which consensus state will
            be returned.
        block_cache (BlockCache): The block store cache
        state_view_factory (StateViewFactory): A factory that can be used
            to create state view object corresponding to blocks
        consensus_state_store (ConsensusStateStore): The consensus state
            store
        poet_enclave_module (module): The PoET enclave module

    Returns:
        ConsensusState object representing the consensus state for the block
            referenced by block_id
    """

    consensus_state = None
    previous_wait_certificate = None
    blocks = collections.OrderedDict()

    # Starting at the chain head, walk the block store backwards until we
    # either get to the root or we get a block for which we have already
    # created consensus state
    while True:
        block = _block_for_id(block_id=block_id, block_cache=block_cache)
        if block is None:
            break

        # Try to fetch the consensus state.  If that succeeds, we can
        # stop walking back as we can now build on that consensus
        # state.
        consensus_state = consensus_state_store.get(block_id=block_id)
        if consensus_state is not None:
            break

        wait_certificate = \
            deserialize_wait_certificate(
                block=block,
                poet_enclave_module=poet_enclave_module)

        # If this is a PoET block (i.e., it has a wait certificate), get the
        # validator info for the validator that signed this block and add the
        # block information we will need to set validator state in the block's
        # consensus state.
        if wait_certificate is not None:
            state_view = \
                state_view_factory.create_view(
                    state_root_hash=block.state_root_hash)
            validator_registry_view = \
                ValidatorRegistryView(state_view=state_view)
            validator_info = \
                validator_registry_view.get_validator_info(
                    validator_id=block.header.signer_pubkey)

            LOGGER.debug('We need to build consensus state for block: %s...%s',
                         block_id[:8], block_id[-8:])

            blocks[block_id] = \
                BlockInfo(
                    wait_certificate=wait_certificate,
                    validator_info=validator_info)

        # Otherwise, this is a non-PoET block.  If we don't have any blocks
        # yet or the last block we processed was a PoET block, put a
        # placeholder in the list so that when we get to it we know that we
        # need to reset the statistics.
        elif len(blocks) == 0 or previous_wait_certificate is not None:
            blocks[block_id] = \
                BlockInfo(
                    wait_certificate=None,
                    validator_info=None)

        previous_wait_certificate = wait_certificate

        # Move to the previous block
        block_id = block.previous_block_id

    # At this point, if we have not found any consensus state, we need to
    # create default state from which we can build upon
    if consensus_state is None:
        consensus_state = ConsensusState()

    # Now, walk through the blocks for which we were supposed to create
    # consensus state, from oldest to newest (i.e., in the reverse order in
    # which they were added), and store state for PoET blocks so that the next
    # time we don't have to walk so far back through the block chain.
    for block_id, block_info in reversed(blocks.items()):
        # If the block was not a PoET block (i.e., didn't have a wait
        # certificate), reset the consensus state statistics.  We are not
        # going to store this in the consensus state store, but we will use it
        # as the starting for the next PoET block.
        if block_info.wait_certificate is None:
            consensus_state = ConsensusState()

        # Otherwise, update the consensus state statistics and fetch the
        # validator state for the validator which claimed the block, create
        # updated validator state for the validator, set/update the validator
        # state in the consensus state object, and then associate the
        # consensus state with the corresponding block in the consensus state
        # store.
        else:
            validator_state = \
                get_current_validator_state(
                    validator_info=block_info.validator_info,
                    consensus_state=consensus_state,
                    block_cache=block_cache)
            consensus_state.set_validator_state(
                validator_id=block_info.validator_info.id,
                validator_state=create_next_validator_state(
                    validator_info=block_info.validator_info,
                    current_validator_state=validator_state,
                    block_cache=block_cache))

            LOGGER.debug('Store consensus state for block: %s...%s',
                         block_id[:8], block_id[-8:])

            consensus_state.total_block_claim_count += 1
            consensus_state_store[block_id] = consensus_state

    return consensus_state
Exemplo n.º 2
0
def get_consensus_state_for_block_id(block_id, block_cache, state_view_factory,
                                     consensus_state_store,
                                     poet_enclave_module):
    """Returns the consensus state for the block referenced by block ID,
        creating it from the consensus state history if necessary.

    Args:
        block_id (str): The ID of the block for which consensus state will
            be returned.
        block_cache (BlockCache): The block store cache
        state_view_factory (StateViewFactory): A factory that can be used
            to create state view object corresponding to blocks
        consensus_state_store (ConsensusStateStore): The consensus state
            store
        poet_enclave_module (module): The PoET enclave module

    Returns:
        ConsensusState object representing the consensus state for the block
            referenced by block_id
    """

    # Starting at the chain head, walk the block store backwards until we
    # either get to the root or we get a block for which we have already
    # created consensus state
    block = \
        block_cache[block_id] if block_id != NULL_BLOCK_IDENTIFIER else None
    consensus_state = None
    block_ids = collections.deque()

    while block is not None:
        # Try to fetch the consensus state.  If that succeeds, we can
        # stop walking back as we can now build on that consensus
        # state.
        consensus_state = consensus_state_store.get(block.identifier)
        if consensus_state is not None:
            break

        # If this is a PoET block, then we want to create consensus state
        # for it when we are done
        if deserialize_wait_certificate(block, poet_enclave_module):
            LOGGER.debug(
                'We need to build consensus state for block ID %s...%s',
                block.identifier[:8], block.identifier[-8:])
            block_ids.appendleft(block.identifier)

        # Move to the previous block
        block = \
            block_cache[block.previous_block_id] \
            if block.previous_block_id != NULL_BLOCK_IDENTIFIER else None

    # If didn't find any consensus state, see if there is any "before" any
    # blocks were created (this might be because we are the first validator
    # and PoET signup information was created, including sealed signup data
    # that was saved in the consensus state store).
    if consensus_state is None:
        consensus_state = consensus_state_store.get(NULL_BLOCK_IDENTIFIER)

    # At this point, if we have not found any consensus state, we need to
    # create default state from which we can build upon
    if consensus_state is None:
        consensus_state = ConsensusState()

    # Now, walking forward through the blocks for which we were supposed to
    # create consensus state, we are going to create and store state for each
    # one so that the next time we don't have to walk so far back through the
    # block chain.
    for identifier in block_ids:
        block = block_cache[identifier]

        # Get the validator registry view for this block's state view and
        # then fetch the validator info for the validator that signed this
        # block.
        state_view = state_view_factory.create_view(block.state_root_hash)
        validator_registry_view = ValidatorRegistryView(state_view)

        validator_id = block.header.signer_pubkey
        validator_info = \
            validator_registry_view.get_validator_info(
                validator_id=validator_id)

        # Fetch the current validator state, set/update the validator state
        # in the consensus state object, and then create the consensus state
        # in the consensus state store and associate it with this block
        validator_state = \
            consensus_state.get_validator_state(validator_id=validator_id)
        consensus_state.set_validator_state(
            validator_id=validator_id,
            validator_state=create_validator_state(
                validator_info=validator_info,
                current_validator_state=validator_state))

        LOGGER.debug('Store consensus state for block ID %s...%s',
                     identifier[:8], identifier[-8:])

        consensus_state_store[identifier] = consensus_state

    return consensus_state