def test_activate_validator(is_genesis, filled_beacon_state, genesis_epoch, epoch_length, entry_exit_delay, max_deposit_amount): validator_count = 10 state = filled_beacon_state.copy( validator_registry=tuple( mock_validator_record( pubkey=index.to_bytes(48, 'big'), is_active=False, ) for index in range(validator_count)), validator_balances=(max_deposit_amount, ) * validator_count, ) index = 1 # Check that the `index`th validator in `state` is inactivated assert state.validator_registry[index].activation_epoch == FAR_FUTURE_EPOCH result_state = activate_validator( state=state, index=index, is_genesis=is_genesis, genesis_epoch=genesis_epoch, epoch_length=epoch_length, entry_exit_delay=entry_exit_delay, ) if is_genesis: assert result_state.validator_registry[ index].activation_epoch == genesis_epoch else: assert (result_state.validator_registry[index].activation_epoch == get_entry_exit_effect_epoch( state.current_epoch(epoch_length), entry_exit_delay, ))
def test_activate_validator(is_genesis, filled_beacon_state, genesis_epoch, slots_per_epoch, activation_exit_delay, max_deposit_amount, config): validator_count = 10 state = filled_beacon_state.copy( validator_registry=tuple( mock_validator( pubkey=index.to_bytes(48, 'little'), config=config, is_active=False, ) for index in range(validator_count)), validator_balances=(max_deposit_amount, ) * validator_count, ) index = 1 # Check that the `index`th validator in `state` is inactivated assert state.validator_registry[index].activation_epoch == FAR_FUTURE_EPOCH result_state = activate_validator( state=state, index=index, is_genesis=is_genesis, genesis_epoch=genesis_epoch, slots_per_epoch=slots_per_epoch, activation_exit_delay=activation_exit_delay, ) if is_genesis: assert result_state.validator_registry[ index].activation_epoch == genesis_epoch else: assert (result_state.validator_registry[index].activation_epoch == get_delayed_activation_exit_epoch( state.current_epoch(slots_per_epoch), activation_exit_delay, ))
def create_mock_validator( pubkey: BLSPubkey, config: Eth2Config, withdrawal_credentials: Hash32 = ZERO_HASH32, is_active: bool = True, ) -> Validator: validator = Validator.create_pending_validator( pubkey, withdrawal_credentials, config.MAX_EFFECTIVE_BALANCE, config) if is_active: return activate_validator(validator, config.GENESIS_EPOCH) else: return validator
def initialize_beacon_state_from_eth1(*, eth1_block_hash: Hash32, eth1_timestamp: Timestamp, deposits: Sequence[Deposit], config: Eth2Config) -> BeaconState: fork = Fork.create( previous_version=config.GENESIS_FORK_VERSION, current_version=config.GENESIS_FORK_VERSION, epoch=GENESIS_EPOCH, ) state = BeaconState.create( genesis_time=_genesis_time_from_eth1_timestamp(eth1_timestamp, config.GENESIS_DELAY), fork=fork, eth1_data=Eth1Data.create(block_hash=eth1_block_hash, deposit_count=len(deposits)), latest_block_header=BeaconBlockHeader.create( body_root=BeaconBlockBody.create().hash_tree_root), block_roots=(ZERO_ROOT, ) * config.SLOTS_PER_HISTORICAL_ROOT, state_roots=(ZERO_HASH32, ) * config.SLOTS_PER_HISTORICAL_ROOT, randao_mixes=(eth1_block_hash, ) * config.EPOCHS_PER_HISTORICAL_VECTOR, slashings=(Gwei(0), ) * config.EPOCHS_PER_SLASHINGS_VECTOR, config=config, ) # Process genesis deposits for index, deposit in enumerate(deposits): deposit_data_list = tuple(deposit.data for deposit in deposits[:index + 1]) deposit_root = ssz.get_hash_tree_root( deposit_data_list, ssz.List(DepositData, 2**DEPOSIT_CONTRACT_TREE_DEPTH)) state = state.transform(("eth1_data", "deposit_root"), deposit_root) state = process_deposit(state=state, deposit=deposit, config=config) # Process genesis activations for validator_index in range(len(state.validators)): validator_index = ValidatorIndex(validator_index) balance = state.balances[validator_index] effective_balance = calculate_effective_balance(balance, config) state = state.transform( ("validators", validator_index, "effective_balance"), effective_balance) if effective_balance == config.MAX_EFFECTIVE_BALANCE: activated_validator = activate_validator( state.validators[validator_index], GENESIS_EPOCH) state = state.transform(("validators", validator_index), activated_validator) return state.set("genesis_validators_root", state.validators.hash_tree_root)
def test_activate_validator(genesis_state, is_already_activated, validator_count, pubkeys, config): some_future_epoch = config.GENESIS_EPOCH + random.randrange(1, 2**32) if is_already_activated: assert validator_count > 0 some_validator = genesis_state.validators[0] assert some_validator.activation_eligibility_epoch == config.GENESIS_EPOCH assert some_validator.activation_epoch == config.GENESIS_EPOCH else: some_validator = create_mock_validator(pubkeys[:validator_count + 1], config, is_active=is_already_activated) assert some_validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH assert some_validator.activation_epoch == FAR_FUTURE_EPOCH assert not some_validator.slashed activated_validator = activate_validator(some_validator, some_future_epoch) assert activated_validator.activation_eligibility_epoch == some_future_epoch assert activated_validator.activation_epoch == some_future_epoch assert not activated_validator.slashed
def test_activate_validator(genesis, filled_beacon_state, genesis_slot, entry_exit_delay, max_deposit): validator_count = 10 state = filled_beacon_state.copy( validator_registry=tuple( mock_validator_record( pubkey=index.to_bytes(48, 'big'), is_active=False, ) for index in range(validator_count)), validator_balances=(max_deposit * GWEI_PER_ETH, ) * validator_count, ) index = 1 # Check that the `index`th validator in `state` is inactivated assert state.validator_registry[index].activation_slot == FAR_FUTURE_SLOT result_state = activate_validator( state=state, index=index, genesis=genesis, genesis_slot=genesis_slot, entry_exit_delay=entry_exit_delay, ) result_validator = result_state.validator_registry[index] new_validator_registry_delta_chain_tip = ValidatorRegistryDeltaBlock( latest_registry_delta_root=state.validator_registry_delta_chain_tip, validator_index=index, pubkey=result_validator.pubkey, slot=result_validator.activation_slot, flag=ValidatorRegistryDeltaFlag.ACTIVATION, ).root assert (result_state.validator_registry_delta_chain_tip == new_validator_registry_delta_chain_tip) if genesis: state.validator_registry[index].activation_slot == genesis_slot else: state.validator_registry[ index].activation_slot == state.slot + entry_exit_delay
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 update_validator_registry(state: BeaconState, config: BeaconConfig) -> BeaconState: """ Update validator registry. """ current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) # The active validators active_validator_indices = get_active_validator_indices( state.validator_registry, current_epoch) # The total effective balance of active validators total_balance = get_total_balance( state.validator_balances, active_validator_indices, config.MAX_DEPOSIT_AMOUNT, ) # The maximum balance churn in Gwei (for deposits and exits separately) max_balance_churn = max( config.MAX_DEPOSIT_AMOUNT, total_balance // (2 * config.MAX_BALANCE_CHURN_QUOTIENT)) # Activate validators within the allowable balance churn # linter didn't like a bare lambda state = _churn_validators( state=state, config=config, check_should_churn_fn=lambda state, index: _is_ready_to_activate( state, index, max_deposit_amount=config.MAX_DEPOSIT_AMOUNT, ), churn_fn=lambda state, index: activate_validator( state, index, is_genesis=False, genesis_epoch=config.GENESIS_EPOCH, slots_per_epoch=config.SLOTS_PER_EPOCH, activation_exit_delay=config.ACTIVATION_EXIT_DELAY, ), max_balance_churn=max_balance_churn, ) # Exit validators within the allowable balance churn # linter didn't like a bare lambda state = _churn_validators( state=state, config=config, check_should_churn_fn=lambda state, index: _is_ready_to_exit( state, index), churn_fn=lambda state, index: exit_validator( state, index, slots_per_epoch=config.SLOTS_PER_EPOCH, activation_exit_delay=config.ACTIVATION_EXIT_DELAY, ), max_balance_churn=max_balance_churn, ) state = state.copy(validator_registry_update_epoch=current_epoch, ) 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 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