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