Skip to content

feat: implement compute_weak_subjectivity_period for Gloas (EIP-8061)#9625

Open
markolazic01 wants to merge 2 commits into
ChainSafe:unstablefrom
markolazic01:feat/gloas-weak-subjectivity
Open

feat: implement compute_weak_subjectivity_period for Gloas (EIP-8061)#9625
markolazic01 wants to merge 2 commits into
ChainSafe:unstablefrom
markolazic01:feat/gloas-weak-subjectivity

Conversation

@markolazic01

Copy link
Copy Markdown
Contributor

Motivation

Implements the Gloas compute_weak_subjectivity_period (modified in EIP-8061),
which the weak-subjectivity guide updated to weight churn asymmetrically.
Resolves the gap left by #9305, which implements EIP-8061.

Description

  • Add computeWeakSubjectivityPeriodFromConstituentsGloas, following the
    Phase0/Electra FromConstituents pattern (caller supplies pre-computed churn
    limits; function does only the period math).
  • Assemble delta per spec: 2/3 * exit + 1/3 * activation + consolidation,
    flooring each weighted term independently, then apply the increment→Gwei
    scaling as the Electra path does.
  • Gate Gloas ahead of Electra in both computeWeakSubjectivityPeriod and
    computeWeakSubjectivityPeriodCachedState (Gloas is post-Electra, so the
    order matters).
  • Add getGloasChurnLimits helper for the plain-state path, which has no
    EpochCache to hand the existing epochCtx-based churn helpers.
  • Register compute_weak_subjectivity_period#gloas in specrefs (remove the
    alpha.3 "not yet implemented" exception, point it at the implementation).
  • Add unit tests with expected periods derived independently from the spec's
    integer Gwei arithmetic, covering the exit MIN floor, the activation cap, and
    the exit/activation asymmetry EIP-8061 introduces.

Closes #9337

  • getGloasChurnLimits is called before the fork specific computeWeakSubjectivity calls for readability, it also runs on pre-Gloas forks but is negligible.
  • getGloasChurnLimits is a function made due to reasons of existing naming entanglement:
    getBalanceChurnLimit -> requires no epoch cache
    getBalanceChurnLimitFromCache -> requires cache
    getActivationChurnLimit(and other wrappers) -> require cache
    This didn't allow for elegant creation of 'non-cache-requiring' wrappers or helpers, and that is why the most elegant solution seemed to be getGloasChurnLimits.

This topic should be addressed in another PR, I'll open a follow-up issue for it.

AI Assistance Disclosure

Used Claude to navigate the repo, review the diffs, and derive/verify the unit test values; it also drafted parts of this description. All code was authored and applied manually.

@markolazic01 markolazic01 requested a review from a team as a code owner July 9, 2026 08:57
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@markolazic01

Copy link
Copy Markdown
Contributor Author

/gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request implements the weak subjectivity period calculation for the Gloas fork, introducing getGloasChurnLimits and computeWeakSubjectivityPeriodFromConstituentsGloas along with corresponding unit tests and spec reference updates. The review feedback suggests optimizing computeWeakSubjectivityPeriod by moving the getGloasChurnLimits call inside the Gloas-specific conditional block. This prevents unnecessary execution and potential NaN errors on older forks where Gloas configuration parameters might not be defined.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +97 to +122
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
);

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update weak subjectivity calculation for EIP-8061

2 participants