def genesis_state(filled_beacon_state, activated_genesis_validators, genesis_balances, epoch_length, target_committee_size, genesis_epoch, shard_count, latest_block_roots_length, latest_penalized_exit_length, latest_randao_mixes_length): return filled_beacon_state.copy( validator_registry=activated_genesis_validators, validator_balances=genesis_balances, latest_block_roots=tuple(ZERO_HASH32 for _ in range(latest_block_roots_length)), latest_penalized_balances=(0,) * latest_penalized_exit_length, latest_crosslinks=tuple( CrosslinkRecord( epoch=genesis_epoch, shard_block_root=ZERO_HASH32, ) for _ in range(shard_count) ), latest_randao_mixes=tuple( ZERO_HASH32 for _ in range(latest_randao_mixes_length) ), )
def validate_attestation_previous_crosslink_or_root( attestation_data: AttestationData, state_latest_crosslink: CrosslinkRecord, slots_per_epoch: int) -> None: """ Validate that either the attestation ``previous_crosslink`` or ``crosslink_data_root`` field of ``attestation_data`` is the provided ``latest_crosslink``. Raise ``ValidationError`` if it's invalid. """ attestation_creating_crosslink = CrosslinkRecord( epoch=slot_to_epoch(attestation_data.slot, slots_per_epoch), crosslink_data_root=attestation_data.crosslink_data_root, ) acceptable_crosslink_data = { # Case 1: Latest crosslink matches the one in the state attestation_data.previous_crosslink, # Case 2: State has already been updated, state's latest crosslink matches the crosslink # the attestation is trying to create attestation_creating_crosslink, } if state_latest_crosslink not in acceptable_crosslink_data: raise ValidationError( f"State's latests crosslink ({state_latest_crosslink}) doesn't match " " case 1: the `attestation_data.previous_crosslink` " f"({attestation_data.previous_crosslink.root}) or " "`case 2: the crosslink the attestation is trying to create " f"({attestation_creating_crosslink})")
async def test_send_multiple_attestations(request, event_loop): alice, msg_buffer = await get_command_setup(request, event_loop) attestations = tuple( Attestation( aggregation_bitfield=b"\x00\x00\x00", data=AttestationData( slot=0, beacon_block_root=ZERO_HASH32, source_epoch=SERENITY_CONFIG.GENESIS_EPOCH, target_root=ZERO_HASH32, source_root=ZERO_HASH32, shard=shard, previous_crosslink=CrosslinkRecord( SERENITY_CONFIG.GENESIS_EPOCH, ZERO_HASH32), crosslink_data_root=ZERO_HASH32, ), custody_bitfield=b"\x00\x00\x00", ) for shard in range(10)) alice.sub_proto.send_attestation_records(attestations) message = await msg_buffer.msg_queue.get() assert isinstance(message.command, AttestationRecords) assert message.payload == tuple( ssz.encode(attestation) for attestation in attestations)
def genesis_state(sample_beacon_state_params, activated_genesis_validators, genesis_balances, epoch_length, target_committee_size, genesis_slot, shard_count, latest_block_roots_length): initial_shuffling = get_shuffling( seed=ZERO_HASH32, validators=activated_genesis_validators, crosslinking_start_shard=0, slot=genesis_slot, epoch_length=epoch_length, target_committee_size=target_committee_size, shard_count=shard_count ) return BeaconState(**sample_beacon_state_params).copy( validator_registry=activated_genesis_validators, validator_balances=genesis_balances, shard_committees_at_slots=initial_shuffling + initial_shuffling, latest_block_roots=tuple(ZERO_HASH32 for _ in range(latest_block_roots_length)), latest_crosslinks=tuple( CrosslinkRecord( slot=genesis_slot, shard_block_root=ZERO_HASH32, ) for _ in range(shard_count) ) )
def test_num_crosslink_records(expected, sample_crosslink_record_params, filled_beacon_state): crosslink_records = [ CrosslinkRecord(**sample_crosslink_record_params) for i in range(expected) ] state = filled_beacon_state.copy(latest_crosslinks=crosslink_records, ) assert state.num_crosslinks == expected
def sample_attestation_data_params(sample_crosslink_record_params): return { 'slot': 10, 'beacon_block_root': b'\x11' * 32, 'source_epoch': 11, 'source_root': b'\x22' * 32, 'target_root': b'\x33' * 32, 'shard': 12, 'previous_crosslink': CrosslinkRecord(**sample_crosslink_record_params), 'crosslink_data_root': b'\x44' * 32, }
def sample_attestation_data_params(sample_crosslink_record_params): return { 'slot': 10, 'shard': 12, 'beacon_block_root': b'\x11' * 32, 'epoch_boundary_root': b'\x22' * 32, 'crosslink_data_root': b'\x33' * 32, 'latest_crosslink': CrosslinkRecord(**sample_crosslink_record_params), 'justified_epoch': 0, 'justified_block_root': b'\x55' * 32, }
def test_check_if_update_validator_registry(genesis_state, state_slot, validator_registry_update_epoch, finalized_epoch, has_crosslink, crosslink_epoch, expected_need_to_update, config): state = genesis_state.copy( slot=state_slot, finalized_epoch=finalized_epoch, validator_registry_update_epoch=validator_registry_update_epoch, ) if has_crosslink: crosslink = CrosslinkRecord( epoch=crosslink_epoch, crosslink_data_root=ZERO_HASH32, ) latest_crosslinks = state.latest_crosslinks for shard in range(config.SHARD_COUNT): latest_crosslinks = update_tuple_item( latest_crosslinks, shard, crosslink, ) state = state.copy( latest_crosslinks=latest_crosslinks, ) need_to_update, num_shards_in_committees = _check_if_update_validator_registry(state, config) assert need_to_update == expected_need_to_update if expected_need_to_update: expected_num_shards_in_committees = get_current_epoch_committee_count( state, shard_count=config.SHARD_COUNT, slots_per_epoch=config.SLOTS_PER_EPOCH, target_committee_size=config.TARGET_COMMITTEE_SIZE, ) assert num_shards_in_committees == expected_num_shards_in_committees else: assert num_shards_in_committees == 0
async def test_send_single_attestation(request, event_loop): alice, msg_buffer = await get_command_setup(request, event_loop) attestation = Attestation( aggregation_bitfield=b"\x00\x00\x00", data=AttestationData( slot=0, shard=1, beacon_block_root=ZERO_HASH32, epoch_boundary_root=ZERO_HASH32, crosslink_data_root=ZERO_HASH32, latest_crosslink=CrosslinkRecord(SERENITY_CONFIG.GENESIS_EPOCH, ZERO_HASH32), justified_epoch=SERENITY_CONFIG.GENESIS_EPOCH, justified_block_root=ZERO_HASH32, ), custody_bitfield=b"\x00\x00\x00", ) alice.sub_proto.send_attestation_records((attestation, )) message = await msg_buffer.msg_queue.get() assert isinstance(message.command, AttestationRecords) assert message.payload == (ssz.encode(attestation), )
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
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: 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_process_crosslinks( random, n_validators_state, config, slots_per_epoch, target_committee_size, shard_count, success_crosslink_in_cur_epoch, sample_attestation_data_params, sample_attestation_params): shard = 1 crosslink_data_root = hash_eth2(b'crosslink_data_root') current_slot = config.SLOTS_PER_EPOCH * 2 - 1 genesis_crosslinks = tuple([ CrosslinkRecord(epoch=config.GENESIS_EPOCH, crosslink_data_root=ZERO_HASH32) for _ in range(shard_count) ]) state = n_validators_state.copy( slot=current_slot, latest_crosslinks=genesis_crosslinks, ) # Generate current epoch attestations cur_epoch_attestations = [] for slot_in_cur_epoch in range(state.slot - config.SLOTS_PER_EPOCH, state.slot): if len(cur_epoch_attestations) > 0: break for committee, _shard in get_crosslink_committees_at_slot( state, slot_in_cur_epoch, CommitteeConfig(config), ): if _shard == shard: # Sample validators attesting to this shard. # Number of attesting validators sampled depends on `success_crosslink_in_cur_epoch` # if True, have >2/3 committee attest if success_crosslink_in_cur_epoch: attesting_validators = random.sample(committee, (2 * len(committee) // 3 + 1)) else: attesting_validators = random.sample(committee, (2 * len(committee) // 3 - 1)) # Generate the bitfield aggregation_bitfield = get_empty_bitfield(len(committee)) for v_index in attesting_validators: aggregation_bitfield = set_voted( aggregation_bitfield, committee.index(v_index)) # Generate the attestation cur_epoch_attestations.append( Attestation(**sample_attestation_params).copy( aggregation_bitfield=aggregation_bitfield, data=AttestationData(**sample_attestation_data_params).copy( slot=slot_in_cur_epoch, shard=shard, crosslink_data_root=crosslink_data_root, ), ) ) state = state.copy( latest_attestations=cur_epoch_attestations, ) assert (state.latest_crosslinks[shard].epoch == config.GENESIS_EPOCH and state.latest_crosslinks[shard].crosslink_data_root == ZERO_HASH32) new_state = process_crosslinks(state, config) crosslink_record = new_state.latest_crosslinks[shard] if success_crosslink_in_cur_epoch: attestation = cur_epoch_attestations[0] assert (crosslink_record.epoch == slot_to_epoch(current_slot, slots_per_epoch) and crosslink_record.crosslink_data_root == attestation.data.crosslink_data_root and attestation.data.crosslink_data_root == crosslink_data_root) else: assert (crosslink_record.epoch == config.GENESIS_EPOCH and crosslink_record.crosslink_data_root == ZERO_HASH32)
def test_defaults(sample_crosslink_record_params): crosslink = CrosslinkRecord(**sample_crosslink_record_params) assert crosslink.epoch == sample_crosslink_record_params['epoch'] assert crosslink.crosslink_data_root == sample_crosslink_record_params['crosslink_data_root']
def test_get_initial_beacon_state( privkeys, pubkeys, num_validators, genesis_epoch, genesis_slot, genesis_fork_version, genesis_start_shard, shard_count, seed_lookahead, latest_block_roots_length, latest_index_roots_length, epoch_length, max_deposit_amount, latest_penalized_exit_length, latest_randao_mixes_length, entry_exit_delay, sample_eth1_data_params): withdrawal_credentials = b'\x22' * 32 randao_commitment = b'\x33' * 32 custody_commitment = b'\x44' * 32 fork = Fork( previous_version=genesis_fork_version, current_version=genesis_fork_version, epoch=genesis_epoch, ) validator_count = 5 initial_validator_deposits = (Deposit( branch=(b'\x11' * 32 for j in range(10)), index=i, deposit_data=DepositData( deposit_input=DepositInput( pubkey=pubkeys[i], withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, proof_of_possession=sign_proof_of_possession( deposit_input=DepositInput( pubkey=pubkeys[i], withdrawal_credentials=withdrawal_credentials, randao_commitment=randao_commitment, custody_commitment=custody_commitment, ), privkey=privkeys[i], fork=fork, slot=genesis_slot, epoch_length=epoch_length, ), ), amount=max_deposit_amount, timestamp=0, ), ) for i in range(validator_count)) genesis_time = 10 latest_eth1_data = Eth1Data(**sample_eth1_data_params) state = get_initial_beacon_state( initial_validator_deposits=initial_validator_deposits, genesis_time=genesis_time, latest_eth1_data=latest_eth1_data, genesis_epoch=genesis_epoch, genesis_slot=genesis_slot, genesis_fork_version=genesis_fork_version, genesis_start_shard=genesis_start_shard, shard_count=shard_count, seed_lookahead=seed_lookahead, latest_block_roots_length=latest_block_roots_length, latest_index_roots_length=latest_index_roots_length, epoch_length=epoch_length, max_deposit_amount=max_deposit_amount, latest_penalized_exit_length=latest_penalized_exit_length, latest_randao_mixes_length=latest_randao_mixes_length, entry_exit_delay=entry_exit_delay, ) # Misc assert state.slot == genesis_slot assert state.genesis_time == genesis_time assert state.fork.previous_version == genesis_fork_version assert state.fork.current_version == genesis_fork_version assert state.fork.epoch == genesis_epoch # Validator registry assert len(state.validator_registry) == validator_count assert len(state.validator_balances) == validator_count assert state.validator_registry_update_epoch == genesis_epoch assert state.validator_registry_exit_count == 0 # Randomness and committees assert len(state.latest_randao_mixes) == latest_randao_mixes_length assert len( state.latest_vdf_outputs) == latest_randao_mixes_length // epoch_length # TODO: `persistent_committees`, `persistent_committee_reassignments` will be removed assert len(state.persistent_committees) == 0 assert len(state.persistent_committee_reassignments) == 0 assert state.previous_epoch_start_shard == genesis_start_shard assert state.current_epoch_start_shard == genesis_start_shard assert state.previous_calculation_epoch == genesis_epoch assert state.current_calculation_epoch == genesis_epoch assert state.previous_epoch_seed == ZERO_HASH32 # Custody challenges assert len(state.custody_challenges) == 0 # Finality assert state.previous_justified_epoch == genesis_epoch assert state.justified_epoch == genesis_epoch assert state.justification_bitfield == 0 assert state.finalized_epoch == genesis_epoch # Recent state assert len(state.latest_crosslinks) == shard_count assert state.latest_crosslinks[0] == CrosslinkRecord( epoch=genesis_epoch, shard_block_root=ZERO_HASH32, ) assert len(state.latest_block_roots) == latest_block_roots_length assert state.latest_block_roots[0] == ZERO_HASH32 assert len(state.latest_penalized_balances) == latest_penalized_exit_length assert state.latest_penalized_balances[0] == Gwei(0) assert len(state.latest_attestations) == 0 assert len(state.batched_block_roots) == 0 # Ethereum 1.0 chain data assert state.latest_eth1_data == latest_eth1_data assert len(state.eth1_data_votes) == 0 assert state.validator_registry[0].is_active(genesis_epoch)
validate_attestation_justified_block_root( attestation_data, justified_block_root ) @pytest.mark.parametrize( ( 'attestation_latest_crosslink,' 'attestation_crosslink_data_root,' 'state_latest_crosslink,' 'is_valid,' ), [ ( CrosslinkRecord(0, b'\x11' * 32), b'\x33' * 32, CrosslinkRecord(0, b'\x22' * 32), False, ), ( CrosslinkRecord(0, b'\x33' * 32), b'\x33' * 32, CrosslinkRecord(0, b'\x11' * 32), False, ), ( CrosslinkRecord(0, b'\x11' * 32), b'\x33' * 32, CrosslinkRecord(0, b'\x33' * 32), True,
def test_defaults(sample_crosslink_record_params): crosslink = CrosslinkRecord(**sample_crosslink_record_params) assert crosslink.slot == sample_crosslink_record_params['slot'] assert crosslink.shard_block_root == sample_crosslink_record_params['shard_block_root']
def test_get_genesis_beacon_state( privkeys, pubkeys, num_validators, genesis_epoch, genesis_slot, genesis_fork_version, genesis_start_shard, shard_count, min_seed_lookahead, latest_block_roots_length, latest_active_index_roots_length, slots_per_epoch, max_deposit_amount, latest_slashed_exit_length, latest_randao_mixes_length, activation_exit_delay, sample_eth1_data_params): withdrawal_credentials = b'\x22' * 32 fork = Fork( previous_version=genesis_fork_version, current_version=genesis_fork_version, epoch=genesis_epoch, ) validator_count = 5 genesis_validator_deposits = tuple( Deposit( branch=(b'\x11' * 32 for j in range(10)), index=i, deposit_data=DepositData( deposit_input=DepositInput( pubkey=pubkeys[i], withdrawal_credentials=withdrawal_credentials, proof_of_possession=sign_proof_of_possession( deposit_input=DepositInput( pubkey=pubkeys[i], withdrawal_credentials=withdrawal_credentials, ), privkey=privkeys[i], fork=fork, slot=genesis_slot, slots_per_epoch=slots_per_epoch, ), ), amount=max_deposit_amount, timestamp=0, ), ) for i in range(validator_count)) genesis_time = 10 latest_eth1_data = Eth1Data(**sample_eth1_data_params) state = get_genesis_beacon_state( genesis_validator_deposits=genesis_validator_deposits, genesis_time=genesis_time, latest_eth1_data=latest_eth1_data, genesis_epoch=genesis_epoch, genesis_slot=genesis_slot, genesis_fork_version=genesis_fork_version, genesis_start_shard=genesis_start_shard, shard_count=shard_count, min_seed_lookahead=min_seed_lookahead, latest_block_roots_length=latest_block_roots_length, latest_active_index_roots_length=latest_active_index_roots_length, slots_per_epoch=slots_per_epoch, max_deposit_amount=max_deposit_amount, latest_slashed_exit_length=latest_slashed_exit_length, latest_randao_mixes_length=latest_randao_mixes_length, activation_exit_delay=activation_exit_delay, ) # Misc assert state.slot == genesis_slot assert state.genesis_time == genesis_time assert state.fork.previous_version == genesis_fork_version assert state.fork.current_version == genesis_fork_version assert state.fork.epoch == genesis_epoch # Validator registry assert len(state.validator_registry) == validator_count assert len(state.validator_balances) == validator_count assert state.validator_registry_update_epoch == genesis_epoch # Randomness and committees assert len(state.latest_randao_mixes) == latest_randao_mixes_length assert state.previous_shuffling_start_shard == genesis_start_shard assert state.current_shuffling_start_shard == genesis_start_shard assert state.previous_shuffling_epoch == genesis_epoch assert state.current_shuffling_epoch == genesis_epoch assert state.previous_shuffling_seed == ZERO_HASH32 # Finality assert state.previous_justified_epoch == genesis_epoch assert state.justified_epoch == genesis_epoch assert state.justification_bitfield == 0 assert state.finalized_epoch == genesis_epoch # Recent state assert len(state.latest_crosslinks) == shard_count assert state.latest_crosslinks[0] == CrosslinkRecord( epoch=genesis_epoch, crosslink_data_root=ZERO_HASH32, ) assert len(state.latest_block_roots) == latest_block_roots_length assert state.latest_block_roots[0] == ZERO_HASH32 assert len(state.latest_slashed_balances) == latest_slashed_exit_length assert state.latest_slashed_balances[0] == Gwei(0) assert len(state.latest_attestations) == 0 assert len(state.batched_block_roots) == 0 # Ethereum 1.0 chain data assert state.latest_eth1_data == latest_eth1_data assert len(state.eth1_data_votes) == 0 assert state.deposit_index == len(genesis_validator_deposits) assert state.validator_registry[0].is_active(genesis_epoch)
def test_get_genesis_beacon_state( num_validators, pubkeys, genesis_epoch, genesis_slot, genesis_fork_version, genesis_start_shard, shard_count, min_seed_lookahead, slots_per_historical_root, latest_active_index_roots_length, slots_per_epoch, max_deposit_amount, latest_slashed_exit_length, latest_randao_mixes_length, activation_exit_delay, config, keymap, deposit_contract_tree_depth): validator_count = 5 genesis_validator_deposits, deposit_root = create_mock_genesis_validator_deposits_and_root( num_validators=validator_count, config=config, pubkeys=pubkeys, keymap=keymap, ) genesis_eth1_data = Eth1Data( deposit_root=deposit_root, block_hash=ZERO_HASH32, ) genesis_time = 10 state = get_genesis_beacon_state( genesis_validator_deposits=genesis_validator_deposits, genesis_time=genesis_time, genesis_eth1_data=genesis_eth1_data, genesis_epoch=genesis_epoch, genesis_slot=genesis_slot, genesis_fork_version=genesis_fork_version, genesis_start_shard=genesis_start_shard, shard_count=shard_count, min_seed_lookahead=min_seed_lookahead, slots_per_historical_root=slots_per_historical_root, latest_active_index_roots_length=latest_active_index_roots_length, slots_per_epoch=slots_per_epoch, max_deposit_amount=max_deposit_amount, latest_slashed_exit_length=latest_slashed_exit_length, latest_randao_mixes_length=latest_randao_mixes_length, activation_exit_delay=activation_exit_delay, deposit_contract_tree_depth=deposit_contract_tree_depth, ) # Misc assert state.slot == genesis_slot assert state.genesis_time == genesis_time assert state.fork.previous_version == genesis_fork_version.to_bytes( 4, 'little') assert state.fork.current_version == genesis_fork_version.to_bytes( 4, 'little') assert state.fork.epoch == genesis_epoch # Validator registry assert len(state.validator_registry) == validator_count assert len(state.validator_balances) == validator_count assert state.validator_registry_update_epoch == genesis_epoch # Randomness and committees assert len(state.latest_randao_mixes) == latest_randao_mixes_length assert state.previous_shuffling_start_shard == genesis_start_shard assert state.current_shuffling_start_shard == genesis_start_shard assert state.previous_shuffling_epoch == genesis_epoch assert state.current_shuffling_epoch == genesis_epoch assert state.previous_shuffling_seed == ZERO_HASH32 # Finality assert len(state.previous_epoch_attestations) == 0 assert len(state.current_epoch_attestations) == 0 assert state.previous_justified_epoch == genesis_epoch assert state.justified_epoch == genesis_epoch assert state.justification_bitfield == 0 assert state.finalized_epoch == genesis_epoch # Recent state assert len(state.latest_crosslinks) == shard_count assert state.latest_crosslinks[0] == CrosslinkRecord( epoch=genesis_epoch, crosslink_data_root=ZERO_HASH32, ) assert len(state.latest_block_roots) == slots_per_historical_root assert state.latest_block_roots[0] == ZERO_HASH32 assert len(state.latest_slashed_balances) == latest_slashed_exit_length assert state.latest_slashed_balances[0] == Gwei(0) assert len(state.historical_roots) == 0 # Ethereum 1.0 chain data assert state.latest_eth1_data == genesis_eth1_data assert len(state.eth1_data_votes) == 0 assert state.deposit_index == len(genesis_validator_deposits) assert state.validator_registry[0].is_active(genesis_epoch)
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 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 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