def _churn_validators(state: BeaconState, config: BeaconConfig, check_should_churn_fn: Callable[..., Any], churn_fn: Callable[..., Any], max_balance_churn: int) -> BeaconState: """ Churn the validators. The number of the churning validators is based on the given ``max_balance_churn``. :param check_should_churn_fn: the funcation to determine if the validator should be churn :param churn_fn``: the function to churn the validators; it could be ``activate_validator`` or ``exit_validator`` """ balance_churn = 0 for index in range(len(state.validator_registry)): index = ValidatorIndex(index) should_churn = check_should_churn_fn( state, index, ) if should_churn: # Check the balance churn would be within the allowance balance_churn += get_effective_balance( state.validator_balances, index, config.MAX_DEPOSIT_AMOUNT, ) if balance_churn > max_balance_churn: break state = churn_fn(state, index) return state
def test_get_effective_balance(balance, max_deposit_amount, expected, sample_validator_record_params): balances = (balance,) result = get_effective_balance(balances, 0, max_deposit_amount) assert result == expected
def get_total_attesting_balance( *, state: 'BeaconState', shard: ShardNumber, shard_block_root: Hash32, attestations: Sequence[PendingAttestationRecord], genesis_epoch: EpochNumber, epoch_length: int, max_deposit_amount: Gwei, target_committee_size: int, shard_count: int) -> Gwei: return Gwei( sum( get_effective_balance(state.validator_balances, i, max_deposit_amount) for i in get_attesting_validator_indices( state=state, attestations=attestations, shard=shard, shard_block_root=shard_block_root, genesis_epoch=genesis_epoch, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count, ) ) )
def get_base_reward(*, state: 'BeaconState', index: ValidatorIndex, base_reward_quotient: int, max_deposit_amount: Gwei) -> Gwei: return Gwei( get_effective_balance( state.validator_balances, index, max_deposit_amount, ) // base_reward_quotient // 5)
def _settle_penality_to_validator_and_whistleblower( *, state: BeaconState, validator_index: ValidatorIndex, latest_penalized_exit_length: int, whistleblower_reward_quotient: int, epoch_length: int, max_deposit: Ether) -> BeaconState: """ Apply penality/reward to validator and whistleblower and update the meta data More intuitive pseudo-code: current_epoch_penalization_index = (state.slot // EPOCH_LENGTH) % LATEST_PENALIZED_EXIT_LENGTH state.latest_penalized_exit_balances[current_epoch_penalization_index] += ( get_effective_balance(state, index) ) whistleblower_index = get_beacon_proposer_index(state, state.slot) whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT state.validator_balances[whistleblower_index] += whistleblower_reward state.validator_balances[index] -= whistleblower_reward validator.penalized_slot = state.slot """ # Update `state.latest_penalized_exit_balances` current_epoch_penalization_index = ( state.slot // epoch_length) % latest_penalized_exit_length effective_balance = get_effective_balance( state.validator_balances, validator_index, max_deposit, ) penalized_exit_balance = ( state.latest_penalized_exit_balances[current_epoch_penalization_index] + effective_balance) latest_penalized_exit_balances = update_tuple_item( tuple_data=state.latest_penalized_exit_balances, index=current_epoch_penalization_index, new_value=penalized_exit_balance, ) state = state.copy( latest_penalized_exit_balances=latest_penalized_exit_balances, ) # Update whistleblower's balance whistleblower_reward = (effective_balance // whistleblower_reward_quotient) whistleblower_index = get_beacon_proposer_index(state, state.slot, epoch_length) state = state.update_validator_balance( whistleblower_index, state.validator_balances[whistleblower_index] + whistleblower_reward, ) # Update validator's balance and `penalized_slot` field validator = state.validator_registry[validator_index] validator = validator.copy(penalized_slot=state.slot, ) state = state.update_validator( validator_index, validator, state.validator_balances[validator_index] - whistleblower_reward, ) return state
def get_base_reward(*, state: 'BeaconState', index: ValidatorIndex, base_reward_quotient: int, previous_total_balance: Gwei, max_deposit_amount: Gwei) -> Gwei: if previous_total_balance == 0: return Gwei(0) adjusted_quotient = (integer_squareroot(previous_total_balance) // base_reward_quotient) return Gwei( get_effective_balance( state.validator_balances, index, max_deposit_amount, ) // adjusted_quotient // 5)
def _compute_individual_penalty(state: BeaconState, config: BeaconConfig, validator_index: ValidatorIndex, total_penalties: Gwei, total_balance: Gwei) -> Gwei: effective_balance = get_effective_balance( state.validator_balances, validator_index, config.MAX_DEPOSIT_AMOUNT, ) return Gwei( max( effective_balance * min(total_penalties * 3, total_balance) // total_balance, effective_balance // config.MIN_PENALTY_QUOTIENT, ))
def get_total_attesting_balance( *, state: 'BeaconState', shard: ShardNumber, shard_block_root: Hash32, attestations: Sequence[PendingAttestationRecord], max_deposit_amount: Gwei, committee_config: CommitteeConfig) -> Gwei: return Gwei( sum( get_effective_balance(state.validator_balances, i, max_deposit_amount) for i in get_attesting_validator_indices( state=state, attestations=attestations, shard=shard, shard_block_root=shard_block_root, committee_config=committee_config, ) ) )
def process_slashings(state: BeaconState, config: BeaconConfig) -> BeaconState: """ Process the slashings. """ latest_slashed_exit_length = config.LATEST_SLASHED_EXIT_LENGTH max_deposit_amount = config.MAX_DEPOSIT_AMOUNT current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) active_validator_indices = get_active_validator_indices( state.validator_registry, current_epoch) total_balance = Gwei( sum( get_effective_balance(state.validator_balances, i, max_deposit_amount) for i in active_validator_indices)) total_penalties = _compute_total_penalties( state, config, current_epoch, ) for validator_index, validator in enumerate(state.validator_registry): validator_index = ValidatorIndex(validator_index) is_halfway_to_withdrawable_epoch = ( current_epoch == validator.withdrawable_epoch - latest_slashed_exit_length // 2) if validator.slashed and is_halfway_to_withdrawable_epoch: penalty = _compute_individual_penalty( state=state, config=config, validator_index=validator_index, total_penalties=total_penalties, total_balance=total_balance, ) state = state.update_validator_balance( validator_index=validator_index, balance=state.validator_balances[validator_index] - penalty, ) return state
def test_get_winning_root_and_participants( random, monkeypatch, target_committee_size, block_root_1_participants, block_root_2_participants, config, committee_config, n_validators_state, sample_attestation_data_params, sample_attestation_params): shard = 1 committee = tuple([i for i in range(target_committee_size)]) from eth2.beacon import committee_helpers def mock_get_crosslink_committees_at_slot(state, slot, committee_config, registry_change=False): return (( committee, shard, ), ) monkeypatch.setattr(committee_helpers, 'get_crosslink_committees_at_slot', mock_get_crosslink_committees_at_slot) competing_block_roots = [ hash_eth2(bytearray(random.getrandbits(8) for _ in range(10))), hash_eth2(bytearray(random.getrandbits(8) for _ in range(10))) ] # Generate bitfield of each participants set root_1_participants_bitfield = get_aggregation_bitfield( block_root_1_participants, target_committee_size, ) root_2_participants_bitfield = get_aggregation_bitfield( block_root_2_participants, target_committee_size, ) # `attestions` contains attestation to different block root by different set of participants attestations = ( # Attestation to `crosslink_data_root_1` by `attestation_participants_1` Attestation(**sample_attestation_params).copy( aggregation_bitfield=root_1_participants_bitfield, data=AttestationData(**sample_attestation_data_params).copy( shard=shard, previous_crosslink=CrosslinkRecord( epoch=config.GENESIS_EPOCH, crosslink_data_root=ZERO_HASH32, ), crosslink_data_root=competing_block_roots[0], ), ), # Attestation to `crosslink_data_root_2` by `attestation_participants_2` Attestation(**sample_attestation_params).copy( aggregation_bitfield=root_2_participants_bitfield, data=AttestationData(**sample_attestation_data_params).copy( shard=shard, previous_crosslink=CrosslinkRecord( epoch=config.GENESIS_EPOCH, crosslink_data_root=ZERO_HASH32, ), crosslink_data_root=competing_block_roots[1], ), ), ) state = n_validators_state.copy(previous_epoch_attestations=attestations, ) effective_balances = { index: get_effective_balance( state.validator_balances, index, config.MAX_DEPOSIT_AMOUNT, ) for index in range(len(state.validator_registry)) } winning_root, attesting_validator_indices = get_winning_root_and_participants( state=state, shard=shard, effective_balances=effective_balances, committee_config=committee_config, ) if len(attesting_validator_indices) == 0: assert len(block_root_1_participants) == 0 and len( block_root_2_participants) == 0 else: if len(block_root_1_participants) == len(block_root_2_participants): if competing_block_roots[0] > competing_block_roots[1]: assert winning_root == competing_block_roots[0] assert set(attesting_validator_indices) == set( block_root_1_participants) else: assert winning_root == competing_block_roots[1] assert set(attesting_validator_indices) == set( block_root_2_participants) elif len(block_root_1_participants) < len(block_root_2_participants): assert winning_root == competing_block_roots[1] assert set(attesting_validator_indices) == set( block_root_2_participants) else: assert winning_root == competing_block_roots[0] assert set(attesting_validator_indices) == set( block_root_1_participants)
def _settle_penality_to_validator_and_whistleblower( *, state: BeaconState, validator_index: ValidatorIndex, latest_slashed_exit_length: int, whistleblower_reward_quotient: int, max_deposit_amount: Gwei, committee_config: CommitteeConfig) -> BeaconState: """ Apply penality/reward to validator and whistleblower and update the meta data More intuitive pseudo-code: current_epoch_penalization_index = (state.slot // SLOTS_PER_EPOCH) % LATEST_SLASHED_EXIT_LENGTH state.latest_slashed_balances[current_epoch_penalization_index] += ( get_effective_balance(state, index) ) whistleblower_index = get_beacon_proposer_index(state, state.slot) whistleblower_reward = get_effective_balance(state, index) // WHISTLEBLOWER_REWARD_QUOTIENT state.validator_balances[whistleblower_index] += whistleblower_reward state.validator_balances[index] -= whistleblower_reward validator.slashed = True validator.withdrawable_epoch = get_current_epoch(state) + LATEST_SLASHED_EXIT_LENGTH """ slots_per_epoch = committee_config.SLOTS_PER_EPOCH # Update `state.latest_slashed_balances` current_epoch_penalization_index = state.current_epoch( slots_per_epoch) % latest_slashed_exit_length effective_balance = get_effective_balance( state.validator_balances, validator_index, max_deposit_amount, ) slashed_exit_balance = ( state.latest_slashed_balances[current_epoch_penalization_index] + effective_balance) latest_slashed_balances = update_tuple_item( tuple_data=state.latest_slashed_balances, index=current_epoch_penalization_index, new_value=slashed_exit_balance, ) state = state.copy(latest_slashed_balances=latest_slashed_balances, ) # Update whistleblower's balance whistleblower_reward = (effective_balance // whistleblower_reward_quotient) whistleblower_index = get_beacon_proposer_index( state, state.slot, committee_config, ) state = state.update_validator_balance( whistleblower_index, state.validator_balances[whistleblower_index] + whistleblower_reward, ) # Update validator's balance and `slashed`, `withdrawable_epoch` field validator = state.validator_registry[validator_index].copy( slashed=True, withdrawable_epoch=state.current_epoch(slots_per_epoch) + latest_slashed_exit_length, ) state = state.update_validator( validator_index, validator, state.validator_balances[validator_index] - whistleblower_reward, ) return state
def get_initial_beacon_state(*, initial_validator_deposits: Sequence[Deposit], genesis_time: Timestamp, latest_eth1_data: Eth1Data, genesis_slot: SlotNumber, genesis_fork_version: int, genesis_start_shard: ShardNumber, shard_count: int, latest_block_roots_length: int, epoch_length: int, target_committee_size: int, max_deposit: Ether, latest_penalized_exit_length: int, latest_randao_mixes_length: int, entry_exit_delay: int) -> BeaconState: state = BeaconState( # Misc slot=genesis_slot, genesis_time=genesis_time, fork=Fork( previous_version=genesis_fork_version, current_version=genesis_fork_version, slot=genesis_slot, ), # Validator registry validator_registry=(), validator_balances=(), validator_registry_update_slot=genesis_slot, validator_registry_exit_count=0, validator_registry_delta_chain_tip=ZERO_HASH32, # Randomness and committees latest_randao_mixes=tuple(ZERO_HASH32 for _ in range(latest_randao_mixes_length)), latest_vdf_outputs=tuple(ZERO_HASH32 for _ in range(latest_randao_mixes_length // epoch_length)), # TODO Remove `persistent_committees`, `persistent_committee_reassignments` persistent_committees=(), persistent_committee_reassignments=(), previous_epoch_start_shard=genesis_start_shard, current_epoch_start_shard=genesis_start_shard, previous_epoch_calculation_slot=genesis_slot, current_epoch_calculation_slot=genesis_slot, previous_epoch_randao_mix=ZERO_HASH32, current_epoch_randao_mix=ZERO_HASH32, # Custody challenges custody_challenges=(), # Finality previous_justified_slot=genesis_slot, justified_slot=genesis_slot, justification_bitfield=0, finalized_slot=genesis_slot, # Recent state latest_crosslinks=tuple([ CrosslinkRecord(slot=genesis_slot, shard_block_root=ZERO_HASH32) for _ in range(shard_count) ]), latest_block_roots=tuple(ZERO_HASH32 for _ in range(latest_block_roots_length)), latest_penalized_balances=tuple( Gwei(0) for _ in range(latest_penalized_exit_length)), latest_attestations=(), batched_block_roots=(), # Ethereum 1.0 chain data latest_eth1_data=latest_eth1_data, eth1_data_votes=(), ) # Process initial deposits for deposit in initial_validator_deposits: state = process_deposit( state=state, pubkey=deposit.deposit_data.deposit_input.pubkey, amount=deposit.deposit_data.amount, proof_of_possession=deposit.deposit_data.deposit_input. proof_of_possession, withdrawal_credentials=deposit.deposit_data.deposit_input. withdrawal_credentials, randao_commitment=deposit.deposit_data.deposit_input. randao_commitment, custody_commitment=deposit.deposit_data.deposit_input. custody_commitment, ) for validator_index, _ in enumerate(state.validator_registry): validator_index = ValidatorIndex(validator_index) is_enough_effective_balance = get_effective_balance( state.validator_balances, validator_index, max_deposit, ) >= max_deposit * GWEI_PER_ETH if is_enough_effective_balance: state = activate_validator( state, validator_index, genesis=True, genesis_slot=genesis_slot, entry_exit_delay=entry_exit_delay, ) return state
def get_genesis_beacon_state( *, genesis_validator_deposits: Sequence[Deposit], genesis_time: Timestamp, genesis_eth1_data: Eth1Data, genesis_slot: Slot, genesis_epoch: Epoch, genesis_fork_version: int, genesis_start_shard: Shard, shard_count: int, min_seed_lookahead: int, slots_per_historical_root: int, latest_active_index_roots_length: int, slots_per_epoch: int, max_deposit_amount: Gwei, latest_slashed_exit_length: int, latest_randao_mixes_length: int, activation_exit_delay: int, deposit_contract_tree_depth: int, block_class: Type[BaseBeaconBlock]) -> BeaconState: state = BeaconState( # Misc slot=genesis_slot, genesis_time=genesis_time, fork=Fork( previous_version=genesis_fork_version.to_bytes(4, 'little'), current_version=genesis_fork_version.to_bytes(4, 'little'), epoch=genesis_epoch, ), # Validator registry validator_registry=(), validator_balances=(), validator_registry_update_epoch=genesis_epoch, # Randomness and committees latest_randao_mixes=(ZERO_HASH32, ) * latest_randao_mixes_length, previous_shuffling_start_shard=genesis_start_shard, current_shuffling_start_shard=genesis_start_shard, previous_shuffling_epoch=genesis_epoch, current_shuffling_epoch=genesis_epoch, previous_shuffling_seed=ZERO_HASH32, current_shuffling_seed=ZERO_HASH32, # Finality previous_epoch_attestations=(), current_epoch_attestations=(), previous_justified_epoch=genesis_epoch, current_justified_epoch=genesis_epoch, previous_justified_root=ZERO_HASH32, current_justified_root=ZERO_HASH32, justification_bitfield=0, finalized_epoch=genesis_epoch, finalized_root=ZERO_HASH32, # Recent state latest_crosslinks=((CrosslinkRecord( epoch=genesis_epoch, crosslink_data_root=ZERO_HASH32), ) * shard_count), latest_block_roots=(ZERO_HASH32, ) * slots_per_historical_root, latest_state_roots=(ZERO_HASH32, ) * slots_per_historical_root, latest_active_index_roots=(ZERO_HASH32, ) * latest_active_index_roots_length, latest_slashed_balances=(Gwei(0), ) * latest_slashed_exit_length, latest_block_header=get_temporary_block_header( BeaconBlock.create_empty_block(genesis_slot), ), historical_roots=(), # Ethereum 1.0 chain data latest_eth1_data=genesis_eth1_data, eth1_data_votes=(), deposit_index=0, ) # Process genesis deposits for deposit in genesis_validator_deposits: state = process_deposit( state=state, deposit=deposit, slots_per_epoch=slots_per_epoch, deposit_contract_tree_depth=deposit_contract_tree_depth, ) # Process genesis activations for validator_index, _ in enumerate(state.validator_registry): validator_index = ValidatorIndex(validator_index) is_enough_effective_balance = get_effective_balance( state.validator_balances, validator_index, max_deposit_amount, ) >= max_deposit_amount if is_enough_effective_balance: state = activate_validator( state=state, index=validator_index, is_genesis=True, genesis_epoch=genesis_epoch, slots_per_epoch=slots_per_epoch, activation_exit_delay=activation_exit_delay, ) # TODO: chanege to hash_tree_root active_validator_indices = get_active_validator_indices( state.validator_registry, genesis_epoch, ) genesis_active_index_root = hash_eth2(b''.join( [index.to_bytes(32, 'little') for index in active_validator_indices])) latest_active_index_roots = ( genesis_active_index_root, ) * latest_active_index_roots_length state = state.copy(latest_active_index_roots=latest_active_index_roots, ) current_shuffling_seed = generate_seed( state=state, epoch=genesis_epoch, slots_per_epoch=slots_per_epoch, min_seed_lookahead=min_seed_lookahead, activation_exit_delay=activation_exit_delay, latest_active_index_roots_length=latest_active_index_roots_length, latest_randao_mixes_length=latest_randao_mixes_length, ) state = state.copy(current_shuffling_seed=current_shuffling_seed, ) return state
def process_rewards_and_penalties(state: BeaconState, config: BeaconConfig) -> BeaconState: # Compute previous epoch active validator indices and the total balance they account for # for later use. previous_epoch_active_validator_indices = set( get_active_validator_indices( state.validator_registry, state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH))) previous_total_balance: Gwei = get_total_balance( state.validator_balances, tuple(previous_epoch_active_validator_indices), config.MAX_DEPOSIT_AMOUNT, ) # Compute previous epoch attester indices and the total balance they account for # for later use. previous_epoch_attestations = get_previous_epoch_attestations( state, config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH, ) previous_epoch_attester_indices = get_attester_indices_from_attesttion( state=state, attestations=previous_epoch_attestations, committee_config=CommitteeConfig(config), ) # Compute inclusion slot/distance of previous attestations for later use. inclusion_infos = get_inclusion_infos( state=state, attestations=previous_epoch_attestations, committee_config=CommitteeConfig(config), ) # Compute effective balance of each previous epoch active validator for later use effective_balances = { index: get_effective_balance( state.validator_balances, index, config.MAX_DEPOSIT_AMOUNT, ) for index in previous_epoch_active_validator_indices } # Compute base reward of each previous epoch active validator for later use _base_reward_quotient = (integer_squareroot(previous_total_balance) // config.BASE_REWARD_QUOTIENT) base_rewards = { index: get_base_reward( state=state, index=index, base_reward_quotient=_base_reward_quotient, max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, ) for index in previous_epoch_active_validator_indices } # Initialize the reward (validator) received map rewards_received = { index: SignedGwei(0) for index in previous_epoch_active_validator_indices } # 1. Process rewards and penalties for justification and finalization rewards_received = pipe( rewards_received, _process_rewards_and_penalties_for_finality( state, config, previous_epoch_active_validator_indices, previous_total_balance, previous_epoch_attestations, previous_epoch_attester_indices, inclusion_infos, effective_balances, base_rewards, ), _process_rewards_and_penalties_for_attestation_inclusion( state, config, previous_epoch_attester_indices, inclusion_infos, base_rewards, ), _process_rewards_and_penalties_for_crosslinks( state, config, previous_epoch_attestations, effective_balances, base_rewards, )) # Apply the overall rewards/penalties for index in previous_epoch_active_validator_indices: state = state.update_validator_balance( index, # Prevent validator balance under flow max(state.validator_balances[index] + rewards_received[index], 0), ) return state
def process_rewards_and_penalties(state: BeaconState, config: Eth2Config) -> BeaconState: # Compute previous epoch active validator indices and the total balance they account for # for later use. previous_epoch_active_validator_indices = set( get_active_validator_indices( state.validator_registry, state.previous_epoch(config.SLOTS_PER_EPOCH))) previous_total_balance: Gwei = get_total_balance( state.validator_balances, tuple(previous_epoch_active_validator_indices), config.MAX_DEPOSIT_AMOUNT, ) # Compute previous epoch attester indices and the total balance they account for # for later use. previous_epoch_attestations = state.previous_epoch_attestations previous_epoch_attester_indices = get_attester_indices_from_attestations( state=state, attestations=previous_epoch_attestations, committee_config=CommitteeConfig(config), ) # Compute inclusion slot/distance of previous attestations for later use. inclusion_infos = get_inclusion_infos( state=state, attestations=previous_epoch_attestations, committee_config=CommitteeConfig(config), ) # Compute effective balance of each previous epoch active validator for later use effective_balances = { ValidatorIndex(index): get_effective_balance( state.validator_balances, ValidatorIndex(index), config.MAX_DEPOSIT_AMOUNT, ) for index in range(len(state.validator_registry)) } # Compute base reward of each previous epoch active validator for later use base_rewards = { ValidatorIndex(index): get_base_reward( state=state, index=ValidatorIndex(index), base_reward_quotient=config.BASE_REWARD_QUOTIENT, previous_total_balance=previous_total_balance, max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, ) for index in range(len(state.validator_registry)) } # 1. Process rewards and penalties for justification and finalization finality_rewards, finality_penalties = _process_rewards_and_penalties_for_finality( state, config, previous_epoch_active_validator_indices, previous_total_balance, previous_epoch_attestations, previous_epoch_attester_indices, inclusion_infos, effective_balances, base_rewards, ) # 2. Process rewards and penalties for crosslinks crosslinks_rewards, crosslinks_penalties = _process_rewards_and_penalties_for_crosslinks( state, config, effective_balances, base_rewards, ) # Apply the overall rewards/penalties for index in range(len(state.validator_registry)): state = state.update_validator_balance( ValidatorIndex(index), # Prevent validator balance under flow max( (state.validator_balances[index] + finality_rewards[index] + crosslinks_rewards[index] - finality_penalties[index] - crosslinks_penalties[index]), 0, ), ) return state
def process_crosslinks(state: BeaconState, config: BeaconConfig) -> BeaconState: """ Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec: https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks For each shard from the past two epochs, find the shard block root that has been attested to by the most stake. If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard. Return resulting ``state`` """ latest_crosslinks = state.latest_crosslinks previous_epoch_attestations = get_previous_epoch_attestations( state, config.EPOCH_LENGTH, config.GENESIS_EPOCH, ) current_epoch_attestations = get_current_epoch_attestations(state, config.EPOCH_LENGTH) prev_epoch_start_slot = get_epoch_start_slot( state.previous_epoch(config.EPOCH_LENGTH, config.GENESIS_EPOCH), config.EPOCH_LENGTH, ) next_epoch_start_slot = get_epoch_start_slot( state.next_epoch(config.EPOCH_LENGTH), config.EPOCH_LENGTH, ) for slot in range(prev_epoch_start_slot, next_epoch_start_slot): crosslink_committees_at_slot = get_crosslink_committees_at_slot( state, slot, CommitteeConfig(config), ) for crosslink_committee, shard in crosslink_committees_at_slot: try: winning_root, total_attesting_balance = get_winning_root( state=state, shard=shard, # Use `_filter_attestations_by_shard` to filter out attestations # not attesting to this shard so we don't need to going over # irrelevent attestations over and over again. attestations=_filter_attestations_by_shard( previous_epoch_attestations + current_epoch_attestations, shard, ), max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, committee_config=CommitteeConfig(config), ) except NoWinningRootError: # No winning shard block root found for this shard. pass else: total_balance = sum( get_effective_balance(state.validator_balances, i, config.MAX_DEPOSIT_AMOUNT) for i in crosslink_committee ) if 3 * total_attesting_balance >= 2 * total_balance: latest_crosslinks = update_tuple_item( latest_crosslinks, shard, CrosslinkRecord( epoch=state.current_epoch(config.EPOCH_LENGTH), shard_block_root=winning_root, ), ) else: # Don't update the crosslink of this shard pass state = state.copy( latest_crosslinks=latest_crosslinks, ) return state
def test_get_winning_root( random, monkeypatch, target_committee_size, block_root_1_participants, block_root_2_participants, config, committee_config, n_validators_state, sample_attestation_data_params, sample_attestation_params): shard = 1 committee = tuple([i for i in range(target_committee_size)]) from eth2.beacon import committee_helpers def mock_get_crosslink_committees_at_slot(state, slot, committee_config): return ( (committee, shard,), ) monkeypatch.setattr( committee_helpers, 'get_crosslink_committees_at_slot', mock_get_crosslink_committees_at_slot ) competing_block_roots = [ hash_eth2(bytearray(random.getrandbits(8) for _ in range(10))), hash_eth2(bytearray(random.getrandbits(8) for _ in range(10))) ] # Generate bitfield of each participants set root_1_participants_bitfield = get_empty_bitfield(target_committee_size) root_2_participants_bitfield = get_empty_bitfield(target_committee_size) for i in block_root_1_participants: root_1_participants_bitfield = set_voted(root_1_participants_bitfield, i) for i in block_root_2_participants: root_2_participants_bitfield = set_voted(root_2_participants_bitfield, i) # `attestions` contains attestation to different block root by different set of participants attestations = [ # Attestation to `shard_block_root_1` by `attestation_participants_1` Attestation(**sample_attestation_params).copy( data=AttestationData(**sample_attestation_data_params).copy( shard=shard, shard_block_root=competing_block_roots[0], ), aggregation_bitfield=root_1_participants_bitfield ), # Attestation to `shard_block_root_2` by `attestation_participants_2` Attestation(**sample_attestation_params).copy( data=AttestationData(**sample_attestation_data_params).copy( shard=shard, shard_block_root=competing_block_roots[1], ), aggregation_bitfield=root_2_participants_bitfield ), ] try: winning_root, attesting_balance = get_winning_root( state=n_validators_state, shard=shard, attestations=attestations, max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, committee_config=committee_config, ) attesting_validators_indices = get_attesting_validator_indices( state=n_validators_state, attestations=attestations, shard=shard, shard_block_root=winning_root, committee_config=committee_config, ) total_attesting_balance = sum( get_effective_balance( n_validators_state.validator_balances, i, config.MAX_DEPOSIT_AMOUNT ) for i in attesting_validators_indices ) assert attesting_balance == total_attesting_balance except NoWinningRootError: assert len(block_root_1_participants) == 0 and len(block_root_2_participants) == 0 else: if len(block_root_1_participants) == len(block_root_2_participants): root_1_as_int = big_endian_to_int(competing_block_roots[0]) root_2_as_int = big_endian_to_int(competing_block_roots[1]) if root_1_as_int < root_2_as_int: assert winning_root == competing_block_roots[0] else: assert winning_root == competing_block_roots[1] elif len(block_root_1_participants) < len(block_root_2_participants): assert winning_root == competing_block_roots[1] else: assert winning_root == competing_block_roots[0]
def get_genesis_beacon_state(*, genesis_validator_deposits: Sequence[Deposit], genesis_time: Timestamp, latest_eth1_data: Eth1Data, genesis_slot: SlotNumber, genesis_epoch: EpochNumber, genesis_fork_version: int, genesis_start_shard: ShardNumber, shard_count: int, seed_lookahead: int, latest_block_roots_length: int, latest_index_roots_length: int, epoch_length: int, max_deposit_amount: Gwei, latest_penalized_exit_length: int, latest_randao_mixes_length: int, entry_exit_delay: int) -> BeaconState: state = BeaconState( # Misc slot=genesis_slot, genesis_time=genesis_time, fork=Fork( previous_version=genesis_fork_version, current_version=genesis_fork_version, epoch=genesis_epoch, ), # Validator registry validator_registry=(), validator_balances=(), validator_registry_update_epoch=genesis_epoch, # Randomness and committees latest_randao_mixes=(ZERO_HASH32,) * latest_randao_mixes_length, previous_epoch_start_shard=genesis_start_shard, current_epoch_start_shard=genesis_start_shard, previous_calculation_epoch=genesis_epoch, current_calculation_epoch=genesis_epoch, previous_epoch_seed=ZERO_HASH32, current_epoch_seed=ZERO_HASH32, # Finality previous_justified_epoch=genesis_epoch, justified_epoch=genesis_epoch, justification_bitfield=0, finalized_epoch=genesis_epoch, # Recent state latest_crosslinks=( (CrosslinkRecord(epoch=genesis_epoch, shard_block_root=ZERO_HASH32),) * shard_count ), latest_block_roots=(ZERO_HASH32,) * latest_block_roots_length, latest_index_roots=(ZERO_HASH32,) * latest_index_roots_length, latest_penalized_balances=(Gwei(0),) * latest_penalized_exit_length, latest_attestations=(), batched_block_roots=(), # Ethereum 1.0 chain data latest_eth1_data=latest_eth1_data, eth1_data_votes=(), deposit_index=len(genesis_validator_deposits), ) # Process initial deposits for deposit in genesis_validator_deposits: state = process_deposit( state=state, pubkey=deposit.deposit_data.deposit_input.pubkey, amount=deposit.deposit_data.amount, proof_of_possession=deposit.deposit_data.deposit_input.proof_of_possession, withdrawal_credentials=deposit.deposit_data.deposit_input.withdrawal_credentials, epoch_length=epoch_length, ) # Process initial activations for validator_index, _ in enumerate(state.validator_registry): validator_index = ValidatorIndex(validator_index) is_enough_effective_balance = get_effective_balance( state.validator_balances, validator_index, max_deposit_amount, ) >= max_deposit_amount if is_enough_effective_balance: state = activate_validator( state=state, index=validator_index, is_genesis=True, genesis_epoch=genesis_epoch, epoch_length=epoch_length, entry_exit_delay=entry_exit_delay, ) # TODO: chanege to hash_tree_root active_validator_indices = get_active_validator_indices( state.validator_registry, genesis_epoch, ) genesis_active_index_root = hash_eth2( b''.join( [ index.to_bytes(32, 'big') for index in active_validator_indices ] ) ) latest_index_roots = (genesis_active_index_root,) * latest_index_roots_length state = state.copy( latest_index_roots=latest_index_roots, ) current_epoch_seed = generate_seed( state=state, epoch=genesis_epoch, epoch_length=epoch_length, seed_lookahead=seed_lookahead, entry_exit_delay=entry_exit_delay, latest_index_roots_length=latest_index_roots_length, latest_randao_mixes_length=latest_randao_mixes_length, ) state = state.copy( current_epoch_seed=current_epoch_seed, ) return state
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState: """ Implement 'per-epoch-processing.crosslinks' portion of Phase 0 spec: https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#crosslinks For each shard from the past two epochs, find the shard block root that has been attested to by the most stake. If enough(>= 2/3 total stake) attesting stake, update the crosslink record of that shard. Return resulting ``state`` """ latest_crosslinks = state.latest_crosslinks effective_balances = { ValidatorIndex(index): get_effective_balance( state.validator_balances, ValidatorIndex(index), config.MAX_DEPOSIT_AMOUNT, ) for index in range(len(state.validator_registry)) } previous_epoch_start_slot = get_epoch_start_slot( state.previous_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) next_epoch_start_slot = get_epoch_start_slot( state.next_epoch(config.SLOTS_PER_EPOCH), config.SLOTS_PER_EPOCH, ) for slot in range(previous_epoch_start_slot, next_epoch_start_slot): crosslink_committees_at_slot = get_crosslink_committees_at_slot( state, slot, CommitteeConfig(config), ) for crosslink_committee, shard in crosslink_committees_at_slot: winning_root, attesting_validator_indices = get_winning_root_and_participants( state=state, shard=shard, effective_balances=effective_balances, committee_config=CommitteeConfig(config), ) if len(attesting_validator_indices) > 0: total_attesting_balance = get_total_balance( state.validator_balances, attesting_validator_indices, config.MAX_DEPOSIT_AMOUNT, ) total_balance = get_total_balance( state.validator_balances, crosslink_committee, config.MAX_DEPOSIT_AMOUNT, ) if 3 * total_attesting_balance >= 2 * total_balance: latest_crosslinks = update_tuple_item( latest_crosslinks, shard, CrosslinkRecord( epoch=slot_to_epoch(Slot(slot), config.SLOTS_PER_EPOCH), crosslink_data_root=winning_root, ), ) state = state.copy(latest_crosslinks=latest_crosslinks, ) return state