Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
17 changes: 17 additions & 0 deletions packages/state-transition/src/util/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,23 @@ export function getConsolidationChurnLimit(fork: ForkSeq, epochCtx: EpochCache):
return getBalanceChurnLimitFromCache(epochCtx) - getActivationExitChurnLimit(epochCtx);
}

// NOTE: duplicates the quotient/min choices in get{Exit,Activation,Consolidation}ChurnLimit.
export function getGloasChurnLimits(
config: ChainForkConfig,
totalActiveBalanceIncrements: number
): {exit: number; activation: number; consolidation: number} {
const exit = getBalanceChurnLimit(
totalActiveBalanceIncrements,
config.CHURN_LIMIT_QUOTIENT_GLOAS,
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
);
return {
exit,
activation: Math.min(config.MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT_GLOAS, exit),
consolidation: getBalanceChurnLimit(totalActiveBalanceIncrements, config.CONSOLIDATION_CHURN_LIMIT_QUOTIENT, 0),
};
}

export function getMaxEffectiveBalance(withdrawalCredentials: Uint8Array): number {
// Compounding withdrawal credential only available since Electra
if (hasCompoundingWithdrawalCredential(withdrawalCredentials)) {
Expand Down
83 changes: 61 additions & 22 deletions packages/state-transition/src/util/weakSubjectivity.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {BeaconConfig, ChainForkConfig} from "@lodestar/config";
import {
EFFECTIVE_BALANCE_INCREMENT,
ForkSeq,
MAX_DEPOSITS,
MAX_EFFECTIVE_BALANCE,
SLOTS_PER_EPOCH,
isForkPostElectra,
isForkPostGloas,
} from "@lodestar/params";
import {Epoch, Root, ssz} from "@lodestar/types";
import {Checkpoint} from "@lodestar/types/phase0";
Expand All @@ -14,10 +16,14 @@ import {BeaconStateAllForks, CachedBeaconStateAllForks} from "../types.js";
import {computeCheckpointEpochAtStateSlot, computeEpochAtSlot, getCurrentEpoch} from "./epoch.js";
import {getCurrentSlot} from "./slot.js";
import {
getActivationChurnLimit,
getActiveValidatorIndices,
getBalanceChurnLimit,
getBalanceChurnLimitFromCache,
getChurnLimit,
getConsolidationChurnLimit,
getExitChurnLimit,
getGloasChurnLimits,
} from "./validator.js";

export const ETH_TO_GWEI = 10 ** 9;
Expand Down Expand Up @@ -49,18 +55,26 @@ export function computeWeakSubjectivityPeriodCachedState(
const activeValidatorCount = state.epochCtx.currentShuffling.activeIndices.length;
const fork = config.getForkName(state.slot);

return isForkPostElectra(fork)
? computeWeakSubjectivityPeriodFromConstituentsElectra(
return isForkPostGloas(fork)
? computeWeakSubjectivityPeriodFromConstituentsGloas(
state.epochCtx.totalActiveBalanceIncrements,
getBalanceChurnLimitFromCache(state.epochCtx),
getExitChurnLimit(state.epochCtx),
getActivationChurnLimit(state.epochCtx),
getConsolidationChurnLimit(ForkSeq.gloas, state.epochCtx),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
)
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
activeValidatorCount,
state.epochCtx.totalActiveBalanceIncrements,
getChurnLimit(config, activeValidatorCount),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
);
: isForkPostElectra(fork)
? computeWeakSubjectivityPeriodFromConstituentsElectra(
state.epochCtx.totalActiveBalanceIncrements,
getBalanceChurnLimitFromCache(state.epochCtx),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
)
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
activeValidatorCount,
state.epochCtx.totalActiveBalanceIncrements,
getChurnLimit(config, activeValidatorCount),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
);
}

/**
Expand All @@ -80,22 +94,32 @@ export function computeWeakSubjectivityPeriod(config: ChainForkConfig, state: Be
totalActiveBalanceIncrements = 1;
}

return isForkPostElectra(fork)
? computeWeakSubjectivityPeriodFromConstituentsElectra(
const churnLimitsGloas = getGloasChurnLimits(config, totalActiveBalanceIncrements);

return isForkPostGloas(fork)
? computeWeakSubjectivityPeriodFromConstituentsGloas(
totalActiveBalanceIncrements,
getBalanceChurnLimit(
totalActiveBalanceIncrements,
config.CHURN_LIMIT_QUOTIENT,
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
),
churnLimitsGloas.exit,
churnLimitsGloas.activation,
churnLimitsGloas.consolidation,
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
)
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
activeIndices.length,
totalActiveBalanceIncrements,
getChurnLimit(config, activeIndices.length),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
);
: isForkPostElectra(fork)
? computeWeakSubjectivityPeriodFromConstituentsElectra(
totalActiveBalanceIncrements,
getBalanceChurnLimit(
totalActiveBalanceIncrements,
config.CHURN_LIMIT_QUOTIENT,
config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
)
: computeWeakSubjectivityPeriodFromConstituentsPhase0(
activeIndices.length,
totalActiveBalanceIncrements,
getChurnLimit(config, activeIndices.length),
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
);
Comment on lines +97 to +122

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Currently, getGloasChurnLimits is called unconditionally, even for pre-Gloas forks. If Gloas configuration parameters (like CHURN_LIMIT_QUOTIENT_GLOAS) are not defined or initialized on older forks or certain networks, this will result in NaN values being computed and passed around, which is unnecessary and potentially error-prone. Moving this calculation inside the isForkPostGloas(fork) conditional block ensures it is only executed when actually needed.

  if (isForkPostGloas(fork)) {
    const churnLimitsGloas = getGloasChurnLimits(config, totalActiveBalanceIncrements);
    return computeWeakSubjectivityPeriodFromConstituentsGloas(
      totalActiveBalanceIncrements,
      churnLimitsGloas.exit,
      churnLimitsGloas.activation,
      churnLimitsGloas.consolidation,
      config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
    );
  }

  return isForkPostElectra(fork)
    ? computeWeakSubjectivityPeriodFromConstituentsElectra(
        totalActiveBalanceIncrements,
        getBalanceChurnLimit(
          totalActiveBalanceIncrements,
          config.CHURN_LIMIT_QUOTIENT,
          config.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA
        ),
        config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
      )
    : computeWeakSubjectivityPeriodFromConstituentsPhase0(
        activeIndices.length,
        totalActiveBalanceIncrements,
        getChurnLimit(config, activeIndices.length),
        config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
      );

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted this in the PR desc, it is not perfect but it is imo harmless and much more readable as is.
Willing to change this if needed ofc.

}

export function computeWeakSubjectivityPeriodFromConstituentsPhase0(
Expand Down Expand Up @@ -142,6 +166,21 @@ export function computeWeakSubjectivityPeriodFromConstituentsElectra(
return minWithdrawabilityDelay + epochsForValidatorSetChurn;
}

export function computeWeakSubjectivityPeriodFromConstituentsGloas(
totalBalanceByIncrement: number,
exitChurnLimit: number,
activationChurnLimit: number,
consolidationChurnLimit: number,
minWithdrawabilityDelay: number
): number {
// Keep t as increment for now. Multiply final result by EFFECTIVE_BALANCE_INCREMENT
const t = totalBalanceByIncrement;
const delta = Math.floor((2 * exitChurnLimit) / 3) + Math.floor(activationChurnLimit / 3) + consolidationChurnLimit;
const epochsForValidatorSetChurn = Math.floor(((SAFETY_DECAY * t) / (2 * delta * 100)) * EFFECTIVE_BALANCE_INCREMENT);

return minWithdrawabilityDelay + epochsForValidatorSetChurn;
}

export function getLatestBlockRoot(state: BeaconStateAllForks): Root {
const header = ssz.phase0.BeaconBlockHeader.clone(state.latestBlockHeader);
if (ssz.Root.equals(header.stateRoot, ZERO_HASH)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {describe, expect, it} from "vitest";
import {config} from "@lodestar/config/default";
import {getBalanceChurnLimit, getChurnLimit} from "../../../src/util/validator.js";
import {getBalanceChurnLimit, getChurnLimit, getGloasChurnLimits} from "../../../src/util/validator.js";
import {
computeWeakSubjectivityPeriodFromConstituentsElectra,
computeWeakSubjectivityPeriodFromConstituentsGloas,
computeWeakSubjectivityPeriodFromConstituentsPhase0,
} from "../../../src/util/weakSubjectivity.js";

Expand Down Expand Up @@ -66,4 +67,28 @@ describe("weak subjectivity tests", () => {
}
);
});
describe("computeWeakSubjectivityPeriodFromConstituentsGloas", () => {
const testValues = [
{totalBalanceIncrement: 1_048_576, wsPeriod: 620},
{totalBalanceIncrement: 2_097_152, wsPeriod: 911},
{totalBalanceIncrement: 4_194_304, wsPeriod: 1348},
{totalBalanceIncrement: 8_388_608, wsPeriod: 1348},
{totalBalanceIncrement: 16_777_216, wsPeriod: 1484},
{totalBalanceIncrement: 33_554_432, wsPeriod: 1566},
];
it.each(testValues)(
"should have wsPeriod: $wsPeriod with totalActiveBalance: $totalBalanceIncrement",
({totalBalanceIncrement, wsPeriod: expectedWsPeriod}) => {
const churn = getGloasChurnLimits(config, totalBalanceIncrement);
const wsPeriod = computeWeakSubjectivityPeriodFromConstituentsGloas(
totalBalanceIncrement,
churn.exit,
churn.activation,
churn.consolidation,
config.MIN_VALIDATOR_WITHDRAWABILITY_DELAY
);
expect(wsPeriod).toBe(expectedWsPeriod);
}
);
});
});
1 change: 0 additions & 1 deletion specrefs/.ethspecify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,6 @@ exceptions:
- get_proposer_dependent_root#gloas

# gloas (new in alpha.3, not yet implemented)
- compute_weak_subjectivity_period#gloas
- block_to_light_client_header#gloas
- get_lc_execution_root#gloas
- is_valid_light_client_header#gloas
Expand Down
4 changes: 3 additions & 1 deletion specrefs/functions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1707,7 +1707,9 @@
</spec>

- name: compute_weak_subjectivity_period#gloas
sources: []
sources:
- file: packages/state-transition/src/util/weakSubjectivity.ts
search: export function computeWeakSubjectivityPeriod(
spec: |
<spec fn="compute_weak_subjectivity_period" fork="gloas" hash="8b1ddc92">
def compute_weak_subjectivity_period(state: BeaconState) -> uint64:
Expand Down
Loading