def process_slot_transition(state: BeaconState, config: Eth2Config, previous_block_root: Hash32) -> BeaconState: slots_per_historical_root = config.SLOTS_PER_HISTORICAL_ROOT # Update state.latest_state_roots # TODO ensure this becomes the `hash_tree_root` of the `state` latest_state_root = state.root updated_latest_state_roots = _update_historical_root( state.latest_state_roots, state.slot, slots_per_historical_root, latest_state_root, ) # Update state.slot state = state.copy( slot=state.slot + 1 ) # Update state.latest_block_roots updated_latest_block_roots = _update_historical_root( state.latest_block_roots, state.slot - 1, slots_per_historical_root, previous_block_root, ) state = state.copy( latest_block_roots=updated_latest_block_roots, latest_state_roots=updated_latest_state_roots, ) return state
def process_final_updates(state: BeaconState, config: BeaconConfig) -> BeaconState: epoch = state.slot // config.EPOCH_LENGTH current_index = (epoch + 1) % config.LATEST_PENALIZED_EXIT_LENGTH previous_index = epoch % config.LATEST_PENALIZED_EXIT_LENGTH state = state.copy( latest_penalized_balances=update_tuple_item( state.latest_penalized_balances, current_index, state.latest_penalized_balances[previous_index], ), ) epoch_start = state.slot - config.EPOCH_LENGTH latest_attestations = tuple( filter( lambda attestation: attestation.data.slot >= epoch_start, state.latest_attestations ) ) state = state.copy( latest_attestations=latest_attestations, ) return state
def process_final_updates(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) state = _update_latest_active_index_roots(state, CommitteeConfig(config)) state = state.copy( latest_slashed_balances=update_tuple_item( state.latest_slashed_balances, next_epoch % config.LATEST_SLASHED_EXIT_LENGTH, state.latest_slashed_balances[current_epoch % config.LATEST_SLASHED_EXIT_LENGTH], ), latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, next_epoch % config.LATEST_RANDAO_MIXES_LENGTH, get_randao_mix( state=state, epoch=current_epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), ), ) state = _update_historical_roots(state, next_epoch, config) # Rotate current/previous epoch attestations state = state.copy( previous_epoch_attestations=state.current_epoch_attestations, current_epoch_attestations=(), ) return state
def per_slot_transition(self, state: BeaconState, previous_block_root: Hash32) -> BeaconState: LATEST_BLOCK_ROOTS_LENGTH = self.config.LATEST_BLOCK_ROOTS_LENGTH # Update state.slot state = state.copy( slot=state.slot + 1 ) # Update state.latest_block_roots updated_latest_block_roots = list(state.latest_block_roots) previous_block_root_index = (state.slot - 1) % LATEST_BLOCK_ROOTS_LENGTH updated_latest_block_roots[previous_block_root_index] = previous_block_root # Update state.batched_block_roots updated_batched_block_roots = state.batched_block_roots if state.slot % LATEST_BLOCK_ROOTS_LENGTH == 0: updated_batched_block_roots += (get_merkle_root(updated_latest_block_roots),) state = state.copy( latest_block_roots=tuple(updated_latest_block_roots), batched_block_roots=updated_batched_block_roots, ) return state
def create_mock_attester_slashing_is_surround_vote( state: BeaconState, config: Eth2Config, keymap: Dict[BLSPubkey, int], attestation_epoch: Epoch) -> AttesterSlashing: # target_epoch_2 < target_epoch_1 attestation_slot_2 = get_epoch_start_slot(attestation_epoch, config.SLOTS_PER_EPOCH) attestation_slot_1 = Slot(attestation_slot_2 + config.SLOTS_PER_EPOCH) slashable_attestation_1 = create_mock_slashable_attestation( state.copy( slot=attestation_slot_1, current_justified_epoch=config.GENESIS_EPOCH, ), config, keymap, attestation_slot_1, ) slashable_attestation_2 = create_mock_slashable_attestation( state.copy( slot=attestation_slot_1, current_justified_epoch=config.GENESIS_EPOCH + 1, # source_epoch_1 < source_epoch_2 ), config, keymap, attestation_slot_2, ) return AttesterSlashing( attestation_1=slashable_attestation_1, attestation_2=slashable_attestation_2, )
def process_final_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_eth1_data_votes = _determine_next_eth1_votes(state, config) new_validators = _update_effective_balances(state, config) new_start_shard = _compute_next_start_shard(state, config) new_active_index_roots = _compute_next_active_index_roots(state, config) new_compact_committees_roots = _compute_next_compact_committees_roots( state.copy( validators=new_validators, start_shard=new_start_shard, ), config, ) new_slashings = _compute_next_slashings(state, config) new_randao_mixes = _compute_next_randao_mixes(state, config) new_historical_roots = _compute_next_historical_roots(state, config) return state.copy( eth1_data_votes=new_eth1_data_votes, validators=new_validators, start_shard=new_start_shard, active_index_roots=new_active_index_roots, compact_committees_roots=new_compact_committees_roots, slashings=new_slashings, randao_mixes=new_randao_mixes, historical_roots=new_historical_roots, previous_epoch_attestations=state.current_epoch_attestations, current_epoch_attestations=tuple(), )
def process_final_updates(state: BeaconState, config: BeaconConfig) -> BeaconState: current_epoch = state.current_epoch(config.EPOCH_LENGTH) next_epoch = state.next_epoch(config.EPOCH_LENGTH) state = state.copy( latest_penalized_balances=update_tuple_item( state.latest_penalized_balances, next_epoch % config.LATEST_PENALIZED_EXIT_LENGTH, state.latest_penalized_balances[ current_epoch % config.LATEST_PENALIZED_EXIT_LENGTH], ), latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, next_epoch % config.LATEST_PENALIZED_EXIT_LENGTH, get_randao_mix( state=state, epoch=current_epoch, epoch_length=config.EPOCH_LENGTH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), ), ) latest_attestations = tuple( filter( lambda attestation: (slot_to_epoch(attestation.data.slot, config. EPOCH_LENGTH) >= current_epoch), state.latest_attestations)) state = state.copy(latest_attestations=latest_attestations, ) return state
def _process_slot(state: BeaconState, config: Eth2Config) -> BeaconState: slots_per_historical_root = config.SLOTS_PER_HISTORICAL_ROOT previous_state_root = state.root updated_state_roots = _update_historical_root( state.state_roots, state.slot, slots_per_historical_root, previous_state_root, ) if state.latest_block_header.state_root == ZERO_HASH32: latest_block_header = state.latest_block_header state = state.copy(latest_block_header=latest_block_header.copy( state_root=previous_state_root, ), ) updated_block_roots = _update_historical_root( state.block_roots, state.slot, slots_per_historical_root, state.latest_block_header.signing_root, ) return state.copy( block_roots=updated_block_roots, state_roots=updated_state_roots, )
def process_final_updates(state: BeaconState, config: BeaconConfig) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) next_epoch = state.next_epoch(config.SLOTS_PER_EPOCH) state = _update_latest_active_index_roots(state, CommitteeConfig(config)) state = state.copy( latest_slashed_balances=update_tuple_item( state.latest_slashed_balances, next_epoch % config.LATEST_SLASHED_EXIT_LENGTH, state.latest_slashed_balances[current_epoch % config.LATEST_SLASHED_EXIT_LENGTH], ), latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, next_epoch % config.LATEST_SLASHED_EXIT_LENGTH, get_randao_mix( state=state, epoch=current_epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), ), ) latest_attestations = tuple( filter( lambda attestation: (slot_to_epoch(attestation.data.slot, config.SLOTS_PER_EPOCH) >= current_epoch), state.latest_attestations)) state = state.copy(latest_attestations=latest_attestations, ) return state
def process_eth1_data(state: BeaconState, block: BaseBeaconBlock) -> BeaconState: try: vote_index, original_vote = first( (index, eth1_data_vote) for index, eth1_data_vote in enumerate(state.eth1_data_votes) if block.eth1_data == eth1_data_vote.eth1_data ) except StopIteration: new_vote = Eth1DataVote( eth1_data=block.eth1_data, vote_count=1, ) state = state.copy( eth1_data_votes=state.eth1_data_votes + (new_vote,) ) else: updated_vote = original_vote.copy( vote_count=original_vote.vote_count + 1 ) state = state.copy( eth1_data_votes=update_tuple_item(state.eth1_data_votes, vote_index, updated_vote) ) return state
def process_cache_state(state: BeaconState, config: Eth2Config) -> BeaconState: slots_per_historical_root = config.SLOTS_PER_HISTORICAL_ROOT # Update state.latest_state_roots latest_state_root = state.root updated_latest_state_roots = _update_historical_root( state.latest_state_roots, state.slot, slots_per_historical_root, latest_state_root, ) if state.latest_block_header.state_root == ZERO_HASH32: latest_block_header = state.latest_block_header state = state.copy(latest_block_header=latest_block_header.copy( state_root=latest_state_root, ), ) # Update state.latest_block_roots updated_latest_block_roots = _update_historical_root( state.latest_block_roots, state.slot, slots_per_historical_root, # TODO make `signed_root` state.latest_block_header.signed_root, ) state = state.copy( latest_block_roots=updated_latest_block_roots, latest_state_roots=updated_latest_state_roots, ) return state
def process_deposit(state: BeaconState, deposit: Deposit, config: Eth2Config) -> BeaconState: """ Process a deposit from Ethereum 1.0. """ validate_deposit_proof(state, deposit, DEPOSIT_CONTRACT_TREE_DEPTH) # Increment the next deposit index we are expecting. Note that this # needs to be done here because while the deposit contract will never # create an invalid Merkle branch, it may admit an invalid deposit # object, and we need to be able to skip over it state = state.copy( eth1_deposit_index=state.eth1_deposit_index + 1, ) pubkey = deposit.data.pubkey amount = deposit.data.amount validator_pubkeys = tuple(v.pubkey for v in state.validators) if pubkey not in validator_pubkeys: # Verify the deposit signature (proof of possession) for new validators. # Note: The deposit contract does not check signatures. # Note: Deposits are valid across forks, thus the deposit domain # is retrieved directly from `compute_domain`. is_valid_proof_of_possession = bls.verify( message_hash=deposit.data.signing_root, pubkey=pubkey, signature=deposit.data.signature, domain=compute_domain( SignatureDomain.DOMAIN_DEPOSIT, ), ) if not is_valid_proof_of_possession: return state withdrawal_credentials = deposit.data.withdrawal_credentials validator = Validator.create_pending_validator( pubkey, withdrawal_credentials, amount, config, ) return state.copy( validators=state.validators + (validator,), balances=state.balances + (amount, ), ) else: index = ValidatorIndex(validator_pubkeys.index(pubkey)) return increase_balance( state, index, amount, )
def process_attestations(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: if len(block.body.attestations) > config.MAX_ATTESTATIONS: raise ValidationError( f"The block has too many attestations:\n" f"\tFound {len(block.body.attestations)} attestations, " f"maximum: {config.MAX_ATTESTATIONS}") current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) new_current_epoch_attestations: Tuple[PendingAttestation, ...] = tuple() new_previous_epoch_attestations: Tuple[PendingAttestation, ...] = tuple() for attestation in block.body.attestations: validate_attestation(state, attestation, config) proposer_index = get_beacon_proposer_index(state, CommitteeConfig(config)) pending_attestation = PendingAttestation( aggregation_bits=attestation.aggregation_bits, data=attestation.data, inclusion_delay=state.slot - attestation.data.slot, proposer_index=proposer_index, ) if attestation.data.target.epoch == current_epoch: new_current_epoch_attestations += (pending_attestation, ) else: new_previous_epoch_attestations += (pending_attestation, ) return state.copy( current_epoch_attestations=(state.current_epoch_attestations + new_current_epoch_attestations), previous_epoch_attestations=(state.previous_epoch_attestations + new_previous_epoch_attestations), )
def process_justification_and_finalization(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) genesis_epoch = config.GENESIS_EPOCH if current_epoch <= genesis_epoch + 1: return state ( new_current_justified_epoch, new_current_justified_root, justification_bitfield, ) = _determine_new_justified_checkpoint_and_bitfield( state, config, ) ( new_finalized_epoch, new_finalized_root, ) = _determine_new_finalized_checkpoint( state, justification_bitfield, config, ) return state.copy( previous_justified_epoch=state.current_justified_epoch, previous_justified_root=state.current_justified_root, current_justified_epoch=new_current_justified_epoch, current_justified_root=new_current_justified_root, justification_bitfield=justification_bitfield, finalized_epoch=new_finalized_epoch, finalized_root=new_finalized_root, )
def process_randao(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: proposer_index = get_beacon_proposer_index( state=state, slot=state.slot, committee_config=CommitteeConfig(config), ) proposer = state.validator_registry[proposer_index] epoch = state.current_epoch(config.SLOTS_PER_EPOCH) validate_randao_reveal( randao_reveal=block.randao_reveal, proposer_index=proposer_index, proposer_pubkey=proposer.pubkey, epoch=epoch, fork=state.fork, ) randao_mix_index = epoch % config.LATEST_RANDAO_MIXES_LENGTH new_randao_mix = bitwise_xor( get_randao_mix( state=state, epoch=epoch, slots_per_epoch=config.SLOTS_PER_EPOCH, latest_randao_mixes_length=config.LATEST_RANDAO_MIXES_LENGTH, ), hash_eth2(block.randao_reveal), ) return state.copy(latest_randao_mixes=update_tuple_item( state.latest_randao_mixes, randao_mix_index, new_randao_mix, ), )
def _update_shuffling_epoch(state: BeaconState, slots_per_epoch: int) -> BeaconState: """ Updates the ``current_shuffling_epoch`` to the ``state``'s next epoch. """ return state.copy( current_shuffling_epoch=state.next_epoch(slots_per_epoch), )
def process_registry_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_validators = tuple( _process_activation_eligibility_or_ejections(state, validator, config) for validator in state.validators ) activation_exit_epoch = compute_activation_exit_epoch( state.finalized_checkpoint.epoch, config.MAX_SEED_LOOKAHEAD ) activation_queue = sorted( ( index for index, validator in enumerate(new_validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= activation_exit_epoch ), key=lambda index: new_validators[index].activation_eligibility_epoch, ) for index in activation_queue[: get_validator_churn_limit(state, config)]: new_validators = update_tuple_item_with_fn( new_validators, index, _update_validator_activation_epoch(state, config) ) return state.copy(validators=new_validators)
def activate_validator(state: BeaconState, index: ValidatorIndex, genesis: bool, genesis_slot: SlotNumber, entry_exit_delay: int) -> BeaconState: """ Activate the validator with the given ``index``. Return the updated state (immutable). """ # Update validator.activation_slot validator = state.validator_registry[index] validator = validator.copy( activation_slot=genesis_slot if genesis else (state.slot + entry_exit_delay)) state = state.update_validator_registry(index, validator) # Update state.validator_registry_delta_chain_tip # TODO: use tree hashing new_validator_registry_delta_chain_tip = ValidatorRegistryDeltaBlock( latest_registry_delta_root=state.validator_registry_delta_chain_tip, validator_index=index, pubkey=validator.pubkey, slot=validator.activation_slot, flag=ValidatorRegistryDeltaFlag.ACTIVATION, ).root state = state.copy(validator_registry_delta_chain_tip= new_validator_registry_delta_chain_tip, ) return state
def process_randao(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: proposer_index = get_beacon_proposer_index( state=state, committee_config=CommitteeConfig(config)) epoch = state.current_epoch(config.SLOTS_PER_EPOCH) validate_randao_reveal( state=state, proposer_index=proposer_index, epoch=epoch, randao_reveal=block.body.randao_reveal, slots_per_epoch=config.SLOTS_PER_EPOCH, ) randao_mix_index = epoch % config.EPOCHS_PER_HISTORICAL_VECTOR new_randao_mix = bitwise_xor( get_randao_mix( state=state, epoch=epoch, epochs_per_historical_vector=config.EPOCHS_PER_HISTORICAL_VECTOR, ), hash_eth2(block.body.randao_reveal), ) return state.copy(randao_mixes=update_tuple_item( state.randao_mixes, randao_mix_index, new_randao_mix))
def process_attestations(state: BeaconState, block: BaseBeaconBlock, config: BeaconConfig) -> BeaconState: """ Implements 'per-block-processing.operations.attestations' portion of Phase 0 spec: https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#attestations-1 Validate the ``attestations`` contained within the ``block`` in the context of ``state``. If any invalid, throw ``ValidationError``. Otherwise, append an ``PendingAttestationRecords`` for each to ``latest_attestations``. Return resulting ``state``. """ for attestation in block.body.attestations: validate_serenity_attestation( state, attestation, config.EPOCH_LENGTH, config.MIN_ATTESTATION_INCLUSION_DELAY, config.LATEST_BLOCK_ROOTS_LENGTH, ) # update_latest_attestations additional_pending_attestations = tuple( PendingAttestationRecord( data=attestation.data, participation_bitfield=attestation.participation_bitfield, custody_bitfield=attestation.custody_bitfield, slot_included=state.slot, ) for attestation in block.body.attestations) state = state.copy(latest_attestations=state.latest_attestations + additional_pending_attestations, ) return state
def process_registry_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_validators = tuple( _process_activation_eligibility_or_ejections(state, validator, config) for validator in state.validators ) delayed_activation_exit_epoch = get_delayed_activation_exit_epoch( state.finalized_epoch, config.ACTIVATION_EXIT_DELAY, ) activation_queue = sorted([ index for index, validator in enumerate(new_validators) if validator.activation_eligibility_epoch != FAR_FUTURE_EPOCH and validator.activation_epoch >= delayed_activation_exit_epoch ], key=lambda index: new_validators[index].activation_eligibility_epoch) for index in activation_queue[:get_churn_limit(state, config)]: new_validators = update_tuple_item_with_fn( new_validators, index, _update_validator_activation_epoch(state, config), ) return state.copy( validators=new_validators, )
def create_mock_deposit( state: BeaconState, pubkey: BLSPubkey, keymap: Dict[BLSPubkey, int], withdrawal_credentials: Hash32, config: Eth2Config, leaves: Sequence[Hash32] = None, ) -> Tuple[BeaconState, Deposit]: deposits, root = create_mock_deposits_and_root( (pubkey, ), keymap, config, withdrawal_credentials=(withdrawal_credentials, ), leaves=leaves, ) # sanity check assert len(deposits) == 1 deposit = deposits[0] state = state.copy( eth1_data=state.eth1_data.copy( deposit_root=root, deposit_count=state.eth1_data.deposit_count + len(deposits), ), eth1_deposit_index=0 if not leaves else len(leaves), ) return state, deposit
def create_mock_block( state: BeaconState, config: BeaconConfig, block_class: Type[BaseBeaconBlock], parent_block: BaseBeaconBlock, keymap: Dict[BLSPubkey, int], slot: SlotNumber = None, attestations: Sequence[Attestation] = () ) -> BaseBeaconBlock: """ Create a mocking block with the given block parameters and ``keymap``. """ proposer_index = get_beacon_proposer_index( state.copy(slot=slot, ), slot, config.EPOCH_LENGTH, config.TARGET_COMMITTEE_SIZE, config.SHARD_COUNT, ) proposer_pubkey = state.validator_registry[proposer_index].pubkey proposer_privkey = keymap[proposer_pubkey] block = create_block_on_state( state, config, block_class, parent_block, slot, validator_index=proposer_index, privkey=proposer_privkey, attestations=attestations, ) return block
def exit_validator(state: BeaconState, index: ValidatorIndex, epoch_length: int, entry_exit_delay: int) -> BeaconState: """ Exit the validator with the given ``index``. Return the updated state (immutable). """ validator = state.validator_registry[index] entry_exit_effect_epoch = get_entry_exit_effect_epoch( state.current_epoch(epoch_length), entry_exit_delay, ) # The following updates only occur if not previous exited if validator.exit_epoch <= entry_exit_effect_epoch: return state # Update state.validator_registry_exit_count state = state.copy( validator_registry_exit_count=state.validator_registry_exit_count + 1, ) # Update validator.exit_epoch and exit_epoch.exit_count validator = validator.copy( exit_epoch=state.current_epoch(epoch_length) + entry_exit_delay, exit_count=state.validator_registry_exit_count, ) state = state.update_validator_registry(index, validator) return state
def validate_proposer_index(state: BeaconState, config: Eth2Config, slot: Slot, validator_index: ValidatorIndex) -> None: beacon_proposer_index = get_beacon_proposer_index(state.copy(slot=slot), config) if validator_index != beacon_proposer_index: raise ProposerIndexError
def _update_latest_index_roots(state: BeaconState, committee_config: CommitteeConfig) -> BeaconState: """ Return the BeaconState with updated `latest_index_roots`. """ next_epoch = state.next_epoch(committee_config.EPOCH_LENGTH) # TODO: chanege to hash_tree_root active_validator_indices = get_active_validator_indices( state.validator_registry, EpochNumber(next_epoch + committee_config.ENTRY_EXIT_DELAY), ) index_root = hash_eth2( b''.join( [ index.to_bytes(32, 'big') for index in active_validator_indices ] ) ) latest_index_roots = update_tuple_item( state.latest_index_roots, ( (next_epoch + committee_config.ENTRY_EXIT_DELAY) % committee_config.LATEST_INDEX_ROOTS_LENGTH ), index_root, ) return state.copy( latest_index_roots=latest_index_roots, )
def decrease_balance(state: BeaconState, index: ValidatorIndex, delta: Gwei) -> BeaconState: return state.copy(balances=update_tuple_item_with_fn( state.balances, index, lambda balance, *_: Gwei(0) if delta > balance else Gwei(balance - delta), ))
def per_slot_transition(self, state: BeaconState, previous_block_root: Hash32) -> BeaconState: # TODO state = state.copy( slot=state.slot + 1 ) return state
def process_crosslinks(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) previous_epoch = state.previous_epoch(config.SLOTS_PER_EPOCH, config.GENESIS_EPOCH) new_current_crosslinks = state.current_crosslinks for epoch in (previous_epoch, current_epoch): active_validators_indices = get_active_validator_indices( state.validators, epoch) epoch_committee_count = get_committee_count( len(active_validators_indices), config.SHARD_COUNT, config.SLOTS_PER_EPOCH, config.TARGET_COMMITTEE_SIZE, ) epoch_start_shard = get_start_shard( state, epoch, CommitteeConfig(config), ) for shard_offset in range(epoch_committee_count): shard = Shard( (epoch_start_shard + shard_offset) % config.SHARD_COUNT) crosslink_committee = set( get_crosslink_committee( state, epoch, shard, CommitteeConfig(config), )) if not crosslink_committee: # empty crosslink committee this epoch continue winning_crosslink, attesting_indices = get_winning_crosslink_and_attesting_indices( state=state, epoch=epoch, shard=shard, config=config, ) threshold_met = _is_threshold_met_against_committee( state, attesting_indices, crosslink_committee, ) if threshold_met: new_current_crosslinks = update_tuple_item( new_current_crosslinks, shard, winning_crosslink, ) return state.copy( previous_crosslinks=state.current_crosslinks, current_crosslinks=new_current_crosslinks, )
def process_deposit(state: BeaconState, deposit: Deposit, slots_per_epoch: int, deposit_contract_tree_depth: int) -> BeaconState: """ Process a deposit from Ethereum 1.0. """ validate_deposit(state, deposit, deposit_contract_tree_depth) # Increment the next deposit index we are expecting. Note that this # needs to be done here because while the deposit contract will never # create an invalid Merkle branch, it may admit an invalid deposit # object, and we need to be able to skip over it state = state.copy(deposit_index=state.deposit_index + 1, ) validator_pubkeys = tuple(v.pubkey for v in state.validator_registry) deposit_input = deposit.deposit_data.deposit_input pubkey = deposit_input.pubkey amount = deposit.deposit_data.amount withdrawal_credentials = deposit_input.withdrawal_credentials if pubkey not in validator_pubkeys: # Verify the proof of possession proof_is_valid = bls.verify( pubkey=pubkey, message_hash=deposit_input.signing_root, signature=deposit_input.signature, domain=get_domain( state.fork, state.current_epoch(slots_per_epoch), SignatureDomain.DOMAIN_DEPOSIT, ), ) if not proof_is_valid: return state validator = Validator.create_pending_validator( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, ) # Note: In phase 2 registry indices that has been withdrawn for a long time # will be recycled. state = add_pending_validator( state, validator, amount, ) else: # Top-up - increase balance by deposit index = ValidatorIndex(validator_pubkeys.index(pubkey)) validator = state.validator_registry[index] # Update validator's balance and state state = state.update_validator_balance( validator_index=index, balance=state.validator_balances[index] + amount, ) return state