Skip to content

Boole convergence: non-blocking hardening follow-ups from the #2941 review #2978

Description

@iurii-ssv

Non-blocking hardening follow-ups from the #2941 (Boole → stage convergence) review, grouped by whether they should ship with the Boole fork or after. Items keep their original numbers; permalinks pin the reviewed revision.

Status (2026-08-11): Both "ship with the fork" items are still outstanding on stage — item 1's fix (#2973) is open/unmerged, and item 5 (spec re-pin) is blocked on the spec being tagged. Boole is still unscheduled on all shared networks (mainnet/holesky/hoodi pin Boole = math.MaxUint64; only local-testnet uses 0), so the pre-fork window item 1 warns about is still open. Among the "ship after" items, item 2 is now resolved (below); items 3, 4, 6, 7, and 8 remain open.

Ship with the Boole fork

Deferring these past the fork loses their value or blocks a clean mainnet cut.

1. A custom config can schedule Boole without rotating the domain (highest priority)

unmarshalFromConfig defaults an omitted next_domain_type to DomainType, so a custom network that sets forks: {boole: N} gets identical pre- and post-fork domains — QBFT message IDs never rotate at the boundary. Built-in configs are guarded by TestBuiltinNetworkDomainsAreUnique; custom ones have no runtime check.

Fix implemented in #2973 — not yet merged (still open against stage). On startup Network.Validate() returns an error and refuses to start (it does not merely warn) when BooleForkScheduled() is set and NextDomainType == DomainType, gated on the fork not yet being active. Land it before Boole is scheduled on any shared or custom network.

5. ssv-spec is pinned to a pseudo-version

go.mod and ssvsigner/go.mod pin ssv-spec v1.2.3-0.20260305184636-289c93aa4c12 — a commit, not a tag.

Action: re-pin both to the tagged spec release before mainnet (depends on the spec being tagged first).

Ship after the Boole fork

Hardening / housekeeping; none affect fork correctness on the built-in networks.

2. Boole topics are whitelisted even when no fork is scheduled

commons.Topics registers all 128 Boole topics in the subscription-filter whitelist unconditionally, even where Boole is unscheduled (e.g. mainnet). Pre-fork nothing validates on them, so exposure is limited to peers forming meshes on dead topics.

Resolved — superseded by #2971 (merged). #2971 reworked this function to be slot-aware but deliberately keeps "always include the Boole set", with an in-code rationale (Boole subscriptions can legitimately open ahead of the fork). The proposed BooleForkScheduled() gate was consciously not adopted, so this item can be closed as superseded. Low severity.

3. Pre-fork decode cap for partial-signature messages grew ~5×

maxPartialSignatureMessages = 5048 is the post-fork (AggregatorCommittee) worst case, but the derived maxEncodedPartialSignatureSize is enforced fork-independently in validatePartialSignatureMessage — the pre-fork acceptance cap jumps ~151 KB → ~763 KB. Spec-derived and drift-guarded, and gossip scoring bounds abuse.

Action: optionally make the cap fork-aware (1000 pre-fork, 5048 from the fork) if pre-fork DoS surface is a concern.

4. Unchecked type assertions when registering committee runners

createRunner asserts r.(*runner.CommitteeRunner) / r.(*runner.AggregatorCommitteeRunner) unchecked. The invariant holds today, but a future CreateRunnerFn returning a mismatched type would panic with a bare runtime error.

Action: use checked assertions and return an error (or a descriptive logger.Panic, matching the default branch).

6. local-testnet activates Boole from genesis

LocalTestnetSSV sets Boole: 0, flipping default local-dev clusters (make docker-all / docker-debug) to post-fork behavior from slot 0 — presumably intentional.

Action: confirm intent and note the local-dev flip in release notes.

7. Role-string mappers rely on doc-comment lockstep only

ssvtypes.RunnerRoleToString and message.RunnerRoleToString are independent mappers that must agree (utils.FormatRunnerRole delegates to the first), but the contract lives only in doc comments — no test asserts it.

Action: add a lockstep test asserting message.RunnerRoleToString(r) == utils.FormatRunnerRole(r) for every role, or unify on one mapper.

8. Codecov project status left informational

codecov.yml sets informational: true to avoid phantom coverage drops on the stacked convergence PRs.

Action: revert once the stack (#2971#2975) has landed and baselines are stable.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions