def test_get_beacon_proposer_index(monkeypatch, num_validators, slots_per_epoch, committee, slot, registry_change, success, sample_state, genesis_epoch, target_committee_size, shard_count, committee_config): from eth2.beacon import committee_helpers def mock_get_crosslink_committees_at_slot(state, slot, committee_config, registry_change=False): return (( committee, 1, ), ) monkeypatch.setattr(committee_helpers, 'get_crosslink_committees_at_slot', mock_get_crosslink_committees_at_slot) if success: proposer_index = get_beacon_proposer_index( sample_state, slot, committee_config, registry_change=registry_change, ) assert proposer_index == committee[slot % len(committee)] else: with pytest.raises(ValidationError): get_beacon_proposer_index( sample_state, slot, committee_config, registry_change=registry_change, )
def process_attestations(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: if len(block.body.attestations) > config.MAX_ATTESTATIONS: raise ValidationError( f"The block has too many attestations:\n" f"\tFound {len(block.body.attestations)} attestations, " f"maximum: {config.MAX_ATTESTATIONS}") current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) current_epoch_attestations = state.current_epoch_attestations previous_epoch_attestations = state.previous_epoch_attestations for attestation in block.body.attestations: validate_attestation(state, attestation, config) proposer_index = get_beacon_proposer_index(state, config) pending_attestation = PendingAttestation.create( aggregation_bits=attestation.aggregation_bits, data=attestation.data, inclusion_delay=state.slot - attestation.data.slot, proposer_index=proposer_index, ) if attestation.data.target.epoch == current_epoch: current_epoch_attestations = current_epoch_attestations.append( pending_attestation) else: previous_epoch_attestations = previous_epoch_attestations.append( pending_attestation) return state.mset( "current_epoch_attestations", current_epoch_attestations, "previous_epoch_attestations", previous_epoch_attestations, )
def is_proposer(state: BeaconState, validator_index: ValidatorIndex, config: Eth2Config) -> bool: """ Return if the validator is proposer of `state.slot`. """ return get_beacon_proposer_index( state, CommitteeConfig(config)) == validator_index
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 validate_proposer_is_not_slashed(state: BeaconState, block_root: Hash32, config: CommitteeConfig) -> None: proposer_index = get_beacon_proposer_index(state, config) proposer = state.validators[proposer_index] if proposer.slashed: raise ValidationError( f"Proposer for block {encode_hex(block_root)} is slashed")
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock, committee_config: CommitteeConfig) -> None: message_hash = block.signing_root # Get the public key of proposer beacon_proposer_index = get_beacon_proposer_index( state, committee_config, ) proposer_pubkey = state.validators[beacon_proposer_index].pubkey domain = get_domain( state, SignatureDomain.DOMAIN_BEACON_PROPOSER, committee_config.SLOTS_PER_EPOCH, ) try: bls.validate( pubkey=proposer_pubkey, message_hash=message_hash, signature=block.signature, domain=domain, ) except SignatureError as error: raise ValidationError( f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}", error, )
def process_randao(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: proposer_index = get_beacon_proposer_index( state=state, slot=state.slot, committee_config=CommitteeConfig(config), ) proposer = state.validator_registry[proposer_index] epoch = state.current_epoch(config.SLOTS_PER_EPOCH) validate_randao_reveal( randao_reveal=block.randao_reveal, proposer_index=proposer_index, proposer_pubkey=proposer.pubkey, epoch=epoch, fork=state.fork, ) randao_mix_index = epoch % config.LATEST_RANDAO_MIXES_LENGTH new_randao_mix = bitwise_xor( get_randao_mix( state=state, epoch=epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), hash_eth2(block.randao_reveal), ) return state.copy(latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, randao_mix_index, new_randao_mix, ), )
def process_attestations(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: if len(block.body.attestations) > config.MAX_ATTESTATIONS: raise ValidationError( f"The block has too many attestations:\n" f"\tFound {len(block.body.attestations)} attestations, " f"maximum: {config.MAX_ATTESTATIONS}") current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) new_current_epoch_attestations: Tuple[PendingAttestation, ...] = tuple() new_previous_epoch_attestations: Tuple[PendingAttestation, ...] = tuple() for attestation in block.body.attestations: validate_attestation(state, attestation, config) proposer_index = get_beacon_proposer_index(state, CommitteeConfig(config)) pending_attestation = PendingAttestation( aggregation_bits=attestation.aggregation_bits, data=attestation.data, inclusion_delay=state.slot - attestation.data.slot, proposer_index=proposer_index, ) if attestation.data.target.epoch == current_epoch: new_current_epoch_attestations += (pending_attestation, ) else: new_previous_epoch_attestations += (pending_attestation, ) return state.copy( current_epoch_attestations=(state.current_epoch_attestations + new_current_epoch_attestations), previous_epoch_attestations=(state.previous_epoch_attestations + new_previous_epoch_attestations), )
def _get_proposer_index(state: BeaconState, config: Eth2Config) -> ValidatorIndex: proposer_index = get_beacon_proposer_index( state, CommitteeConfig(config), ) return proposer_index
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock, beacon_chain_shard_number: Shard, committee_config: CommitteeConfig) -> None: # TODO: Replace this with real signed_root message_hash = block.signed_root # Get the public key of proposer beacon_proposer_index = get_beacon_proposer_index( state, state.slot, committee_config, ) proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey domain = get_domain( state.fork, state.current_epoch(committee_config.SLOTS_PER_EPOCH), SignatureDomain.DOMAIN_BEACON_BLOCK ) is_valid_signature = bls.verify( pubkey=proposer_pubkey, message_hash=message_hash, signature=block.signature, domain=domain, ) if not is_valid_signature: raise ValidationError( f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}, " f"pubkey={proposer_pubkey}, message_hash={message_hash}, " f"block.signature={block.signature}, domain={domain}" )
def test_get_beacon_proposer_index(genesis_state, config): # TODO(hwwhww) find a way to normalize validator effective balance distribution. state = genesis_state validators = tuple([ state.validators[index].set("effective_balance", config.MAX_EFFECTIVE_BALANCE) for index in range(len(state.validators)) ]) for slot in range(0, config.SLOTS_PER_EPOCH): state = state.mset("slot", slot, "validators", validators) proposer_index = get_beacon_proposer_index(state, config) assert proposer_index current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) domain_type = signature_domain_to_domain_type( SignatureDomain.DOMAIN_BEACON_PROPOSER) seed = hash_eth2( get_seed(state, current_epoch, domain_type, config) + state.slot.to_bytes(8, "little")) random_byte = hash_eth2(seed + (proposer_index // 32).to_bytes(8, "little"))[proposer_index % 32] # Verify if proposer_index matches the condition. assert (state.validators[proposer_index].effective_balance * MAX_RANDOM_BYTE >= config.MAX_EFFECTIVE_BALANCE * random_byte)
def validate_proposer_index(state: BeaconState, config: Eth2Config, slot: Slot, validator_index: ValidatorIndex) -> None: beacon_proposer_index = get_beacon_proposer_index(state.copy(slot=slot), config) if validator_index != beacon_proposer_index: raise ProposerIndexError
def process_randao(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: proposer_index = get_beacon_proposer_index( state=state, committee_config=CommitteeConfig(config)) epoch = state.current_epoch(config.SLOTS_PER_EPOCH) validate_randao_reveal( state=state, proposer_index=proposer_index, epoch=epoch, randao_reveal=block.body.randao_reveal, slots_per_epoch=config.SLOTS_PER_EPOCH, ) randao_mix_index = epoch % config.EPOCHS_PER_HISTORICAL_VECTOR new_randao_mix = bitwise_xor( get_randao_mix( state=state, epoch=epoch, epochs_per_historical_vector=config.EPOCHS_PER_HISTORICAL_VECTOR, ), hash_eth2(block.body.randao_reveal), ) return state.transform(("randao_mixes", randao_mix_index), new_randao_mix)
def validate_proposer_signature(state: BeaconState, block: BaseBeaconBlock, beacon_chain_shard_number: ShardNumber, committee_config: CommitteeConfig) -> None: block_without_signature_root = block.block_without_signature_root # TODO: Replace this root with tree hash root proposal_root = ProposalSignedData( state.slot, beacon_chain_shard_number, block_without_signature_root, ).root # Get the public key of proposer beacon_proposer_index = get_beacon_proposer_index( state, state.slot, committee_config, ) proposer_pubkey = state.validator_registry[beacon_proposer_index].pubkey domain = get_domain(state.fork, state.current_epoch(committee_config.EPOCH_LENGTH), SignatureDomain.DOMAIN_PROPOSAL) is_valid_signature = bls.verify( pubkey=proposer_pubkey, message=proposal_root, signature=block.signature, domain=domain, ) if not is_valid_signature: raise ValidationError( f"Invalid Proposer Signature on block, beacon_proposer_index={beacon_proposer_index}, " f"pubkey={proposer_pubkey}, message={proposal_root}," f"block.signature={block.signature}, domain={domain}")
def process_transfers(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: if len(block.body.transfers) > config.MAX_TRANSFERS: raise ValidationError( f"The block ({block}) has too many transfers:\n" f"\tFound {len(block.body.transfers)} transfers, " f"maximum: {config.MAX_TRANSFERS}") for transfer in block.body.transfers: validate_transfer( state, transfer, config, ) state = decrease_balance( state, transfer.sender, transfer.amount + transfer.fee, ) state = increase_balance( state, transfer.recipient, transfer.amount, ) state = increase_balance( state, get_beacon_proposer_index( state, CommitteeConfig(config), ), transfer.fee, ) return state
def create_mock_block( *, state: BeaconState, config: Eth2Config, state_machine: BaseBeaconStateMachine, signed_block_class: Type[BaseSignedBeaconBlock], parent_block: BaseSignedBeaconBlock, keymap: Dict[BLSPubkey, int], slot: Slot = None, attestations: Sequence[Attestation] = (), ) -> BaseSignedBeaconBlock: """ Create a mocking block at ``slot`` with the given block parameters and ``keymap``. Note that it doesn't return the correct ``state_root``. """ future_state = advance_to_slot(state_machine, state, slot) proposer_index = get_beacon_proposer_index(future_state, config) proposer_pubkey = state.validators[proposer_index].pubkey proposer_privkey = keymap[proposer_pubkey] result_block = create_block_on_state( state=future_state, config=config, state_machine=state_machine, signed_block_class=signed_block_class, parent_block=parent_block, slot=slot, validator_index=proposer_index, privkey=proposer_privkey, attestations=attestations, check_proposer_index=False, ) return result_block
def test_get_state_by_slot(valid_chain, genesis_block, genesis_state, keymap): # First, skip block and check if `get_state_by_slot` returns the expected state state_machine = valid_chain.get_state_machine(genesis_block.slot) config = state_machine.config state = valid_chain.get_head_state() block_skipped_slot = genesis_block.slot + 1 block_skipped_state, _ = state_machine.apply_state_transition( state, future_slot=block_skipped_slot) valid_chain.chaindb.persist_state(block_skipped_state) with pytest.raises(StateNotFound): valid_chain.get_state_by_slot(block_skipped_slot) # Next, import proposed block and check if `get_state_by_slot` returns the expected state proposed_slot = block_skipped_slot + 1 future_state, _ = state_machine.apply_state_transition( block_skipped_state, future_slot=proposed_slot) proposer_index = get_beacon_proposer_index(future_state, config) proposer = block_skipped_state.validators[proposer_index].pubkey private_key = keymap[proposer] randao_reveal = generate_randao_reveal(private_key, proposed_slot, block_skipped_state, config) block = create_block( proposed_slot, genesis_block.message.hash_tree_root, randao_reveal, state.eth1_data, (), block_skipped_state, state_machine, private_key, ) valid_chain.import_block(block) state = valid_chain.get_head_state() assert (valid_chain.get_state_by_slot(proposed_slot).hash_tree_root == state.hash_tree_root)
def test_settle_penality_to_validator_and_whistleblower( monkeypatch, num_validators, committee, n_validators_state, latest_slashed_exit_length, whistleblower_reward_quotient, max_deposit_amount, committee_config): from eth2.beacon import committee_helpers def mock_get_crosslink_committees_at_slot(state, slot, committee_config, registry_change=False): return (( committee, 1, ), ) monkeypatch.setattr(committee_helpers, 'get_crosslink_committees_at_slot', mock_get_crosslink_committees_at_slot) state = n_validators_state validator_index = 5 whistleblower_index = get_beacon_proposer_index( state, state.slot, committee_config, ) effective_balance = max_deposit_amount # Check the initial balance assert (state.validator_balances[validator_index] == state.validator_balances[whistleblower_index] == effective_balance) state = _settle_penality_to_validator_and_whistleblower( state=state, validator_index=validator_index, latest_slashed_exit_length=latest_slashed_exit_length, whistleblower_reward_quotient=whistleblower_reward_quotient, max_deposit_amount=max_deposit_amount, committee_config=committee_config, ) # Check `state.latest_slashed_balances` latest_slashed_balances_list = list(state.latest_slashed_balances) last_slashed_epoch = ( state.current_epoch(committee_config.SLOTS_PER_EPOCH) % latest_slashed_exit_length) latest_slashed_balances_list[last_slashed_epoch] = max_deposit_amount latest_slashed_balances = tuple(latest_slashed_balances_list) assert state.latest_slashed_balances == latest_slashed_balances # Check penality and reward whistleblower_reward = (effective_balance // whistleblower_reward_quotient) whistleblower_balance = state.validator_balances[whistleblower_index] validator_balance = state.validator_balances[validator_index] balance_difference = whistleblower_balance - validator_balance assert balance_difference == whistleblower_reward * 2
def validate_proposer_index(state: BeaconState, config: BeaconConfig, slot: SlotNumber, validator_index: ValidatorIndex): beacon_proposer_index = get_beacon_proposer_index( state.copy(slot=slot, ), slot, CommitteeConfig(config), ) if validator_index != beacon_proposer_index: raise ProposerIndexError
def validate_proposer_index( state: BeaconState, block: BaseBeaconBlock, config: Eth2Config ) -> None: expected_proposer = get_beacon_proposer_index(state, config) if block.proposer_index != expected_proposer: raise ValidationError( f"block.proposer_index " f"({block.proposer_index}) does not equal expected_proposer ({expected_proposer}) " f"at block.slot {state.slot}" )
def test_process_proposer_slashings(genesis_state, sample_beacon_block_params, sample_beacon_block_body_params, config, keymap, block_root_1, block_root_2, success): current_slot = config.GENESIS_SLOT + 1 state = genesis_state.copy( slot=current_slot, ) whistleblower_index = get_beacon_proposer_index( state, CommitteeConfig(config), ) slashing_proposer_index = (whistleblower_index + 1) % len(state.validators) proposer_slashing = create_mock_proposer_slashing_at_block( state, config, keymap, block_root_1=block_root_1, block_root_2=block_root_2, proposer_index=slashing_proposer_index, ) proposer_slashings = (proposer_slashing,) block_body = BeaconBlockBody(**sample_beacon_block_body_params).copy( proposer_slashings=proposer_slashings, ) block = SerenityBeaconBlock(**sample_beacon_block_params).copy( slot=current_slot, body=block_body, ) if success: new_state = process_proposer_slashings( state, block, config, ) # Check if slashed assert ( new_state.balances[slashing_proposer_index] < state.balances[slashing_proposer_index] ) else: with pytest.raises(ValidationError): process_proposer_slashings( state, block, config, )
def get_committee_assignment( state: BeaconState, config: BeaconConfig, epoch: Epoch, validator_index: ValidatorIndex, registry_change: bool = False) -> CommitteeAssignment: """ Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index`` and ``registry_change``. ``CommitteeAssignment.committee`` is the tuple array of validators in the committee ``CommitteeAssignment.shard`` is the shard to which the committee is assigned ``CommitteeAssignment.slot`` is the slot at which the committee is assigned ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to propose a beacon block at the assigned slot. """ current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) next_epoch = Epoch(current_epoch + 1) validate_epoch_within_previous_and_next(epoch, previous_epoch, next_epoch) epoch_start_slot = get_epoch_start_slot(epoch, config.SLOTS_PER_EPOCH) committee_config = CommitteeConfig(config) for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH): crosslink_committees = get_crosslink_committees_at_slot( state, slot, committee_config, registry_change=registry_change, ) selected_committees = [ committee for committee in crosslink_committees if validator_index in committee[0] ] if len(selected_committees) > 0: validators = selected_committees[0][0] shard = selected_committees[0][1] is_proposer = validator_index == get_beacon_proposer_index( state, Slot(slot), committee_config, registry_change=registry_change, ) return CommitteeAssignment(validators, shard, Slot(slot), is_proposer) raise NoCommitteeAssignment
def validate_proposer_index(state: BeaconState, config: BeaconConfig, slot: SlotNumber, validator_index: ValidatorIndex): beacon_proposer_index = get_beacon_proposer_index( state.copy(slot=slot, ), slot, config.GENESIS_EPOCH, config.EPOCH_LENGTH, config.TARGET_COMMITTEE_SIZE, config.SHARD_COUNT, ) if validator_index != beacon_proposer_index: raise ProposerIndexError
def slash_validator(state: BeaconState, index: ValidatorIndex, config: Eth2Config, whistleblower_index: ValidatorIndex = None) -> BeaconState: """ Slash the validator with index ``index``. Exit the validator, penalize the validator, and reward the whistleblower. """ # NOTE: remove in phase 1 assert whistleblower_index is None slots_per_epoch = config.SLOTS_PER_EPOCH current_epoch = state.current_epoch(slots_per_epoch) state = initiate_validator_exit(state, index, config) state = state.update_validator_with_fn( index, _set_validator_slashed, current_epoch, config.EPOCHS_PER_SLASHINGS_VECTOR, ) slashed_balance = state.validators[index].effective_balance slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR state = state.copy(slashings=update_tuple_item_with_fn( state.slashings, slashed_epoch, lambda balance, slashed_balance: Gwei(balance + slashed_balance), slashed_balance, )) state = decrease_balance( state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT) proposer_index = get_beacon_proposer_index(state, CommitteeConfig(config)) if whistleblower_index is None: whistleblower_index = proposer_index whistleblower_reward = Gwei(slashed_balance // config.WHISTLEBLOWER_REWARD_QUOTIENT) proposer_reward = Gwei(whistleblower_reward // config.PROPOSER_REWARD_QUOTIENT) state = increase_balance(state, proposer_index, proposer_reward) state = increase_balance( state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward), ) return state
def get_committee_assignment( state: BeaconState, config: Eth2Config, epoch: Epoch, validator_index: ValidatorIndex, ) -> CommitteeAssignment: """ Return the ``CommitteeAssignment`` in the ``epoch`` for ``validator_index``. ``CommitteeAssignment.committee`` is the tuple array of validators in the committee ``CommitteeAssignment.shard`` is the shard to which the committee is assigned ``CommitteeAssignment.slot`` is the slot at which the committee is assigned ``CommitteeAssignment.is_proposer`` is a bool signalling if the validator is expected to propose a beacon block at the assigned slot. """ next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) if epoch > next_epoch: raise ValidationError( f"Epoch for committee assignment ({epoch}) must not be after next epoch {next_epoch}." ) active_validators = get_active_validator_indices(state.validators, epoch) committees_per_slot = ( get_committee_count( len(active_validators), config.SHARD_COUNT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ) // config.SLOTS_PER_EPOCH ) epoch_start_slot = compute_start_slot_of_epoch(epoch, config.SLOTS_PER_EPOCH) epoch_start_shard = get_start_shard(state, epoch, CommitteeConfig(config)) for slot in range(epoch_start_slot, epoch_start_slot + config.SLOTS_PER_EPOCH): offset = committees_per_slot * (slot % config.SLOTS_PER_EPOCH) slot_start_shard = (epoch_start_shard + offset) % config.SHARD_COUNT for i in range(committees_per_slot): shard = Shard((slot_start_shard + i) % config.SHARD_COUNT) committee = get_crosslink_committee( state, epoch, shard, CommitteeConfig(config) ) if validator_index in committee: is_proposer = validator_index == get_beacon_proposer_index( state.copy(slot=slot), CommitteeConfig(config) ) return CommitteeAssignment( committee, Shard(shard), Slot(slot), is_proposer ) raise NoCommitteeAssignment
def _get_proposer_index(state_machine: BaseBeaconStateMachine, state: BeaconState, slot: Slot, previous_block_root: Hash32, config: Eth2Config) -> ValidatorIndex: # advance the state to the ``slot``. state_transition = state_machine.state_transition state = state_transition.apply_state_transition_without_block( state, slot, previous_block_root) proposer_index = get_beacon_proposer_index( state, slot, CommitteeConfig(config), ) return proposer_index
def _mk_minimum_viable_signed_beacon_blocks(slots, state_machine_provider, state, block, config): for slot in slots: future_state, _ = state_machine_provider(slot).apply_state_transition( state, future_slot=block.slot + 1) proposer_index = get_beacon_proposer_index(future_state, config) message = BeaconBlock.create( slot=slot, parent_root=block.message.hash_tree_root, proposer_index=proposer_index, ) block = SignedBeaconBlock.create(message=message) state, block = state_machine_provider(slot).apply_state_transition( state, block) yield block
def slash_validator( state: BeaconState, index: ValidatorIndex, config: Eth2Config, whistleblower_index: ValidatorIndex = None, ) -> BeaconState: """ Slash the validator with index ``index``. Exit the validator, penalize the validator, and reward the whistleblower. """ # NOTE: remove in phase 1 assert whistleblower_index is None slots_per_epoch = config.SLOTS_PER_EPOCH current_epoch = state.current_epoch(slots_per_epoch) state = initiate_validator_exit(state, index, config) state = state.transform( ("validators", index), partial( _set_validator_slashed, current_epoch=current_epoch, epochs_per_slashings_vector=config.EPOCHS_PER_SLASHINGS_VECTOR, ), ) slashed_balance = state.validators[index].effective_balance slashed_epoch = current_epoch % config.EPOCHS_PER_SLASHINGS_VECTOR state = state.transform(("slashings", slashed_epoch), lambda balance: Gwei(balance + slashed_balance)) state = decrease_balance( state, index, slashed_balance // config.MIN_SLASHING_PENALTY_QUOTIENT) proposer_index = get_beacon_proposer_index(state, config) if whistleblower_index is None: whistleblower_index = proposer_index whistleblower_reward = Gwei(slashed_balance // config.WHISTLEBLOWER_REWARD_QUOTIENT) proposer_reward = Gwei(whistleblower_reward // config.PROPOSER_REWARD_QUOTIENT) state = increase_balance(state, proposer_index, proposer_reward) state = increase_balance(state, whistleblower_index, Gwei(whistleblower_reward - proposer_reward)) return state
def test_import_blocks(valid_chain, genesis_block, genesis_state, config, keymap): state = genesis_state blocks = (genesis_block, ) valid_chain_2 = copy.deepcopy(valid_chain) for _ in range(3): state_machine = valid_chain.get_state_machine(blocks[-1].slot) parent_block = blocks[-1] slot = state.slot + 2 future_state, _ = state_machine.apply_state_transition( state, future_slot=state.slot + 2) proposer_index = get_beacon_proposer_index(future_state, config) proposer = state.validators[proposer_index].pubkey private_key = keymap[proposer] randao_reveal = generate_randao_reveal(private_key, slot, state, config) block = create_block( slot, parent_block.message.hash_tree_root, randao_reveal, state.eth1_data, (), state, state_machine, private_key, ) valid_chain.import_block(block) assert valid_chain.get_canonical_head() == block state = valid_chain.get_head_state() assert block == valid_chain.get_canonical_block_by_slot(block.slot) assert block.message.hash_tree_root == valid_chain.get_canonical_block_root( block.slot) blocks += (block, ) assert valid_chain.get_canonical_head( ) != valid_chain_2.get_canonical_head() for block in blocks[1:]: valid_chain_2.import_block(block) assert valid_chain.get_canonical_head( ) == valid_chain_2.get_canonical_head() assert valid_chain.get_head_state().slot != 0 assert valid_chain.get_head_state() == valid_chain_2.get_head_state()
def _build_chain_of_blocks_with_states( chain, state, parent_block, slots, config, keymap, attestation_participation=1.0, eth1_block_hash=ZERO_HASH32, ): blocks = () states = () for slot in range(parent_block.slot + 1, parent_block.slot + 1 + slots): sm = chain.get_state_machine(state.slot) pre_state, _ = sm.apply_state_transition(state, future_slot=slot) proposer_index = get_beacon_proposer_index(pre_state, config) public_key = state.validators[proposer_index].pubkey private_key = keymap[public_key] randao_reveal = generate_randao_reveal(private_key, slot, pre_state, config) attestations = create_mock_signed_attestations_at_slot( state, config, sm, slot - 1, parent_block.hash_tree_root, keymap, voted_attesters_ratio=attestation_participation, ) block = create_block( slot, parent_block.hash_tree_root, randao_reveal, Eth1Data.create(block_hash=eth1_block_hash), attestations, state, sm, private_key, ) parent_block = block.message state, block = sm.apply_state_transition(state, block) blocks += (block, ) states += (state, ) return blocks, states