Skip to content

boole-convergence polish: gating docs, startup fork validation, spectest bound (#2968 items 4, 6, 7) - #2973

Open
momosh-ssv wants to merge 12 commits into
stagefrom
fix/2968-cleanups
Open

boole-convergence polish: gating docs, startup fork validation, spectest bound (#2968 items 4, 6, 7)#2973
momosh-ssv wants to merge 12 commits into
stagefrom
fix/2968-cleanups

Conversation

@momosh-ssv

Copy link
Copy Markdown
Contributor

Items 4, 6 and 7 of #2968, one commit each:

  • Item 4 (docs only) — the BooleFork() gate on the legacy Alan RoleAggregator/RoleSyncCommitteeContribution runners is now documented as a deliberate share-add-time snapshot: the cross-population asymmetry is bounded to the Boole subsequent window (SlotsPerEpoch + booleSubsequentWindowLateSlots; 34 slots on mainnet), affects only already-decided pre-fork stragglers, and the runners retire with the Alan topics. Decision recorded on the issue: not worth restructuring the one-shot runner-map construction to slot-gate a dormant path.
  • Item 6Network.Validate(), called right after the Network is assembled at startup: hard error when a scheduled forks.boole epoch would overflow FirstSlotAtEpoch (or SlotsPerEpoch is zero — the review caught that the overflow guard alone would panic on that same malformed-config class); operator-actionable warning when Boole is scheduled but NextDomainType == DomainType (the exact signature of a forgotten next_domain_type, which would "activate" the fork with zero observable domain change).
  • Item 7 — the alan-spec error-code remap bound is derived from TimeoutInstanceErrorCode + 2 (= 72, the real v1.2.2 maximum) instead of the disconnected magic 79, so a spec bump adding codes can't silently widen the remap. Builds under -tags alan_spec (that leg doesn't run in normal CI).

The BooleFork() gate on the RoleAggregator/RoleSyncCommitteeContribution
runners is a deliberate share-add-time snapshot: the resulting
cross-population asymmetry is bounded to the Boole subsequent window
(SlotsPerEpoch + booleSubsequentWindowLateSlots; 34 slots on mainnet)
and affects only already-decided pre-fork aggregator stragglers. These
runners retire wholesale with the Alan topics.

Item 4 of #2968 (decision: document, don't slot-gate).
A garbage forks.boole epoch silently overflowed FirstSlotAtEpoch, and a
custom network scheduling Boole without setting next_domain_type
"activates" the fork with zero observable domain change (unmarshal
defaults the next domain to the current one). Add Network.Validate() -
hard error on the overflow and zero-slots-per-epoch cases,
operator-actionable warning on the same-domain case - called right
after the Network is assembled.

Item 6 of #2968.
The remap's magic upper bound (79) was disconnected from the real
v1.2.2 maximum (72). Derive it from TimeoutInstanceErrorCode - the last
pre-Boole-era spec error code - plus the documented +2 shift, so a spec
bump that adds codes can't silently widen the remap.

Item 7 of #2968.
@momosh-ssv
momosh-ssv requested review from a team as code owners July 30, 2026 12:32
@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds Boole fork configuration validation during node startup and tightens Alan spectest compatibility behavior.

  • Rejects scheduled Boole forks whose slot conversion would divide by zero or overflow.
  • Warns operators when a scheduled fork leaves the domain type unchanged.
  • Documents the intentional share-add-time snapshot used for legacy Alan runners.
  • Derives the Alan error-code remapping boundary from the spec enum instead of a disconnected magic value.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking issues identified.

The startup validation runs after the consensus client has initialized its beacon configuration, correctly handles the unscheduled-fork sentinel, and the remaining changes are scoped documentation and spectest compatibility refinements.

Important Files Changed

Filename Overview
cli/operator/node.go Validates the fully assembled network configuration before continuing node startup and logs operator-actionable warnings.
networkconfig/network.go Adds scheduled-Boole validation for zero slots per epoch, slot-conversion overflow, and unchanged domain types.
networkconfig/network_test.go Covers validation errors, warnings, valid scheduled configurations, and the unscheduled sentinel.
operator/validator/controller.go Documents why legacy runner selection is intentionally snapshotted when a share is added.
protocol/v2/qbft/spectest/error_code_map_alan.go Replaces the Alan compatibility remapping magic bound with one derived from the final legacy error-code enum.

Reviews (1): Last reviewed commit: "protocol/v2/qbft/spectest: derive the al..." | Re-trigger Greptile

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 70.7%. Comparing base (874ba31) to head (699a9a7).

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@momosh-ssv
momosh-ssv requested review from iurii-ssv and y0sher July 31, 2026 08:35
iurii-ssv
iurii-ssv previously approved these changes Jul 31, 2026

@iurii-ssv iurii-ssv 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.

A few minor, non-blocking nits.

Comment thread operator/validator/controller.go Outdated
Comment thread protocol/v2/qbft/spectest/error_code_map_alan.go
Comment thread networkconfig/network_test.go
Base automatically changed from integration/boole-convergence to stage August 5, 2026 08:28
@momosh-ssv
momosh-ssv dismissed iurii-ssv’s stale review August 5, 2026 08:28

The base branch was changed.

An error occurred while trying to automatically change base from integration/boole-convergence to stage August 5, 2026 08:28
@momosh-ssv
momosh-ssv requested a review from iurii-ssv August 6, 2026 08:45
Comment thread networkconfig/network.go Outdated
@momosh-ssv
momosh-ssv requested a review from nkryuchkov August 6, 2026 10:24
Comment thread networkconfig/network.go Outdated
…l ahead

A scheduled Boole fork whose NextDomainType equals DomainType is the
signature of a config that forgot to set NextDomainType (the YAML
unmarshal defaults it), so fail startup instead of warning while the
fork is still ahead. Once the fork is active, equality is legitimate
steady state - a post-fork config may collapse both fields to the
post-fork domain - so it passes validation.
@momosh-ssv
momosh-ssv requested a review from y0sher August 6, 2026 11:46
y0sher
y0sher previously approved these changes Aug 6, 2026

@y0sher y0sher 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.

lgtm, ut failing.

@iurii-ssv iurii-ssv 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.

A bunch of small suggestions.

Comment thread networkconfig/network.go Outdated
Comment thread networkconfig/network.go Outdated
Comment thread networkconfig/network.go Outdated
Comment thread cli/operator/node.go
@momosh-ssv

Copy link
Copy Markdown
Contributor Author

ut failing

It's a flake ❄ will fix in followups.
Thanks for the reviews, guys

@momosh-ssv
momosh-ssv enabled auto-merge August 6, 2026 13:04
EstimatedCurrentSlot panics while the wall clock is still before
GenesisTime, so the unchanged-domain check would panic instead of
returning the intended error on a not-yet-genesis network. Before
genesis a scheduled fork is by definition not yet active, so guard the
wall-clock read and keep reporting the misconfiguration as an error.
Once the unchanged-domain case became a hard error, no code path ever
populated the warnings return: the node.go warn loop never ran and the
test's expectedWarnings field only ever asserted emptiness. Collapse
the signature to a plain error so it no longer advertises a code path
that can't happen.
Validate and inBooleSubsequentWindowWithSlots duplicated the
MaxUint64/SlotsPerEpoch bound verbatim; a cross-reference comment kept
them associated but nothing kept them in lockstep. Extract
maxEpochConvertibleToSlot so both sites derive the bound from one
place.

@iurii-ssv iurii-ssv 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.

LGTM (couple nits below)

beacon := *TestNetwork.Beacon
beacon.SlotsPerEpoch = test.slotsPerEpoch
slotsSinceGenesis := uint64(test.currentEpoch) * test.slotsPerEpoch
beacon.GenesisTime = time.Now().Add(-time.Duration(slotsSinceGenesis) * beacon.SlotDuration)

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.

Nit (optional, maintainability) — non-blocking: this per-case beacon setup duplicates beaconAtEpoch just below (same *TestNetwork.Beacon copy + GenesisTime = now - slotsSinceGenesis*SlotDuration). It can't reuse beaconAtEpoch as-is because this test varies SlotsPerEpoch (including 0) and needs the preGenesis override — but a small beaconAt(epoch, slotsPerEpoch) helper (keeping the pre-genesis branch here) would fold the genesis math back into one place. Fine to leave if you'd rather not churn the helper.

{
name: "clean_next_domain_equals_domain_after_fork",
boole: 10,
currentEpoch: 20,

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.

Nit (optional, coverage) — non-blocking: the domain-equality cases cover currentEpoch before the fork (before_fork = 5) and well after (after_fork = 20), but not the exact activation epoch currentEpoch == boole (= 10), where BooleFork() flips on >=. This is a different axis from the fork-value boundaries already added (clean_genesis_fork, clean_at_max_epoch_boundary) — it's the wall-clock activation edge. Low value, since TestBooleForkAtSlot's at_fork case already pins the >= semantics, so genuinely fine to skip; flagging only to fully close the transition edge.

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.

5 participants