Skip to content

Boole domain#2679

Open
nkryuchkov wants to merge 11 commits intoboole-forkfrom
boole-domain
Open

Boole domain#2679
nkryuchkov wants to merge 11 commits intoboole-forkfrom
boole-domain

Conversation

@nkryuchkov
Copy link
Contributor

@nkryuchkov nkryuchkov commented Feb 6, 2026

The PR must be rebased onto the boole-fork branch after both #2302 and #2503 are merged
The PR must be rebased onto the boole-fork branch after #2503 is merged

@nkryuchkov nkryuchkov marked this pull request as ready for review February 6, 2026 21:04
@nkryuchkov nkryuchkov requested review from a team as code owners February 6, 2026 21:04
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 6, 2026

Greptile Overview

Greptile Summary

This PR implements the Boole domain fork infrastructure, enabling dynamic domain type selection based on slot/epoch to support smooth transition between Alan and Boole domains.

Key Changes:

  • Added NextDomainType field to SSV configuration for specifying the post-fork domain
  • Converted static Identifier field to dynamic IdentifierFn in QBFT controller for height-based domain resolution
  • Implemented slot-based domain type resolution through DomainTypeAtSlot() and NextDomainTypeAtSlot() methods
  • Added domain compatibility checking in peer discovery to accept both current and next domains during transition window
  • Updated message validation to verify domain type matches expected domain at message's slot
  • Modified P2P handshake filters to accept multiple domain types during fork transition periods
  • Removed unused BeaconSigner and Domain fields from QBFT config as domain is now dynamically resolved
  • Updated all runner types (proposer, aggregator, committee, etc.) to use slot-based domain when creating message IDs

Transition Window Handling:
The PR implements a transition window (PRIOR_WINDOW of 1 epoch before fork, SUBSEQUENT_WINDOW of 1 slot after fork) where nodes accept connections from peers using either the old or new domain type, ensuring smooth network-wide migration.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • The implementation is well-structured with comprehensive test coverage for domain type resolution logic. All changes follow a consistent pattern of converting static domain types to dynamic slot-based resolution. The transition window logic ensures network compatibility during the fork. No breaking changes to existing functionality outside of the intended fork mechanism.
  • No files require special attention

Important Files Changed

Filename Overview
networkconfig/network.go Added domain type selection logic for Boole fork with slot-based domain type resolution and transition window handling
networkconfig/ssv.go Added NextDomainType field to SSV config for Boole fork support with proper marshaling and validation
protocol/v2/qbft/controller/controller.go Changed Identifier from static field to dynamic function for height-based domain type resolution with proper JSON marshaling
operator/validator/controller.go Updated controller initialization to use identifierFn with slot-based domain type for both validator and committee runners
network/discovery/dv5_service.go Implemented domain compatibility checking during peer discovery to support both current and next domain types during transition
network/p2p/p2p_setup.go Updated handshake filters to accept multiple domain types during Boole transition window using dynamic domain type resolution
message/validation/validation.go Added validateDomainAtSlot function to check message domain type matches expected domain at given slot
protocol/v2/qbft/config.go Removed unused BeaconSigner and Domain fields from QBFT config as domain type is now dynamically resolved

Sequence Diagram

sequenceDiagram
    participant Node as SSV Node
    participant NetCfg as NetworkConfig
    participant Disc as Discovery (dv5)
    participant P2P as P2P Layer
    participant Valid as Message Validator
    participant QBFT as QBFT Controller
    
    Note over Node,QBFT: Pre-Boole Fork (current domain)
    
    Node->>NetCfg: EstimatedCurrentSlot()
    NetCfg->>NetCfg: Check if slot >= Boole fork epoch
    NetCfg-->>Node: Returns current slot
    
    Node->>NetCfg: DomainTypeAtSlot(slot)
    alt Slot < Boole Fork
        NetCfg-->>Node: Return DomainType (Alan)
    else Slot >= Boole Fork
        NetCfg-->>Node: Return NextDomainType (Boole)
    end
    
    Note over Node,QBFT: Peer Discovery with Domain Compatibility
    
    Disc->>NetCfg: currentDomainType()
    NetCfg-->>Disc: Current domain
    Disc->>NetCfg: nextDomainType()
    NetCfg-->>Disc: Next domain
    
    Disc->>Disc: Check peer's domain & nextDomain
    alt In Transition Window
        Disc->>Disc: Accept if peer matches current OR next domain
    else Outside Transition
        Disc->>Disc: Accept only if peer matches current domain
    end
    
    Note over Node,QBFT: P2P Handshake Filter Setup
    
    P2P->>NetCfg: InBooleTransitionWindow(slot)
    alt In Transition Window
        P2P->>P2P: Create NetworkIDFilterAny([current, next])
    else Outside Transition
        P2P->>P2P: Create NetworkIDFilter(current)
    end
    
    Note over Node,QBFT: Message Creation & Validation
    
    QBFT->>NetCfg: DomainTypeAtSlot(height as slot)
    NetCfg-->>QBFT: Domain type for slot
    QBFT->>QBFT: Create identifier with domain+pubkey+role
    QBFT->>P2P: Broadcast message
    
    P2P->>Valid: Validate incoming message
    Valid->>Valid: Extract slot from message
    Valid->>NetCfg: DomainTypeAtSlot(slot)
    NetCfg-->>Valid: Expected domain for slot
    Valid->>Valid: Compare message domain with expected
    alt Domain matches
        Valid-->>P2P: Accept message
    else Domain mismatch
        Valid-->>P2P: Reject (ErrWrongDomain)
    end
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

8 files reviewed, no comments

Edit Code Review Agent Settings | Greptile

@y0sher y0sher added the boole label Feb 8, 2026
@y0sher y0sher added the boole label Feb 8, 2026
@nkryuchkov nkryuchkov changed the base branch from deploy/nettop+aggcomm-2 to aggregator-committee February 9, 2026 18:18
@codecov
Copy link

codecov bot commented Feb 9, 2026

Codecov Report

❌ Patch coverage is 49.59350% with 62 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (boole-fork@92cc23d). Learn more about missing BASE report.

Files with missing lines Patch % Lines
operator/validator/controller.go 6.2% 14 Missing and 1 partial ⚠️
network/peers/connections/handshaker.go 14.2% 12 Missing ⚠️
network/p2p/p2p_setup.go 53.3% 6 Missing and 1 partial ⚠️
cli/generate_config.go 0.0% 6 Missing ⚠️
exporter/api/decided/stream.go 0.0% 4 Missing ⚠️
network/discovery/testutils.go 0.0% 4 Missing ⚠️
networkconfig/ssv.go 33.3% 2 Missing and 2 partials ⚠️
cli/operator/node.go 0.0% 2 Missing ⚠️
exporter/api/msg.go 50.0% 2 Missing ⚠️
message/validation/partial_validation.go 0.0% 1 Missing and 1 partial ⚠️
... and 3 more

☔ View full report in Codecov by Sentry.
📢 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.

Base automatically changed from aggregator-committee to boole-fork February 16, 2026 09:01
Comment on lines +237 to +238
domain := r.BaseRunner.NetworkConfig.DomainTypeAtSlot(decidedValue.Duty.Slot)
msgID := spectypes.NewMsgID(domain, r.GetShare().ValidatorPubKey[:], r.BaseRunner.RunnerRoleType)
Copy link
Contributor

Choose a reason for hiding this comment

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

should we send old aggregator runner messages using the new domain type after fork? I'm not sure about the change here..

Copy link
Contributor Author

@nkryuchkov nkryuchkov Feb 16, 2026

Choose a reason for hiding this comment

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

It shouldn't be possible because we won't have any aggregator runner duties during Boole epochs. We could have used r.BaseRunner.NetworkConfig.DomainType but I like the current code better, because it keeps the runner choice logic abstract and independent of the runner code, otherwise it would look like a hardcoded value

# Conflicts:
#	go.mod
#	go.sum
#	ssvsigner/go.mod
#	ssvsigner/go.sum
@nkryuchkov nkryuchkov requested a review from y0sher February 17, 2026 07:17
Copy link
Contributor

@iurii-ssv iurii-ssv left a comment

Choose a reason for hiding this comment

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

LGTM, with maybe a minor adjustment

@nkryuchkov nkryuchkov requested a review from iurii-ssv February 17, 2026 15:12
Copy link
Contributor

@iurii-ssv iurii-ssv left a comment

Choose a reason for hiding this comment

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

Looks good, but maybe we could simplify the current/next domain handling a bit

Comment on lines +247 to +251
// During transition, accept either configured fork domain for compatibility.
return nodeDomainType == dvs.netCfg.DomainType ||
nodeNextDomainType == dvs.netCfg.DomainType ||
nodeDomainType == dvs.netCfg.NextDomainType ||
nodeNextDomainType == dvs.netCfg.NextDomainType
Copy link
Contributor

@iurii-ssv iurii-ssv Feb 18, 2026

Choose a reason for hiding this comment

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

I wonder if we could simplify the current/next domain handling to something like this ?

  • publisher will only publish the current domain
  • the receiver would check that ^ against its current/next domain by doing something like:
func (dvs *DiscV5Service) isDomainCompatible(nodeDomainType spectypes.DomainType) bool {
	if nodeDomainType == dvs.netCfg.CurrentDomainType() {
		return true
	}

	if dvs.netCfg.InBooleTransitionWindow(dvs.netCfg.EstimatedCurrentSlot()) {
		return nodeDomainType == dvs.netCfg.DomainType || nodeDomainType == dvs.netCfg.NextDomainType
	}

	return false
}

Copy link
Contributor Author

@nkryuchkov nkryuchkov Feb 18, 2026

Choose a reason for hiding this comment

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

@iurii-ssv probably, it might be good to check nodeNextDomainType == dvs.netCfg.DomainType || nodeDomainType == dvs.netCfg.NextDomainType too to avoid any clock skew. I think it's still possible to be in the fork and get a handshake from a node that was sent before the fork

Copy link
Contributor

@iurii-ssv iurii-ssv Feb 18, 2026

Choose a reason for hiding this comment

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

I'm thinking: the InBooleTransitionWindow is designed to take care of the clock-skews,

I think it's still possible to be in the fork and get a handshake from a node that was sent before the fork

so once our node is past Boole-fork we'll have 1 slot of time accepting peers who broadcast the older domainType ... after that 1 slot passes those peers must switch to broadcasting the nextDomainType. It is possible that we'll ignore some peers during the transition because of p2p delays, but it doesn't seem like it should cause any real issues (while the simpler code is always preferable).

But maybe it's not worth changing it if you already have tested the current solution in this PR to work well.

Copy link
Contributor

@iurii-ssv iurii-ssv Feb 18, 2026

Choose a reason for hiding this comment

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

Thinking more about it, maybe InBooleTransitionWindow isn't even the "right" window to use here,

what we really need is to wait a sufficient amount of time (however long it takes for all SSV nodes to start publishing/advertising themselves with the nextDomainType value) after Boole-fork epoch starts ... I don't think 1 slot is enough

^ we'd need that ^ if we were to simplify as I suggested above, your current solution in this PR probably works already regardless

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.

3 participants

Comments