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.set("eth1_deposit_index", state.eth1_deposit_index + 1) pubkey = deposit.data.pubkey amount = deposit.data.amount withdrawal_credentials = deposit.data.withdrawal_credentials 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`. deposit_message = DepositMessage.create( pubkey=pubkey, withdrawal_credentials=withdrawal_credentials, amount=amount) domain = compute_domain(SignatureDomain.DOMAIN_DEPOSIT, fork_version=config.GENESIS_FORK_VERSION) signing_root = compute_signing_root(deposit_message, domain) is_valid_proof_of_possession = bls.verify(signing_root, deposit.data.signature, pubkey) if not is_valid_proof_of_possession: return state validator = Validator.create_pending_validator(pubkey, withdrawal_credentials, amount, config) return state.mset( "validators", state.validators.append(validator), "balances", state.balances.append(amount), ) else: index = ValidatorIndex(validator_pubkeys.index(pubkey)) return increase_balance(state, index, amount)
def process_block_header(state: BeaconState, block: BaseBeaconBlock, config: Eth2Config) -> BeaconState: validate_block_slot(state, block) validate_block_parent_root(state, block) validate_proposer_is_not_slashed(state, block.hash_tree_root, config) return state.set( "latest_block_header", BeaconBlockHeader.create( slot=block.slot, parent_root=block.parent_root, # `state_root` is zeroed and overwritten in the next `process_slot` call body_root=block.body.hash_tree_root, # `signature` is zeroed ), )
def process_rewards_and_penalties(state: BeaconState, config: Eth2Config) -> BeaconState: current_epoch = state.current_epoch(config.SLOTS_PER_EPOCH) if current_epoch == GENESIS_EPOCH: return state rewards_for_attestations, penalties_for_attestations = get_attestation_deltas( state, config) new_balances = (max(balance + reward - penalty, 0) for balance, reward, penalty in zip( state.balances, rewards_for_attestations, penalties_for_attestations)) return state.set( "balances", HashableList.from_iterable(new_balances, state.balances.sedes))
def process_registry_updates(state: BeaconState, config: Eth2Config) -> BeaconState: new_validators = state.validators for index, validator in enumerate(state.validators): new_validator = _process_activation_eligibility_or_ejections( state, validator, config) new_validators = new_validators.set(index, new_validator) 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 = new_validators.transform( (index, ), _update_validator_activation_epoch(state, config)) return state.set("validators", new_validators)
def _increment_slot(state: BeaconState) -> BeaconState: return state.set("slot", state.slot + 1)