def process_validator_registry(state: BeaconState, config: BeaconConfig) -> BeaconState: state = state.copy( previous_epoch_calculation_slot=state.current_epoch_calculation_slot, previous_epoch_start_shard=state.current_epoch_start_shard, previous_epoch_seed=state.current_epoch_seed, ) state = _update_latest_index_roots(state, config) need_to_update, num_shards_in_committees = _check_if_update_validator_registry( state, config) if need_to_update: state = update_validator_registry(state) # Update step-by-step since updated `state.current_epoch_calculation_slot` # is used to calculate other value). Follow the spec tightly now. state = state.copy(current_epoch_calculation_slot=state.slot, ) state = state.copy( current_epoch_start_shard=(state.current_epoch_start_shard + num_shards_in_committees) % config.SHARD_COUNT, ) # The `helpers.generate_seed` function is only present to provide an entry point # for mocking this out in tests. current_epoch_seed = helpers.generate_seed( state=state, slot=state.current_epoch_calculation_slot, epoch_length=config.EPOCH_LENGTH, seed_lookahead=config.SEED_LOOKAHEAD, latest_index_roots_length=config.LATEST_INDEX_ROOTS_LENGTH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ) state = state.copy(current_epoch_seed=current_epoch_seed, ) else: epochs_since_last_registry_change = ( state.slot - state.validator_registry_update_slot) // config.EPOCH_LENGTH if is_power_of_two(epochs_since_last_registry_change): # Update step-by-step since updated `state.current_epoch_calculation_slot` # is used to calculate other value). Follow the spec tightly now. state = state.copy(current_epoch_calculation_slot=state.slot, ) # The `helpers.generate_seed` function is only present to provide an entry point # for mocking this out in tests. current_epoch_seed = helpers.generate_seed( state=state, slot=state.current_epoch_calculation_slot, epoch_length=config.EPOCH_LENGTH, seed_lookahead=config.SEED_LOOKAHEAD, latest_index_roots_length=config.LATEST_INDEX_ROOTS_LENGTH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ) state = state.copy(current_epoch_seed=current_epoch_seed, ) else: pass return state
def get_crosslink_committee(state: BeaconState, epoch: Epoch, shard: Shard, config: CommitteeConfig) -> Iterable[ValidatorIndex]: target_shard = ( shard + config.SHARD_COUNT - get_epoch_start_shard(state, epoch, config) ) % config.SHARD_COUNT active_validator_indices = get_active_validator_indices( state.validators, epoch, ) return _compute_committee( indices=active_validator_indices, seed=generate_seed(state, epoch, config), index=target_shard, count=get_epoch_committee_count( len(active_validator_indices), config.SHARD_COUNT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ), shuffle_round_count=config.SHUFFLE_ROUND_COUNT, )
def _get_shuffling_contextis_next_epoch_registry_change( state: 'BeaconState', next_epoch: Epoch, committee_config: CommitteeConfig) -> ShufflingContext: current_committees_per_epoch = get_current_epoch_committee_count( state=state, shard_count=committee_config.SHARD_COUNT, slots_per_epoch=committee_config.SLOTS_PER_EPOCH, target_committee_size=committee_config.TARGET_COMMITTEE_SIZE, ) return ShufflingContext( committees_per_epoch=get_next_epoch_committee_count( state=state, shard_count=committee_config.SHARD_COUNT, slots_per_epoch=committee_config.SLOTS_PER_EPOCH, target_committee_size=committee_config.TARGET_COMMITTEE_SIZE, ), seed=helpers.generate_seed( state=state, epoch=next_epoch, slots_per_epoch=committee_config.SLOTS_PER_EPOCH, min_seed_lookahead=committee_config.MIN_SEED_LOOKAHEAD, activation_exit_delay=committee_config.SLOTS_PER_EPOCH, latest_active_index_roots_length=committee_config.LATEST_ACTIVE_INDEX_ROOTS_LENGTH, latest_randao_mixes_length=committee_config.LATEST_RANDAO_MIXES_LENGTH, ), shuffling_epoch=next_epoch, # for mocking this out in tests. shuffling_start_shard=( state.current_shuffling_start_shard + current_committees_per_epoch ) % committee_config.SHARD_COUNT, )
def _get_shuffling_contextis_next_epoch_registry_change( state: 'BeaconState', next_epoch: Epoch, committee_config: CommitteeConfig) -> ShufflingContext: current_committees_per_epoch = get_current_epoch_committee_count( state=state, shard_count=committee_config.SHARD_COUNT, slots_per_epoch=committee_config.SLOTS_PER_EPOCH, target_committee_size=committee_config.TARGET_COMMITTEE_SIZE, ) return ShufflingContext( committees_per_epoch=get_next_epoch_committee_count( state=state, shard_count=committee_config.SHARD_COUNT, slots_per_epoch=committee_config.SLOTS_PER_EPOCH, target_committee_size=committee_config.TARGET_COMMITTEE_SIZE, ), seed=helpers.generate_seed( state=state, epoch=next_epoch, committee_config=committee_config, ), shuffling_epoch=next_epoch, # for mocking this out in tests. shuffling_start_shard=(state.current_shuffling_start_shard + current_committees_per_epoch) % committee_config.SHARD_COUNT, )
def _update_shuffling_seed(state: BeaconState, committee_config: CommitteeConfig) -> BeaconState: """ Updates the ``current_shuffling_seed`` in the ``state`` given the current state data. """ # The `helpers.generate_seed` function is only present to provide an entry point # for mocking this out in tests. current_shuffling_seed = helpers.generate_seed( state=state, epoch=state.current_shuffling_epoch, committee_config=committee_config, ) return state.copy(current_shuffling_seed=current_shuffling_seed, )
def test_generate_seed(monkeypatch, genesis_state, slots_per_epoch, min_seed_lookahead, activation_exit_delay, latest_active_index_roots_length, latest_randao_mixes_length): from eth2.beacon import helpers def mock_get_randao_mix(state, epoch, slots_per_epoch, latest_randao_mixes_length): return hash_eth2( state.root + epoch.to_bytes(32, byteorder='little') + latest_randao_mixes_length.to_bytes(32, byteorder='little')) def mock_get_active_index_root(state, epoch, slots_per_epoch, activation_exit_delay, latest_active_index_roots_length): return hash_eth2( state.root + epoch.to_bytes(32, byteorder='little') + slots_per_epoch.to_bytes(32, byteorder='little') + latest_active_index_roots_length.to_bytes(32, byteorder='little')) monkeypatch.setattr(helpers, 'get_randao_mix', mock_get_randao_mix) monkeypatch.setattr(helpers, 'get_active_index_root', mock_get_active_index_root) state = genesis_state epoch = 1 epoch_as_bytes = epoch.to_bytes(32, 'little') seed = generate_seed( state=state, epoch=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, ) assert seed == hash_eth2( mock_get_randao_mix( state=state, epoch=(epoch - min_seed_lookahead), slots_per_epoch=slots_per_epoch, latest_randao_mixes_length=latest_randao_mixes_length, ) + mock_get_active_index_root( state=state, epoch=epoch, slots_per_epoch=slots_per_epoch, activation_exit_delay=activation_exit_delay, latest_active_index_roots_length=latest_active_index_roots_length, ) + epoch_as_bytes)
def test_generate_seed(monkeypatch, genesis_state, epoch_length, seed_lookahead, entry_exit_delay, latest_index_roots_length, latest_randao_mixes_length): from eth2.beacon import helpers def mock_get_randao_mix(state, epoch, epoch_length, latest_randao_mixes_length): return hash_eth2( state.root + abs(epoch).to_bytes(32, byteorder='big') + latest_randao_mixes_length.to_bytes(32, byteorder='big')) def mock_get_active_index_root(state, epoch, epoch_length, entry_exit_delay, latest_index_roots_length): return hash_eth2( state.root + abs(epoch).to_bytes(32, byteorder='big') + epoch_length.to_bytes(32, byteorder='big') + latest_index_roots_length.to_bytes(32, byteorder='big')) monkeypatch.setattr(helpers, 'get_randao_mix', mock_get_randao_mix) monkeypatch.setattr(helpers, 'get_active_index_root', mock_get_active_index_root) state = genesis_state epoch = 1 seed = generate_seed( state=state, epoch=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, ) assert seed == hash_eth2( mock_get_randao_mix( state=state, epoch=(epoch - seed_lookahead), epoch_length=epoch_length, latest_randao_mixes_length=latest_randao_mixes_length, ) + mock_get_active_index_root( state=state, epoch=epoch, epoch_length=epoch_length, entry_exit_delay=entry_exit_delay, latest_index_roots_length=latest_index_roots_length, ))
def _update_shuffling_seed(state: BeaconState, slots_per_epoch: int, min_seed_lookahead: int, activation_exit_delay: int, latest_active_index_roots_length: int, latest_randao_mixes_length: int) -> BeaconState: """ Updates the ``current_shuffling_seed`` in the ``state`` given the current state data. """ # The `helpers.generate_seed` function is only present to provide an entry point # for mocking this out in tests. current_shuffling_seed = helpers.generate_seed( state=state, epoch=state.current_shuffling_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, ) return state.copy(current_shuffling_seed=current_shuffling_seed, )
def get_beacon_proposer_index(state: BeaconState, committee_config: CommitteeConfig) -> ValidatorIndex: """ Return the current beacon proposer index. """ first_committee = _calculate_first_committee_at_slot( state, state.slot, committee_config, ) current_epoch = state.current_epoch(committee_config.SLOTS_PER_EPOCH) seed = generate_seed(state, current_epoch, committee_config) return _find_proposer_in_committee( state.validators, first_committee, current_epoch, seed, committee_config.MAX_EFFECTIVE_BALANCE, )
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 get_crosslink_committees_at_slot( state: 'BeaconState', slot: SlotNumber, committee_config: CommitteeConfig, registry_change: bool = False ) -> Iterable[Tuple[Iterable[ValidatorIndex], ShardNumber]]: """ Return the list of ``(committee, shard)`` tuples for the ``slot``. """ genesis_epoch = committee_config.GENESIS_EPOCH shard_count = committee_config.SHARD_COUNT epoch_length = committee_config.EPOCH_LENGTH target_committee_size = committee_config.TARGET_COMMITTEE_SIZE seed_lookahead = committee_config.SEED_LOOKAHEAD entry_exit_delay = committee_config.ENTRY_EXIT_DELAY latest_index_roots_length = committee_config.LATEST_INDEX_ROOTS_LENGTH latest_randao_mixes_length = committee_config.LATEST_RANDAO_MIXES_LENGTH epoch = slot_to_epoch(slot, epoch_length) current_epoch = state.current_epoch(epoch_length) previous_epoch = state.previous_epoch(epoch_length, genesis_epoch) next_epoch = state.next_epoch(epoch_length) validate_epoch_for_current_epoch( current_epoch=current_epoch, given_epoch=epoch, genesis_epoch=genesis_epoch, ) if epoch == previous_epoch: committees_per_epoch = get_previous_epoch_committee_count( state=state, shard_count=shard_count, epoch_length=epoch_length, target_committee_size=target_committee_size, ) seed = state.previous_epoch_seed shuffling_epoch = state.previous_calculation_epoch shuffling_start_shard = state.previous_epoch_start_shard elif epoch == current_epoch: committees_per_epoch = get_current_epoch_committee_count( state=state, shard_count=shard_count, epoch_length=epoch_length, target_committee_size=target_committee_size, ) seed = state.current_epoch_seed shuffling_epoch = state.current_calculation_epoch shuffling_start_shard = state.current_epoch_start_shard elif epoch == next_epoch: current_committees_per_epoch = get_current_epoch_committee_count( state=state, shard_count=shard_count, epoch_length=epoch_length, target_committee_size=target_committee_size, ) committees_per_epoch = get_next_epoch_committee_count( state=state, shard_count=shard_count, epoch_length=epoch_length, target_committee_size=target_committee_size, ) shuffling_epoch = next_epoch epochs_since_last_registry_update = current_epoch - state.validator_registry_update_epoch should_reseed = (epochs_since_last_registry_update > 1 and is_power_of_two(epochs_since_last_registry_update)) if registry_change: # for mocking this out in tests. seed = helpers.generate_seed( state=state, epoch=next_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, ) shuffling_start_shard = ( state.current_epoch_start_shard + current_committees_per_epoch) % shard_count elif should_reseed: # for mocking this out in tests. seed = helpers.generate_seed( state=state, epoch=next_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, ) shuffling_start_shard = state.current_epoch_start_shard else: seed = state.current_epoch_seed shuffling_start_shard = state.current_epoch_start_shard shuffling = get_shuffling( seed=seed, validators=state.validator_registry, epoch=shuffling_epoch, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count, ) offset = slot % epoch_length committees_per_slot = committees_per_epoch // epoch_length slot_start_shard = (shuffling_start_shard + committees_per_slot * offset) % shard_count for index in range(committees_per_slot): committee = shuffling[committees_per_slot * offset + index] yield ( committee, ShardNumber((slot_start_shard + index) % shard_count), )
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