Ejemplo n.º 1
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
Ejemplo n.º 2
0
    def on_block(
        self,
        block: BaseBeaconBlock,
        post_state: BeaconState = None,
        state_machine: BaseBeaconStateMachine = None,
    ) -> None:
        """
        Handler to update the fork choice context upon receiving a new ``block``.

        This handler requests the ``post_state`` of this block to avoid recomputing
        it if it is already known.
        """
        # NOTE: this invariant should hold based on how we handle
        # block importing in the chain but we will sanity check for now
        assert block.parent_root in self._context.block_states

        pre_state = self._context.block_states[block.parent_root]

        # NOTE: this invariant should hold based on how we handle
        # block importing in the chain but we will sanity check for now
        assert (self._context.time >= pre_state.genesis_time +
                block.slot * self._config.SECONDS_PER_SLOT)

        root = block.signing_root

        self._context.blocks[root] = block

        finalized_slot = self._context.finalized_slot
        finalized_ancestor = self.get_ancestor_root(root, finalized_slot)
        is_ancestor_of_finalized_block = (
            finalized_ancestor == self._context.finalized_checkpoint.root)
        if not is_ancestor_of_finalized_block:
            raise ValidationError(
                f"block with signing root {root.hex()} is not a descendant of the finalized"
                f" checkpoint with root {finalized_ancestor.hex()}")

        # NOTE: sanity check implied by the previous verification on finalized ancestor
        assert block.slot > compute_start_slot_at_epoch(
            self._context.finalized_checkpoint.epoch,
            self._config.SLOTS_PER_EPOCH)

        if not post_state:
            # NOTE: error to not provide a post_state and not provide a way to compute it
            assert state_machine is not None
            post_state, _ = state_machine.import_block(block, pre_state)

        self._context.block_states[root] = post_state

        if (post_state.current_justified_checkpoint.epoch >
                self._context.justified_checkpoint.epoch):
            self._context.best_justified_checkpoint = (
                post_state.current_justified_checkpoint)
            if self._should_update_justified_checkpoint(
                    post_state.current_justified_checkpoint):
                self._context.justified_checkpoint = (
                    post_state.current_justified_checkpoint)

        if (post_state.finalized_checkpoint.epoch >
                self._context.finalized_checkpoint.epoch):
            self._context.finalized_checkpoint = post_state.finalized_checkpoint
Ejemplo n.º 3
0
def create_block_on_state(
        *,
        state: BeaconState,
        config: BeaconConfig,
        state_machine: BaseBeaconStateMachine,
        block_class: BaseBeaconBlock,
        parent_block: BaseBeaconBlock,
        slot: SlotNumber,
        validator_index: ValidatorIndex,
        privkey: int,
        attestations: Sequence[Attestation],
        check_proposer_index: bool = True) -> BaseBeaconBlock:
    """
    Create a beacon block with the given parameters.
    """
    # Check proposer
    if check_proposer_index:
        validate_proposer_index(state, config, slot, validator_index)

    # 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,
    )

    # Apply state transition to get state root
    state, block = state_machine.import_block(block,
                                              check_proposer_signature=True)

    # 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_to_epoch(slot, config.EPOCH_LENGTH),
        SignatureDomain.DOMAIN_PROPOSAL,
    )
    block = block.copy(signature=bls.sign(
        message=proposal_root,
        privkey=privkey,
        domain=domain,
    ), )

    return block
Ejemplo n.º 4
0
def create_block_on_state(
    *,
    state: BeaconState,
    config: Eth2Config,
    state_machine: BaseBeaconStateMachine,
    signed_block_class: Type[BaseSignedBeaconBlock],
    parent_block: BaseBeaconBlock,
    slot: Slot,
    validator_index: ValidatorIndex,
    privkey: int,
    attestations: Sequence[Attestation],
    eth1_data: Eth1Data = None,
    deposits: Sequence[Deposit] = None,
    check_proposer_index: bool = True,
) -> SignedBeaconBlock:
    """
    Create a beacon block with the given parameters.
    """
    if check_proposer_index:
        validate_proposer_index(state, config, slot, validator_index)

    block_class = signed_block_class.block_class
    block = create_unsigned_block_on_state(
        state=state,
        config=config,
        block_class=block_class,
        parent_block=parent_block.message,
        slot=slot,
        attestations=attestations,
        eth1_data=eth1_data,
        deposits=deposits,
    )

    # Randao reveal
    randao_reveal = _generate_randao_reveal(privkey, slot, state, config)
    block = block.set("body", block.body.set("randao_reveal", randao_reveal))

    # Apply state transition to get state root
    signed_block = signed_block_class.create(message=block,
                                             signature=EMPTY_SIGNATURE)
    post_state, signed_block = state_machine.import_block(
        signed_block, state, check_proposer_signature=False)

    # Sign
    signature = sign_transaction(
        message_hash=signed_block.message.hash_tree_root,
        privkey=privkey,
        state=post_state,
        slot=slot,
        signature_domain=SignatureDomain.DOMAIN_BEACON_PROPOSER,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )
    signed_block = signed_block.set("signature", signature)

    return signed_block
Ejemplo n.º 5
0
def create_block_on_state(
        *,
        state: BeaconState,
        config: Eth2Config,
        state_machine: BaseBeaconStateMachine,
        block_class: Type[BaseBeaconBlock],
        parent_block: BaseBeaconBlock,
        slot: Slot,
        validator_index: ValidatorIndex,
        privkey: int,
        attestations: Sequence[Attestation],
        check_proposer_index: bool = True) -> BaseBeaconBlock:
    """
    Create a beacon block with the given parameters.
    """
    # Check proposer
    if check_proposer_index:
        validate_proposer_index(state, config, slot, validator_index)

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

    # TODO: Add more operations
    randao_reveal = _generate_randao_reveal(privkey, slot, state.fork, config)
    eth1_data = Eth1Data.create_empty_data()
    body = BeaconBlockBody.create_empty_body().copy(
        randao_reveal=randao_reveal,
        eth1_data=eth1_data,
        attestations=attestations,
    )

    block = block.copy(body=body, )

    # Apply state transition to get state root
    state, block = state_machine.import_block(block,
                                              check_proposer_signature=False)

    # Sign
    # TODO make sure we use the correct signed_root
    signature = sign_transaction(
        message_hash=block.signed_root,
        privkey=privkey,
        fork=state.fork,
        slot=slot,
        signature_domain=SignatureDomain.DOMAIN_BEACON_BLOCK,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )

    block = block.copy(signature=signature, )

    return block
Ejemplo n.º 6
0
def create_block_on_state(
        *,
        state: BeaconState,
        config: Eth2Config,
        state_machine: BaseBeaconStateMachine,
        block_class: Type[BaseBeaconBlock],
        parent_block: BaseBeaconBlock,
        slot: Slot,
        validator_index: ValidatorIndex,
        privkey: int,
        attestations: Sequence[Attestation],
        check_proposer_index: bool = True) -> BaseBeaconBlock:
    """
    Create a beacon block with the given parameters.
    """
    if check_proposer_index:
        validate_proposer_index(state, config, slot, validator_index)

    block = block_class.from_parent(parent_block=parent_block,
                                    block_params=FromBlockParams(slot=slot))

    # MAX_ATTESTATIONS
    attestations = attestations[:config.MAX_ATTESTATIONS]

    # TODO: Add more operations
    randao_reveal = _generate_randao_reveal(privkey, slot, state, config)
    eth1_data = state.eth1_data
    body = BeaconBlockBody.create(randao_reveal=randao_reveal,
                                  eth1_data=eth1_data,
                                  attestations=attestations)

    block = block.set("body", body)

    # Apply state transition to get state root
    state, block = state_machine.import_block(block,
                                              state,
                                              check_proposer_signature=False)

    # Sign
    signature = sign_transaction(
        message_hash=block.signing_root,
        privkey=privkey,
        state=state,
        slot=slot,
        signature_domain=SignatureDomain.DOMAIN_BEACON_PROPOSER,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )

    block = block.set("signature", signature)

    return block
Ejemplo n.º 7
0
 def skip_block(
     self, slot: Slot, state: BeaconState, state_machine: BaseBeaconStateMachine
 ) -> BeaconState:
     """
     Forward state to the target ``slot`` and persist the state.
     """
     post_state, _ = state_machine.apply_state_transition(state, future_slot=slot)
     self.logger.debug(
         bold_green("Skip block at slot=%s  post_state=%s"), slot, repr(post_state)
     )
     # FIXME: We might not need to persist state for skip slots since `create_block_on_state`
     # will run the state transition which also includes the state transition for skipped slots.
     self.chain.chaindb.persist_state(post_state)
     self.chain.chaindb.update_head_state(post_state.slot, post_state.hash_tree_root)
     return post_state
Ejemplo n.º 8
0
def create_block_proposal(
    slot: Slot,
    parent_root: Root,
    randao_reveal: BLSSignature,
    eth1_data: Eth1Data,
    state: BeaconState,
    state_machine: BaseBeaconStateMachine,
) -> BeaconBlock:
    proposal = BeaconBlock.create(
        slot=slot,
        parent_root=parent_root,
        body=BeaconBlockBody.create(randao_reveal=randao_reveal, eth1_data=eth1_data),
    )
    signed_block = SignedBeaconBlock.create(message=proposal, signature=EMPTY_SIGNATURE)
    post_state, signed_block = state_machine.import_block(
        signed_block, state, check_proposer_signature=False
    )
    return signed_block.message
Ejemplo n.º 9
0
def create_signed_attestations_at_slot(
    state: BeaconState,
    config: Eth2Config,
    state_machine: BaseBeaconStateMachine,
    attestation_slot: Slot,
    beacon_block_root: Root,
    validator_privkeys: Dict[ValidatorIndex, int],
    committee: Tuple[ValidatorIndex, ...],
    committee_index: CommitteeIndex,
    attesting_indices: Sequence[CommitteeValidatorIndex],
) -> Iterable[Attestation]:
    """
    Create the attestations of the given ``attestation_slot`` slot with ``validator_privkeys``.
    """
    state, _ = state_machine.apply_state_transition(
        state, future_slot=attestation_slot)

    attestation_data = create_atteatsion_data(
        state,
        config,
        state_machine,
        attestation_slot,
        beacon_block_root,
        committee_index,
    )

    validator_indices = tuple(validator_privkeys)
    for index, committee_validator_index in enumerate(attesting_indices):
        validator_index = validator_indices[index]
        yield _create_mock_signed_attestation(
            state,
            attestation_data,
            attestation_slot,
            committee,
            len(committee),
            {
                state.validators[validator_index].pubkey:
                validator_privkeys[validator_index]
            },
            config.SLOTS_PER_EPOCH,
            is_for_simulation=False,
            attesting_indices=(committee_validator_index, ),
        )
Ejemplo n.º 10
0
def run_validate_block_proposer_signature(
        state: BeaconState, state_machine: BaseBeaconStateMachine,
        block: BaseSignedBeaconBlock) -> None:
    # Fast forward to state in future slot in order to pass
    # block.slot validity check
    try:
        future_state, _ = state_machine.apply_state_transition(
            state,
            future_slot=block.slot,
        )
    except ValidationError as error:
        raise InvalidGossipMessage(
            f"Failed to fast forward to state at slot={block.slot}",
            error,
        )

    try:
        validate_proposer_signature(future_state, block, state_machine.config)
    except ValidationError as error:
        raise InvalidGossipMessage(
            f"Failed to validate block={encode_hex(block.message.hash_tree_root)}",
            error,
        )
Ejemplo n.º 11
0
def create_block_on_state(
        *,
        state: BeaconState,
        config: BeaconConfig,
        state_machine: BaseBeaconStateMachine,
        block_class: Type[BaseBeaconBlock],
        parent_block: BaseBeaconBlock,
        slot: Slot,
        validator_index: ValidatorIndex,
        privkey: int,
        attestations: Sequence[Attestation],
        check_proposer_index: bool = True) -> BaseBeaconBlock:
    """
    Create a beacon block with the given parameters.
    """
    # Check proposer
    if check_proposer_index:
        validate_proposer_index(state, config, slot, validator_index)

    # 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 = EMPTY_SIGNATURE
    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,
    )

    # Apply state transition to get state root
    state, block = state_machine.import_block(block,
                                              check_proposer_signature=False)

    # Sign
    empty_signature_block_root = block.block_without_signature_root
    proposal_root = Proposal(
        slot,
        config.BEACON_CHAIN_SHARD_NUMBER,
        empty_signature_block_root,
    ).root

    signature = sign_transaction(
        message_hash=proposal_root,
        privkey=privkey,
        fork=state.fork,
        slot=slot,
        signature_domain=SignatureDomain.DOMAIN_PROPOSAL,
        slots_per_epoch=config.SLOTS_PER_EPOCH,
    )

    block = block.copy(signature=signature, )

    return block