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 test_canonical_chain(valid_chain, genesis_slot, fork_choice_scoring): genesis_block = valid_chain.get_canonical_block_by_slot(genesis_slot) # Our chain fixture is created with only the genesis header, so initially that's the head of # the canonical chain. assert valid_chain.get_canonical_head() == genesis_block # verify a special case (score(genesis) == 0) assert valid_chain.get_score( genesis_block.message.hash_tree_root) == fork_choice_scoring.score( genesis_block.message) block = SerenitySignedBeaconBlock.from_parent(genesis_block, FromBlockParams(slot=1)) valid_chain.chaindb.persist_block(block, block.__class__, fork_choice_scoring) assert valid_chain.get_canonical_head() == block state_machine = valid_chain.get_state_machine(block.slot) scoring = state_machine.get_fork_choice_scoring() assert valid_chain.get_score( block.message.hash_tree_root) == scoring.score(block.message) assert scoring.score(block.message) != 0 canonical_block_1 = valid_chain.get_canonical_block_by_slot( genesis_block.slot + 1) assert canonical_block_1 == block result_block = valid_chain.get_block_by_root(block.message.hash_tree_root) assert result_block == block
def test_chaindb_get_score(chaindb, fixture_sm_class, genesis_block, fork_choice_scoring): chaindb.persist_block(genesis_block, genesis_block.__class__, fork_choice_scoring) genesis_score_key = SchemaV1.make_block_root_to_score_lookup_key( genesis_block.message.hash_tree_root) genesis_score_data = chaindb.db.get(genesis_score_key) genesis_score_class = fork_choice_scoring.get_score_class() genesis_score = genesis_score_class.deserialize(genesis_score_data) expected_genesis_score = fork_choice_scoring.score(genesis_block.message) assert genesis_score == expected_genesis_score assert (chaindb.get_score(genesis_block.message.hash_tree_root, genesis_score_class) == expected_genesis_score) block1 = SignedBeaconBlock.from_parent(genesis_block, FromBlockParams(slot=1)) chaindb.persist_block(block1, block1.__class__, fork_choice_scoring) block1_score_key = SchemaV1.make_block_root_to_score_lookup_key( block1.message.hash_tree_root) block1_score_data = chaindb.db.get(block1_score_key) block1_score = genesis_score_class.deserialize(block1_score_data) expected_block1_score = fork_choice_scoring.score(block1.message) assert block1_score == expected_block1_score assert (chaindb.get_score(block1.message.hash_tree_root, genesis_score_class) == expected_block1_score)
def create_unsigned_block_on_state( *, state: BeaconState, config: Eth2Config, block_class: Type[BaseBeaconBlock], parent_block: BaseBeaconBlock, slot: Slot, attestations: Sequence[Attestation], eth1_data: Eth1Data = None, deposits: Sequence[Deposit] = None, check_proposer_index: bool = True, ) -> BeaconBlock: """ Create a beacon block with the given parameters. """ 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 if eth1_data is None: eth1_data = state.eth1_data body = BeaconBlockBody.create(eth1_data=eth1_data, attestations=attestations) if deposits is not None and len(deposits) > 0: body = body.set("deposits", deposits) block = block.set("body", body) return block
def test_block_is_not_genesis(): genesis_block = SignedBeaconBlock.create().transform( ("message", "parent_root"), GENESIS_PARENT_ROOT) another_block = SignedBeaconBlock.from_parent(genesis_block, FromBlockParams()) assert genesis_block.is_genesis assert not another_block.is_genesis
def create_block_on_state(state: BeaconState, config: BeaconConfig, block_class: BaseBeaconBlock, parent_block: BaseBeaconBlock, slot: SlotNumber, validator_index: int, privkey: int, attestations: Sequence[Attestation]): """ Create a beacon block with the given parameters. """ # Check proposer beacon_proposer_index = get_beacon_proposer_index( state.copy(slot=slot, ), slot, config.EPOCH_LENGTH, config.TARGET_COMMITTEE_SIZE, config.SHARD_COUNT, ) if validator_index != beacon_proposer_index: raise ProposerIndexError # 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, ) # 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, SignatureDomain.DOMAIN_PROPOSAL, ) block = block.copy(signature=bls.sign( message=proposal_root, privkey=privkey, domain=domain, ), ) return block
def get_pseudo_chain(length, genesis_block): """ Get a pseudo chain, only slot and parent_root are valid. """ block = genesis_block yield genesis_block for slot in range(1, length * 3): block = SignedBeaconBlock.from_parent(block, FromBlockParams(slot=slot)) yield block
def __init__(self, chaindb: BaseBeaconChainDB, block: BaseBeaconBlock, parent_block_class: Type[BaseBeaconBlock]) -> None: self.chaindb = chaindb self.block = self.get_block_class().from_parent( parent_block=self.chaindb.get_block_by_root(block.parent_root, parent_block_class), block_params=FromBlockParams(slot=block.slot), )
def ensure_block(self, block: BaseBeaconBlock=None) -> BaseBeaconBlock: """ Return ``block`` if it is not ``None``, otherwise return the block of the canonical head. """ if block is None: head = self.get_canonical_head() return self.create_block_from_parent(head, FromBlockParams()) else: return block
def block_with_attestation(chaindb, genesis_block, sample_attestation_params, fork_choice_scoring): sample_attestation = Attestation.create(**sample_attestation_params) chaindb.persist_block(genesis_block, genesis_block.__class__, fork_choice_scoring) block1 = SignedBeaconBlock.from_parent( genesis_block, FromBlockParams(slot=1)).transform( ("message", "body", "attestations"), (sample_attestation, )) return block1, sample_attestation
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 test_chaindb_get_canonical_head(chaindb, block, fork_choice_scoring): chaindb.persist_block(block, block.__class__, fork_choice_scoring) canonical_head_root = chaindb.get_canonical_head_root() assert canonical_head_root == block.message.hash_tree_root result_block = chaindb.get_canonical_head(block.__class__) assert result_block == block block_2 = SignedBeaconBlock.from_parent( block, FromBlockParams(slot=block.message.slot + 1)) chaindb.persist_block(block_2, block_2.__class__, fork_choice_scoring) result_block = chaindb.get_canonical_head(block.__class__) assert result_block == block_2 block_3 = SignedBeaconBlock.from_parent( block_2, FromBlockParams(slot=block_2.message.slot + 1)) chaindb.persist_block(block_3, block_3.__class__, fork_choice_scoring) result_block = chaindb.get_canonical_head(block.__class__) assert result_block == block_3
def import_block( self, block: BaseBeaconBlock, perform_validation: bool=True ) -> Tuple[BaseBeaconBlock, Tuple[BaseBeaconBlock, ...], Tuple[BaseBeaconBlock, ...]]: """ Import a complete block and returns a 3-tuple - the imported block - a tuple of blocks which are now part of the canonical chain. - a tuple of blocks which are were canonical and now are no longer canonical. """ try: parent_block = self.get_block_by_root(block.parent_root) except BlockNotFound: raise ValidationError( "Attempt to import block #{}. Cannot import block {} before importing " "its parent block at {}".format( block.slot, block.hash, block.parent_root, ) ) base_block_for_import = self.create_block_from_parent( parent_block, FromBlockParams(), ) state, imported_block = self.get_state_machine( base_block_for_import, ).import_block(block) # TODO: Now it just persit all state. Should design how to clean up the old state. self.chaindb.persist_state(state) # Validate the imported block. if perform_validation: validate_imported_block_unchanged(imported_block, block) ( new_canonical_blocks, old_canonical_blocks, ) = self.chaindb.persist_block(imported_block, imported_block.__class__) self.logger.debug( 'IMPORTED_BLOCK: slot %s | hash %s', imported_block.slot, encode_hex(imported_block.hash), ) return imported_block, new_canonical_blocks, old_canonical_blocks
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 get_blocks( chain: BaseBeaconChain, parent_block: SerenityBeaconBlock = None, num_blocks: int = 3, ) -> Tuple[SerenityBeaconBlock, ...]: if parent_block is None: parent_block = chain.get_canonical_head() blocks = [] for _ in range(num_blocks): block = chain.create_block_from_parent(parent_block=parent_block, block_params=FromBlockParams()) blocks.append(block) parent_block = block return tuple(blocks)
def get_blocks(receive_server: BCCReceiveServer, parent_block: SerenityBeaconBlock = None, num_blocks: int = 3) -> Tuple[SerenityBeaconBlock, ...]: chain = receive_server.chain if parent_block is None: parent_block = chain.get_canonical_head() blocks = [] for _ in range(num_blocks): block = chain.create_block_from_parent( parent_block=parent_block, block_params=FromBlockParams(), ) blocks.append(block) parent_block = block return tuple(blocks)
def test_chaindb_get_finalized_head( chaindb_at_genesis, genesis_block, genesis_state, sample_beacon_block_params, fork_choice_scoring, ): chaindb = chaindb_at_genesis block = SignedBeaconBlock.from_parent(genesis_block, FromBlockParams(slot=1)) assert chaindb.get_finalized_head(genesis_block.__class__) == genesis_block assert chaindb.get_justified_head(genesis_block.__class__) == genesis_block state_with_finalized_block = genesis_state.set( "finalized_checkpoint", Checkpoint.create(root=block.signing_root)) chaindb.persist_state(state_with_finalized_block) chaindb.persist_block(block, SignedBeaconBlock, fork_choice_scoring) assert (chaindb.get_finalized_head(SignedBeaconBlock).signing_root == block.signing_root) assert chaindb.get_justified_head(genesis_block.__class__) == genesis_block
def test_chaindb_get_justified_head( chaindb_at_genesis, genesis_block, genesis_state, sample_beacon_block_params, fork_choice_scoring, config, ): chaindb = chaindb_at_genesis block = SignedBeaconBlock.from_parent(genesis_block, FromBlockParams(slot=1)) assert chaindb.get_finalized_head(genesis_block.__class__) == genesis_block assert chaindb.get_justified_head(genesis_block.__class__) == genesis_block # test that there is only one justified head per epoch state_with_bad_epoch = genesis_state.set( "current_justified_checkpoint", Checkpoint.create(root=block.message.hash_tree_root, epoch=config.GENESIS_EPOCH), ) chaindb.persist_state(state_with_bad_epoch) chaindb.persist_block(block, SignedBeaconBlock, fork_choice_scoring) assert chaindb.get_finalized_head(genesis_block.__class__) == genesis_block assert chaindb.get_justified_head(genesis_block.__class__) == genesis_block # test that the we can update justified head if we satisfy the invariants state_with_justified_block = genesis_state.set( "current_justified_checkpoint", Checkpoint.create(root=block.message.hash_tree_root, epoch=config.GENESIS_EPOCH + 1), ) chaindb.persist_state(state_with_justified_block) assert chaindb.get_finalized_head(genesis_block.__class__) == genesis_block assert (chaindb.get_justified_head(SignedBeaconBlock).message. hash_tree_root == block.message.hash_tree_root)
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
def test_block_is_not_genesis(sample_beacon_block_params): genesis_block = BeaconBlock(**sample_beacon_block_params) another_block = BeaconBlock.from_parent(genesis_block, FromBlockParams()) assert genesis_block.is_genesis assert not another_block.is_genesis