def test_process_voluntary_exits(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, success): state = genesis_state.copy(slot=get_epoch_start_slot( config.GENESIS_EPOCH + config.PERSISTENT_COMMITTEE_PERIOD, config.SLOTS_PER_EPOCH, ), ) validator_index = 0 validator = state.validators[validator_index].copy( activation_epoch=config.GENESIS_EPOCH, ) state = state.update_validator(validator_index, validator) valid_voluntary_exit = create_mock_voluntary_exit( state, config, keymap, validator_index, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(valid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) new_state = process_voluntary_exits( state, block, config, ) updated_validator = new_state.validators[validator_index] assert updated_validator.exit_epoch != FAR_FUTURE_EPOCH assert updated_validator.exit_epoch > state.current_epoch( config.SLOTS_PER_EPOCH) assert updated_validator.withdrawable_epoch == ( updated_validator.exit_epoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY) else: invalid_voluntary_exit = valid_voluntary_exit.copy( signature=b'\x12' * 96, # Put wrong signature ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(invalid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_voluntary_exits( state, block, config, )
def test_process_attester_slashings(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, min_attestation_inclusion_delay, success): attesting_state = genesis_state.copy( slot=genesis_state.slot + config.SLOTS_PER_EPOCH, block_roots=tuple( i.to_bytes(32, "little") for i in range(config.SLOTS_PER_HISTORICAL_ROOT))) valid_attester_slashing = create_mock_attester_slashing_is_double_vote( attesting_state, config, keymap, attestation_epoch=0, ) state = attesting_state.copy(slot=attesting_state.slot + min_attestation_inclusion_delay, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( attester_slashings=(valid_attester_slashing, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) attester_index = valid_attester_slashing.attestation_1.custody_bit_0_indices[ 0] new_state = process_attester_slashings( state, block, config, ) # Check if slashed assert not state.validators[attester_index].slashed assert new_state.validators[attester_index].slashed else: invalid_attester_slashing = valid_attester_slashing.copy( attestation_2=valid_attester_slashing.attestation_2.copy( data=valid_attester_slashing.attestation_1.data, )) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( attester_slashings=(invalid_attester_slashing, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_attester_slashings( state, block, config, )
def test_process_attester_slashings(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, min_attestation_inclusion_delay, success): attesting_state = genesis_state.copy(slot=genesis_state.slot + config.SLOTS_PER_EPOCH, ) valid_attester_slashing = create_mock_attester_slashing_is_double_vote( attesting_state, config, keymap, attestation_epoch=0, ) state = attesting_state.copy(slot=attesting_state.slot + min_attestation_inclusion_delay, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( attester_slashings=(valid_attester_slashing, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) attester_index = valid_attester_slashing.slashable_attestation_1.validator_indices[ 0] new_state = process_attester_slashings( state, block, config, ) # Check if slashed assert (new_state.validator_balances[attester_index] < state.validator_balances[attester_index]) else: invalid_attester_slashing = valid_attester_slashing.copy( slashable_attestation_2=valid_attester_slashing. slashable_attestation_2.copy( data=valid_attester_slashing.slashable_attestation_1.data, )) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( attester_slashings=(invalid_attester_slashing, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_attester_slashings( state, block, config, )
def test_block_body_empty(sample_attestation_params): block_body = BeaconBlockBody() assert block_body.proposer_slashings == () assert block_body.attester_slashings == () assert block_body.attestations == () assert block_body.deposits == () assert block_body.voluntary_exits == () assert block_body.is_empty block_body = block_body.copy(attestations=(Attestation( **sample_attestation_params), )) assert not block_body.is_empty
def test_process_voluntary_exits( genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, success, ): state = genesis_state.set( "slot", compute_start_slot_at_epoch( config.GENESIS_EPOCH + config.PERSISTENT_COMMITTEE_PERIOD, config.SLOTS_PER_EPOCH, ), ) validator_index = 0 validator = state.validators[validator_index].set("activation_epoch", config.GENESIS_EPOCH) state = state.transform(["validators", validator_index], validator) valid_voluntary_exit = create_mock_voluntary_exit(state, config, keymap, validator_index) if success: block_body = BeaconBlockBody.create( **sample_beacon_block_body_params).set("voluntary_exits", (valid_voluntary_exit, )) block = SerenityBeaconBlock.create(**sample_beacon_block_params).mset( "slot", state.slot, "body", block_body) new_state = process_voluntary_exits(state, block, config) updated_validator = new_state.validators[validator_index] assert updated_validator.exit_epoch != FAR_FUTURE_EPOCH assert updated_validator.exit_epoch > state.current_epoch( config.SLOTS_PER_EPOCH) assert updated_validator.withdrawable_epoch == ( updated_validator.exit_epoch + config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY) else: invalid_voluntary_exit = valid_voluntary_exit.set( "signature", b"\x12" * 96 # Put wrong signature ) block_body = BeaconBlockBody.create( **sample_beacon_block_body_params).set("voluntary_exits", (invalid_voluntary_exit, )) block = SerenityBeaconBlock.create(**sample_beacon_block_params).mset( "slot", state.slot, "body", block_body) with pytest.raises(ValidationError): process_voluntary_exits(state, block, config)
def test_process_voluntary_exits(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, success): state = genesis_state.copy(slot=get_epoch_start_slot( config.GENESIS_EPOCH + config.PERSISTENT_COMMITTEE_PERIOD, config.SLOTS_PER_EPOCH, ), ) validator_index = 0 validator = state.validator_registry[validator_index].copy( activation_epoch=config.GENESIS_EPOCH, ) state = state.update_validator_registry(validator_index, validator) valid_voluntary_exit = create_mock_voluntary_exit( state, config, keymap, validator_index, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(valid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) new_state = process_voluntary_exits( state, block, config, ) # Check if initiated exit assert (new_state.validator_registry[validator_index].initiated_exit) else: invalid_voluntary_exit = valid_voluntary_exit.copy( signature=b'\x12' * 96, # Put wrong signature ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(invalid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_voluntary_exits( state, block, config, )
def test_process_attester_slashings( genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, min_attestation_inclusion_delay, success, ): attesting_state = genesis_state.mset( "slot", genesis_state.slot + config.SLOTS_PER_EPOCH, "block_roots", tuple( i.to_bytes(32, "little") for i in range(config.SLOTS_PER_HISTORICAL_ROOT)), ) valid_attester_slashing = create_mock_attester_slashing_is_double_vote( attesting_state, config, keymap, attestation_epoch=0) state = attesting_state.set( "slot", attesting_state.slot + min_attestation_inclusion_delay) if success: block_body = BeaconBlockBody.create( **sample_beacon_block_body_params).set("attester_slashings", (valid_attester_slashing, )) block = SerenityBeaconBlock.create(**sample_beacon_block_params).mset( "slot", state.slot, "body", block_body) attester_index = valid_attester_slashing.attestation_1.attesting_indices[ 0] new_state = process_attester_slashings(state, block, config) # Check if slashed assert not state.validators[attester_index].slashed assert new_state.validators[attester_index].slashed else: invalid_attester_slashing = valid_attester_slashing.transform( ["attestation_2", "data"], valid_attester_slashing.attestation_1.data) block_body = BeaconBlockBody.create( **sample_beacon_block_body_params).set( "attester_slashings", (invalid_attester_slashing, )) block = SerenityBeaconBlock.create(**sample_beacon_block_params).mset( "slot", state.slot, "body", block_body) with pytest.raises(ValidationError): process_attester_slashings(state, block, config)
def test_process_eth1_data(original_votes, block_data, expected_votes, sample_beacon_state_params, sample_beacon_block_params, sample_beacon_block_body_params): eth1_data_votes = tuple( Eth1DataVote(data, vote_count) for data, vote_count in original_votes ) state = BeaconState(**sample_beacon_state_params).copy( eth1_data_votes=eth1_data_votes, ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( eth1_data=block_data, ) block = BeaconBlock(**sample_beacon_block_params).copy( body=block_body, ) updated_state = process_eth1_data(state, block) updated_votes = tuple( (vote.eth1_data, vote.vote_count) for vote in updated_state.eth1_data_votes ) assert updated_votes == expected_votes
def test_process_max_attestations(genesis_state, genesis_block, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap): attestation_slot = config.GENESIS_SLOT current_slot = attestation_slot + config.MIN_ATTESTATION_INCLUSION_DELAY state = genesis_state.copy(slot=current_slot, ) attestations = create_mock_signed_attestations_at_slot( state=state, config=config, attestation_slot=attestation_slot, beacon_block_root=genesis_block.root, keymap=keymap, voted_attesters_ratio=1.0, ) attestations_count = len(attestations) assert attestations_count > 0 block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( attestations=attestations * (attestations_count // config.MAX_ATTESTATIONS + 1), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=current_slot, body=block_body, ) with pytest.raises(ValidationError): process_attestations( state, block, config, )
def sample_beacon_block_params(sample_beacon_block_body_params): return { "slot": GENESIS_SLOT + 10, "parent_root": ZERO_HASH32, "state_root": b"\x55" * 32, "body": BeaconBlockBody.create(**sample_beacon_block_body_params), }
def test_ensure_update_eth1_vote_if_exists(genesis_state, config, vote_offsets): # one less than a majority is the majority divided by 2 threshold = config.SLOTS_PER_ETH1_VOTING_PERIOD // 2 data_votes = tuple( concat((Eth1Data.create(block_hash=(i).to_bytes(32, "little")), ) * (threshold + offset) for i, offset in enumerate(vote_offsets))) state = genesis_state for vote in data_votes: state = process_eth1_data( state, BeaconBlock.create(body=BeaconBlockBody.create(eth1_data=vote)), config, ) if not vote_offsets: assert state.eth1_data == genesis_state.eth1_data # we should update the 'latest' entry if we have a majority for offset in vote_offsets: if offset <= 0: assert genesis_state.eth1_data == state.eth1_data else: assert state.eth1_data == data_votes[0]
def test_process_eth1_data(original_votes, block_data, expected_votes, sample_beacon_state_params, sample_beacon_block_params, sample_beacon_block_body_params, config): eth1_data_votes = tuple(mapcat( _expand_eth1_votes, original_votes, )) state = BeaconState(**sample_beacon_state_params).copy( eth1_data_votes=eth1_data_votes, ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( eth1_data=Eth1Data( block_hash=block_data, ), ) block = BeaconBlock(**sample_beacon_block_params).copy( body=block_body, ) updated_state = process_eth1_data(state, block, config) updated_votes = updated_state.eth1_data_votes expanded_expected_votes = tuple(mapcat( _expand_eth1_votes, expected_votes, )) assert updated_votes == expanded_expected_votes
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 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 run_with( cls, inputs: Tuple[BeaconState, OperationOrBlockHeader], config: Optional[Eth2Config], ) -> BeaconState: state, operation = inputs # NOTE: we do not have an easy way to evaluate a single operation on the state # So, we wrap it in a beacon block. The following statement lets us rely on # the config given in a particular handler class while working w/in the # update API provided by `py-ssz`. # NOTE: we ignore the type here, otherwise need to spell out each of the keyword # arguments individually... save some work and just build them dynamically block = BeaconBlock( body=BeaconBlockBody(**{f"{cls.name}s": ( operation, )}) # type: ignore ) try: return cls.processor(state, block, config) except ValidationError as e: # if already a ValidationError, re-raise raise e except Exception as e: # check if the exception is expected... for exception in cls.expected_exceptions: if isinstance(e, exception): raise ValidationError(e) # else raise (and fail the pytest test case ...) raise e
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_randao_processing_validates_randao_reveal( sample_beacon_block_params, sample_beacon_block_body_params, sample_beacon_state_params, sample_fork_params, keymap, config, ): proposer_pubkey, proposer_privkey = first(keymap.items()) state = SerenityBeaconState.create(**sample_beacon_state_params).mset( "validators", tuple( create_mock_validator(proposer_pubkey, config) for _ in range(config.TARGET_COMMITTEE_SIZE)), "balances", (config.MAX_EFFECTIVE_BALANCE, ) * config.TARGET_COMMITTEE_SIZE, "randao_mixes", tuple(ZERO_HASH32 for _ in range(config.EPOCHS_PER_HISTORICAL_VECTOR)), ) epoch = state.current_epoch(config.SLOTS_PER_EPOCH) message_hash = (epoch + 1).to_bytes(32, byteorder="little") domain = get_domain(state, SignatureDomain.DOMAIN_RANDAO, config.SLOTS_PER_EPOCH) randao_reveal = bls.sign(message_hash, proposer_privkey, domain) block_body = BeaconBlockBody.create(**sample_beacon_block_body_params).set( "randao_reveal", randao_reveal) block = SerenityBeaconBlock.create(**sample_beacon_block_params).set( "body", block_body) with pytest.raises(ValidationError): process_randao(state, block, config)
async def test_get_blocks_from_canonical_chain_by_slot( monkeypatch, db_block_slots, slot_of_requested_blocks, expected_block_slots ): node = NodeFactory() # Mock up block database mock_slot_to_block_db = { slot: BeaconBlock( slot=slot, parent_root=ZERO_HASH32, state_root=ZERO_HASH32, signature=EMPTY_SIGNATURE, body=BeaconBlockBody(), ) for slot in db_block_slots } def get_canonical_block_by_slot(slot): if slot in mock_slot_to_block_db: return mock_slot_to_block_db[slot] else: raise BlockNotFound monkeypatch.setattr( node.chain, "get_canonical_block_by_slot", get_canonical_block_by_slot ) result_blocks = node._get_blocks_from_canonical_chain_by_slot( slot_of_requested_blocks=slot_of_requested_blocks ) expected_blocks = [mock_slot_to_block_db[slot] for slot in expected_block_slots] assert len(result_blocks) == len(expected_blocks) assert set(result_blocks) == set(expected_blocks)
def test_process_eth1_data( original_votes, block_data, expected_votes, sample_beacon_state_params, sample_beacon_block_params, sample_beacon_block_body_params, config, ): eth1_data_votes = tuple(mapcat(_expand_eth1_votes, original_votes)) state = BeaconState.create(**sample_beacon_state_params).set( "eth1_data_votes", eth1_data_votes) block_body = BeaconBlockBody.create( **sample_beacon_block_body_params).mset( "eth1_data", Eth1Data.create(block_hash=block_data)) block = BeaconBlock.create(**sample_beacon_block_params).set( "body", block_body) updated_state = process_eth1_data(state, block, config) updated_votes = updated_state.eth1_data_votes expanded_expected_votes = tuple(mapcat(_expand_eth1_votes, expected_votes)) assert tuple(updated_votes) == expanded_expected_votes
def sample_beacon_block_params(sample_beacon_block_body_params, genesis_slot): return { "slot": genesis_slot + 10, "parent_root": ZERO_HASH32, "state_root": b"\x55" * 32, "body": BeaconBlockBody.create(**sample_beacon_block_body_params), }
def sample_beacon_block_params(sample_beacon_block_body_params, genesis_slot): return { 'slot': genesis_slot + 10, 'previous_block_root': ZERO_HASH32, 'state_root': b'\x55' * 32, 'signature': SAMPLE_SIGNATURE, 'body': BeaconBlockBody(**sample_beacon_block_body_params) }
async def _get_block_proposal(self, request: web.Request) -> web.Response: slot = Slot(int(request.query["slot"])) randao_reveal = BLSSignature( decode_hex(request.query["randao_reveal"]).ljust(96, b"\x00")) block = BeaconBlock.create( slot=slot, body=BeaconBlockBody.create(randao_reveal=randao_reveal)) return web.json_response(to_formatted_dict(block))
def test_process_attestations(genesis_state, genesis_block, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, fixture_sm_class, chaindb, empty_attestation_pool, success): attestation_slot = 0 current_slot = attestation_slot + config.MIN_ATTESTATION_INCLUSION_DELAY state = genesis_state.copy(slot=current_slot, ) attestations = create_mock_signed_attestations_at_slot( state=state, config=config, state_machine=fixture_sm_class( chaindb, empty_attestation_pool, genesis_block.slot, ), attestation_slot=attestation_slot, beacon_block_root=genesis_block.signing_root, keymap=keymap, voted_attesters_ratio=1.0, ) assert len(attestations) > 0 if not success: # create invalid attestation by shard # i.e. wrong parent invalid_attestation_data = attestations[-1].data.copy( crosslink=attestations[-1].data.crosslink.copy( parent_root=Crosslink(shard=333, ).root, )) invalid_attestation = attestations[-1].copy( data=invalid_attestation_data, ) attestations = attestations[:-1] + (invalid_attestation, ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( attestations=attestations, ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=current_slot, body=block_body, ) if success: new_state = process_attestations( state, block, config, ) assert len(new_state.current_epoch_attestations) == len(attestations) else: with pytest.raises(ValidationError): process_attestations( state, block, config, )
def test_process_voluntary_exits(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, min_attestation_inclusion_delay, success): state = genesis_state validator_index = 0 valid_voluntary_exit = create_mock_voluntary_exit( state, config, keymap, validator_index, ) if success: block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(valid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) new_state = process_voluntary_exits( state, block, config, ) # Check if initiated exit assert (new_state.validator_registry[validator_index].initiated_exit) else: invalid_voluntary_exit = valid_voluntary_exit.copy( signature=b'\x12' * 96, # Put wrong signature ) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( voluntary_exits=(invalid_voluntary_exit, ), ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=state.slot, body=block_body, ) with pytest.raises(ValidationError): process_voluntary_exits( state, block, config, )
def sample_beacon_block_params(sample_signature, sample_beacon_block_body_params, genesis_slot): return { 'slot': genesis_slot + 10, 'parent_root': ZERO_HASH32, 'state_root': b'\x55' * 32, 'body': BeaconBlockBody(**sample_beacon_block_body_params), 'signature': sample_signature, }
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 sample_beacon_block_params(sample_beacon_block_body_params): return { 'slot': 10, 'parent_root': ZERO_HASH32, 'state_root': b'\x55' * 32, 'randao_reveal': b'\x55' * 32, 'candidate_pow_receipt_root': b'\x55' * 32, 'signature': (0, 0), 'body': BeaconBlockBody(**sample_beacon_block_body_params) }
def sample_beacon_block_params(sample_beacon_block_body_params, sample_eth1_data_params): return { 'slot': 10, 'parent_root': ZERO_HASH32, 'state_root': b'\x55' * 32, 'randao_reveal': EMPTY_SIGNATURE, 'eth1_data': Eth1Data(**sample_eth1_data_params), 'signature': EMPTY_SIGNATURE, 'body': BeaconBlockBody(**sample_beacon_block_body_params) }
def empty_body(): return BeaconBlockBody( proposer_slashings=(), casper_slashings=(), attestations=(), custody_reseeds=(), custody_challenges=(), custody_responses=(), deposits=(), exits=(), )
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