-
-
Notifications
You must be signed in to change notification settings - Fork 450
feat: switch to compounding from consolidation requests #7122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
808b37b
9673c6c
65f06af
37b1b7b
7e0957e
522e8c9
46b0d9a
12a5914
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,42 +1,51 @@ | ||
| import {electra, ssz} from "@lodestar/types"; | ||
| import {FAR_FUTURE_EPOCH, MIN_ACTIVATION_BALANCE, PENDING_CONSOLIDATIONS_LIMIT} from "@lodestar/params"; | ||
|
|
||
| import {toHex} from "@lodestar/utils"; | ||
| import {CachedBeaconStateElectra} from "../types.js"; | ||
| import {getConsolidationChurnLimit, isActiveValidator} from "../util/validator.js"; | ||
| import {hasExecutionWithdrawalCredential} from "../util/electra.js"; | ||
| import {hasExecutionWithdrawalCredential, switchToCompoundingValidator} from "../util/electra.js"; | ||
| import {computeConsolidationEpochAndUpdateChurn} from "../util/epoch.js"; | ||
| import {hasEth1WithdrawalCredential} from "../util/capella.js"; | ||
|
|
||
| // TODO Electra: Clean up necessary as there is a lot of overlap with isValidSwitchToCompoundRequest | ||
| export function processConsolidationRequest( | ||
| state: CachedBeaconStateElectra, | ||
| consolidationRequest: electra.ConsolidationRequest | ||
| ): void { | ||
| // If the pending consolidations queue is full, consolidation requests are ignored | ||
| if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { | ||
| const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest; | ||
| const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); | ||
| const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); | ||
|
|
||
| if (sourceIndex === null || targetIndex === null) { | ||
| return; | ||
| } | ||
|
|
||
| // If there is too little available consolidation churn limit, consolidation requests are ignored | ||
| if (getConsolidationChurnLimit(state.epochCtx) <= MIN_ACTIVATION_BALANCE) { | ||
| if (isValidSwitchToCompoundRequest(state, consolidationRequest)) { | ||
| switchToCompoundingValidator(state, sourceIndex); | ||
| // Early return since we have already switched validator to compounding | ||
| return; | ||
| } | ||
|
|
||
| const {sourcePubkey, targetPubkey} = consolidationRequest; | ||
| const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); | ||
| const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); | ||
|
|
||
| if (sourceIndex === null || targetIndex === null) { | ||
| // If the pending consolidations queue is full, consolidation requests are ignored | ||
| if (state.pendingConsolidations.length >= PENDING_CONSOLIDATIONS_LIMIT) { | ||
| return; | ||
| } | ||
|
|
||
| // If there is too little available consolidation churn limit, consolidation requests are ignored | ||
| if (getConsolidationChurnLimit(state.epochCtx) <= MIN_ACTIVATION_BALANCE) { | ||
| return; | ||
| } | ||
| // Verify that source != target, so a consolidation cannot be used as an exit. | ||
| if (sourceIndex === targetIndex) { | ||
| return; | ||
| } | ||
|
|
||
| const sourceValidator = state.validators.get(sourceIndex); | ||
| const targetValidator = state.validators.getReadonly(targetIndex); | ||
| const sourceWithdrawalAddress = sourceValidator.withdrawalCredentials.subarray(12); | ||
| const currentEpoch = state.epochCtx.epoch; | ||
| const sourceWithdrawalAddressStr = toHex(sourceValidator.withdrawalCredentials.subarray(12)); | ||
| const sourceAddressStr = toHex(sourceAddress); | ||
|
|
||
| // Verify withdrawal credentials | ||
| if ( | ||
|
|
@@ -46,7 +55,7 @@ export function processConsolidationRequest( | |
| return; | ||
| } | ||
|
|
||
| if (Buffer.compare(sourceWithdrawalAddress, consolidationRequest.sourceAddress) !== 0) { | ||
| if (sourceWithdrawalAddressStr !== sourceAddressStr) { | ||
| return; | ||
| } | ||
|
|
||
|
|
@@ -70,4 +79,56 @@ export function processConsolidationRequest( | |
| targetIndex, | ||
| }); | ||
| state.pendingConsolidations.push(pendingConsolidation); | ||
|
|
||
| // Churn any target excess active balance of target and raise its max | ||
| if (hasEth1WithdrawalCredential(targetValidator.withdrawalCredentials)) { | ||
| switchToCompoundingValidator(state, targetIndex); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Determine if we should set consolidation target validator to compounding credential | ||
| */ | ||
| function isValidSwitchToCompoundRequest( | ||
| state: CachedBeaconStateElectra, | ||
| consolidationRequest: electra.ConsolidationRequest | ||
| ): boolean { | ||
| const {sourcePubkey, targetPubkey, sourceAddress} = consolidationRequest; | ||
| const sourceIndex = state.epochCtx.getValidatorIndex(sourcePubkey); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could save the index lookup if we compare the pubkeys first, not sure if it's worth though but would match more closely to the spec
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Let's do the optimization later. This part of spec is sub-optimized and will very likely to be cleaned up in alpha 9 or 10. We can optimize when the spec gets refactored. |
||
| const targetIndex = state.epochCtx.getValidatorIndex(targetPubkey); | ||
|
|
||
| // Verify pubkey exists | ||
| if (sourceIndex === null) { | ||
| return false; | ||
| } | ||
|
|
||
| // Switch to compounding requires source and target be equal | ||
| if (sourceIndex !== targetIndex) { | ||
| return false; | ||
| } | ||
|
|
||
| const sourceValidator = state.validators.getReadonly(sourceIndex); | ||
| const addressStr = toHex(sourceValidator.withdrawalCredentials.subarray(12)); | ||
ensi321 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| const sourceAddressStr = toHex(sourceAddress); | ||
| // Verify request has been authorized | ||
| if (addressStr !== sourceAddressStr) { | ||
| return false; | ||
| } | ||
|
|
||
| // Verify source withdrawal credentials | ||
| if (!hasEth1WithdrawalCredential(sourceValidator.withdrawalCredentials)) { | ||
| return false; | ||
| } | ||
|
|
||
| // Verify the source is active | ||
| if (!isActiveValidator(sourceValidator, state.epochCtx.epoch)) { | ||
| return false; | ||
| } | ||
|
|
||
| // Verify exit for source has not been initiated | ||
| if (sourceValidator.exitEpoch !== FAR_FUTURE_EPOCH) { | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.