Created
May 14, 2025 13:13
-
-
Save ydm/6dca3f65bd82efcfa3a7fe2e2c491ac5 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def get_balance_churn_limit(state: BeaconState) -> Gwei: | |
""" | |
Return the churn limit for the current epoch. | |
""" | |
churn = max( | |
MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA, | |
get_total_active_balance(state) // CHURN_LIMIT_QUOTIENT | |
) | |
return churn - churn % EFFECTIVE_BALANCE_INCREMENT | |
def get_activation_exit_churn_limit(state: BeaconState) -> Gwei: | |
""" | |
Return the churn limit for the current epoch dedicated to activations and exits. | |
""" | |
return min(MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT, get_balance_churn_limit(state)) | |
def process_deposit(state: BeaconState, deposit: Deposit) -> None: | |
# Verify the Merkle branch | |
assert is_valid_merkle_branch( | |
leaf=hash_tree_root(deposit.data), | |
branch=deposit.proof, | |
depth=DEPOSIT_CONTRACT_TREE_DEPTH + 1, # Add 1 for the List length mix-in | |
index=state.eth1_deposit_index, | |
root=state.eth1_data.deposit_root, | |
) | |
# Deposits must be processed in order | |
state.eth1_deposit_index += 1 | |
# [Modified in Electra:EIP7251] | |
apply_deposit( | |
state=state, | |
pubkey=deposit.data.pubkey, | |
withdrawal_credentials=deposit.data.withdrawal_credentials, | |
amount=deposit.data.amount, | |
signature=deposit.data.signature, | |
) | |
def apply_deposit(state: BeaconState, | |
pubkey: BLSPubkey, | |
withdrawal_credentials: Bytes32, | |
amount: uint64, | |
signature: BLSSignature) -> None: | |
validator_pubkeys = [v.pubkey for v in state.validators] | |
if pubkey not in validator_pubkeys: | |
# Verify the deposit signature (proof of possession) which is not checked by the deposit contract | |
if is_valid_deposit_signature(pubkey, withdrawal_credentials, amount, signature): | |
add_validator_to_registry(state, pubkey, withdrawal_credentials, Gwei(0)) # [Modified in Electra:EIP7251] | |
else: | |
return | |
# Increase balance by deposit amount | |
# [Modified in Electra:EIP7251] | |
state.pending_deposits.append(PendingDeposit( | |
pubkey=pubkey, | |
withdrawal_credentials=withdrawal_credentials, | |
amount=amount, | |
signature=signature, | |
slot=GENESIS_SLOT # Use GENESIS_SLOT to distinguish from a pending deposit request | |
)) | |
def process_deposit_request(state: BeaconState, deposit_request: DepositRequest) -> None: | |
# Set deposit request start index | |
if state.deposit_requests_start_index == UNSET_DEPOSIT_REQUESTS_START_INDEX: | |
state.deposit_requests_start_index = deposit_request.index | |
# Create pending deposit | |
state.pending_deposits.append(PendingDeposit( | |
pubkey=deposit_request.pubkey, | |
withdrawal_credentials=deposit_request.withdrawal_credentials, | |
amount=deposit_request.amount, | |
signature=deposit_request.signature, | |
slot=state.slot, | |
)) | |
def process_pending_deposits(state: BeaconState) -> None: | |
next_epoch = Epoch(get_current_epoch(state) + 1) | |
available_for_processing = state.deposit_balance_to_consume + get_activation_exit_churn_limit(state) | |
processed_amount = 0 | |
next_deposit_index = 0 | |
deposits_to_postpone = [] | |
is_churn_limit_reached = False | |
finalized_slot = compute_start_slot_at_epoch(state.finalized_checkpoint.epoch) | |
for deposit in state.pending_deposits: | |
# Do not process deposit requests if Eth1 bridge deposits are not yet applied. | |
if ( | |
# Is deposit request | |
deposit.slot > GENESIS_SLOT and | |
# There are pending Eth1 bridge deposits | |
state.eth1_deposit_index < state.deposit_requests_start_index | |
): | |
break | |
# Check if deposit has been finalized, otherwise, stop processing. | |
if deposit.slot > finalized_slot: | |
break | |
# Check if number of processed deposits has not reached the limit, otherwise, stop processing. | |
if next_deposit_index >= MAX_PENDING_DEPOSITS_PER_EPOCH: # MAX_PENDING_DEPOSITS_PER_EPOCH = 16 | |
break | |
# Read validator state | |
is_validator_exited = False | |
is_validator_withdrawn = False | |
validator_pubkeys = [v.pubkey for v in state.validators] | |
if deposit.pubkey in validator_pubkeys: | |
validator = state.validators[ValidatorIndex(validator_pubkeys.index(deposit.pubkey))] | |
is_validator_exited = validator.exit_epoch < FAR_FUTURE_EPOCH | |
is_validator_withdrawn = validator.withdrawable_epoch < next_epoch | |
if is_validator_withdrawn: | |
# Deposited balance will never become active. Increase balance but do not consume churn | |
apply_pending_deposit(state, deposit) | |
elif is_validator_exited: | |
# Validator is exiting, postpone the deposit until after withdrawable epoch | |
deposits_to_postpone.append(deposit) | |
else: | |
# Check if deposit fits in the churn, otherwise, do no more deposit processing in this epoch. | |
is_churn_limit_reached = processed_amount + deposit.amount > available_for_processing | |
if is_churn_limit_reached: | |
break | |
# Consume churn and apply deposit. | |
processed_amount += deposit.amount | |
apply_pending_deposit(state, deposit) | |
# Regardless of how the deposit was handled, we move on in the queue. | |
next_deposit_index += 1 | |
state.pending_deposits = state.pending_deposits[next_deposit_index:] + deposits_to_postpone | |
# Accumulate churn only if the churn limit has been hit. | |
if is_churn_limit_reached: | |
state.deposit_balance_to_consume = available_for_processing - processed_amount | |
else: | |
state.deposit_balance_to_consume = Gwei(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment