Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 76 additions & 2 deletions specs/_features/maxeb_increase/capella.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ def floorlog2(x: int) -> uint64:
MAX_BLS_TO_EXECUTION_CHANGES = 16
MAX_WITHDRAWALS_PER_PAYLOAD = uint64(16)
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP = 16384

DOMAIN_CONSOLIDATION = DomainType('0x0B000000')
MAX_CONSOLIDATIONS = 4
Comment thread
mkalinin marked this conversation as resolved.
Outdated
PENDING_CONSOLIDATIONS_LIMIT = uint64(1048576) # MAX_CONSOLIDATIONS * SLOTS_PER_EPOCH * 8192

class Configuration(NamedTuple):
PRESET_BASE: str
Expand Down Expand Up @@ -425,6 +427,19 @@ class SignedVoluntaryExit(Container):
message: VoluntaryExit
signature: BLSSignature

class Consolidation(Container):
source_index: ValidatorIndex
Comment thread
mkalinin marked this conversation as resolved.
target_index: ValidatorIndex
epoch: Epoch


class SignedConsolidation(Container):
message: Consolidation
signature: BLSSignature

class PendingConsolidation(Container):
source_index: ValidatorIndex
target_index: ValidatorIndex

class SignedBeaconBlockHeader(Container):
message: BeaconBlockHeader
Expand Down Expand Up @@ -636,6 +651,8 @@ class BeaconBlockBody(Container):
execution_payload: ExecutionPayload
# Capella operations
bls_to_execution_changes: List[SignedBLSToExecutionChange, MAX_BLS_TO_EXECUTION_CHANGES] # [New in Capella]
# MaxEB operations
consolidations: List[SignedConsolidation, MAX_CONSOLIDATIONS] # [New in MAXEB]


class BeaconBlock(Container):
Expand Down Expand Up @@ -707,6 +724,7 @@ class BeaconState(Container):
historical_summaries: List[HistoricalSummary, HISTORICAL_ROOTS_LIMIT] # [New in Capella]
pending_balance_deposits: List[PendingBalanceDeposit]
pending_partial_withdrawals: List[PartialWithdrawal]
pending_consolidations: List[PendingConsolidation, PENDING_CONSOLIDATIONS_LIMIT]


@dataclass(eq=True, frozen=True)
Expand Down Expand Up @@ -1327,6 +1345,7 @@ def process_epoch(state: BeaconState) -> None:
process_slashings(state)
process_eth1_data_reset(state)
process_pending_balance_deposits(state)
process_pending_consolidations(state)
process_effective_balance_updates(state)
process_slashings_reset(state)
process_randao_mixes_reset(state)
Expand Down Expand Up @@ -1627,14 +1646,37 @@ def process_pending_balance_deposits(state: BeaconState) -> None:
state.pending_balance_deposits = state.pending_balance_deposits[next_pending_deposit_index:]


def apply_pending_consolidation(state: BeaconState, pending_consolidation: PendingConsolidation) -> None:
source_validator = state.validators[pending_consolidation.source_index]
target_validator = state.validators[pending_consolidation.target_index]
# Move active balance
Comment thread
mkalinin marked this conversation as resolved.
Outdated
active_balance_ceil = MIN_ACTIVATION_BALANCE if has_eth1_withdrawal_credential(source_validator) else MAX_EFFECTIVE_BALANCE
Comment thread
mkalinin marked this conversation as resolved.
Outdated
active_balance = min(state.balances[source_validator.index], active_balance_ceil)
state.balances[target_validator.index] += active_balance
# Excess balance above current active balance ceil will be withdrawn
state.balances[source_validator.index] = state.balances[target_validator.index] - active_balance


def process_pending_consolidations(state: BeaconState) -> None:
next_pending_consolidation = 0
for pending_consolidation in state.pending_consolidations:
source_validator = state.validators[pending_consolidation.source_index]
if source_validator.exit_epoch > get_current_epoch(state):
break

apply_pending_consolidation(state, pending_consolidation)
next_pending_consolidation += 1

state.pending_consolidations = state.pending_consolidations[next_pending_consolidation:]

def process_effective_balance_updates(state: BeaconState) -> None:
# Update effective balances with hysteresis
for index, validator in enumerate(state.validators):
balance = state.balances[index]
HYSTERESIS_INCREMENT = uint64(EFFECTIVE_BALANCE_INCREMENT // HYSTERESIS_QUOTIENT)
DOWNWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_DOWNWARD_MULTIPLIER
UPWARD_THRESHOLD = HYSTERESIS_INCREMENT * HYSTERESIS_UPWARD_MULTIPLIER
EFFECTIVE_BALANCE_LIMIT = MAX_EFFECTIVE_BALANCE if has_compounding_withdrawal_credential(validator) else MIN_ACTIVATION_BALANCE
EFFECTIVE_BALANCE_LIMIT = MAX_EFFECTIVE_BALANCE if has_compounding_withdrawal_credential(validator) else MIN_ACTIVATION_BALANCE
if (
balance + DOWNWARD_THRESHOLD < validator.effective_balance
or validator.effective_balance + UPWARD_THRESHOLD < balance
Expand Down Expand Up @@ -1735,6 +1777,7 @@ def for_ops(operations: Sequence[Any], fn: Callable[[BeaconState, Any], None]) -
for_ops(body.voluntary_exits, process_voluntary_exit)
for_ops(body.bls_to_execution_changes, process_bls_to_execution_change) # [New in Capella]
for_ops(body.execution_payload.withdraw_request, process_execution_layer_withdraw_request)
for_ops(body.consolidations, process_consolidation)


def process_execution_layer_withdraw_request(
Expand Down Expand Up @@ -1939,6 +1982,37 @@ def process_voluntary_exit(state: BeaconState, signed_voluntary_exit: SignedVolu
initiate_validator_exit(state, voluntary_exit.validator_index)


def process_consolidation(state: BeaconState, signed_consolidation: SignedConsolidation) -> None:
consolidation = signed_consolidation.message
Comment thread
mkalinin marked this conversation as resolved.
target_validator = state.validators[consolidation.target_index]
source_validator = state.validators[consolidation.source_index]
# Verify the source and the target are active
assert is_active_validator(source_validator)
assert is_active_validator(target_validator)
# Verify exits for source and target have not been initiated
assert source_validator.exit_epoch == FAR_FUTURE_EPOCH
assert target_validator.exit_epoch == FAR_FUTURE_EPOCH
# Consolidations must specify an epoch when they become valid; they are not valid before then
assert get_current_epoch(state) >= consolidation.epoch

# Verify the source and the target have Execution layer withdrawal credentials
assert source_validator.withdrawal_credentials[:1] in (ETH1_ADDRESS_WITHDRAWAL_PREFIX, COMPOUNDING_WITHDRAWAL_PREFIX)
assert target_validator.withdrawal_credentials[:1] in (ETH1_ADDRESS_WITHDRAWAL_PREFIX, COMPOUNDING_WITHDRAWAL_PREFIX)
# Verify the same withdrawal address
Comment thread
mkalinin marked this conversation as resolved.
assert source_validator.withdrawal_credentials[1:] == target_validator.withdrawal_credentials[1:]

# Verify consolidation is signed by the source and the target
domain = compute_domain(DOMAIN_CONSOLIDATION, genesis_validators_root=state.genesis_validators_root)
signing_root = compute_signing_root(consolidation, domain)
pubkeys = [source_validator.pubkey, target_validator.pubkey]
assert bls.FastAggregateVerify(pubkeys, signing_root, signed_consolidation.signature)

# Initiate source validator exit and append pending consolidation
initiate_validator_exit(state, source_validator.index)
state.pending_consolidations.append(PendingConsolidation(source_index = source_validator.source,
target_index = target_validator.index))


def is_previous_epoch_justified(store: Store) -> bool:
current_slot = get_current_slot(store)
current_epoch = compute_epoch_at_slot(current_slot)
Expand Down