This is an unstable pre-release for Sepolia's Glamsterdam (Gloas / ePBS) hard fork. It adds node-side ePBS support per SIP-94 (EIP-7732): Gloas attestations and aggregation, Payload Timeliness Committee (PTC) duties, Gloas block proposals with the self-build execution-payload envelope, proposer preferences, and an opt-in direct-builder overlay. It also cuts the proposer's QBFT round budget to 1.5s (SIP-102) so round changes still fit Glamsterdam's earlier attestation deadline. On top of that come fixes to consensus, duty execution, P2P, the execution layer, remote signing, and node startup/shutdown, plus exporter refactors and dependency updates. The release also carries code for the Boole SSV fork, which is dormant: it isn't scheduled on any network.
๐ Upgrade Priority
| Network | Priority |
|---|---|
| Sepolia | ๐ฅ Required (before the Glamsterdam fork) |
| Hoodi | ๐งช Optional (testing) |
| Mainnet | โ Do not use |
โ ๏ธ This is an unstable pre-release. Do not run it on mainnet.
โ ๏ธ Sepolia: upgrade your Execution + Consensus clients to Glamsterdam-ready releases before you restart the SSV node on this version. The node reads
GLOAS_FORK_EPOCHfrom the beacon node at startup. After the restart, check the logs forGloas (ePBS) fork scheduledwith the expectedepoch. See Operator notes below.
โ ๏ธ Always ensure your Execution + Consensus clients and any remote signers (web3signer, external signers) are updated, SSV strives to support latest released versions of these clients.
๐ณ Docker image
docker pull ssvlabs/ssv-node:v2.5.0-unstable.2โ ๏ธ Operator notes
- Upgrade the beacon node(s) first, then restart SSV. The node reads its fork schedule once at startup, from the first beacon node that connects, and can't change it while running. It does keep re-checking its beacon nodes. If one of them schedules a fork the node started without, the node logs an error telling you to upgrade every beacon node and then restart. The same happens if a fork is moved or cancelled after the node started.
- Why the node may stop on its own: if the fork is 2 epochs away or less, the node shuts itself down with that error. This is a deliberate failsafe. A node that crossed the fork on its old schedule would fail every duty from then on, and nothing in its logs would point at the fork. Stopping makes the problem visible right away, and a restart picks up the new schedule. The 2-epoch margin gives the restarted node the new schedule before the Gloas pre-fork window opens (proposer preferences are sent one epoch ahead).
- The node stops again on every restart while the beacon node it reads from still lacks the fork. If you run several beacon nodes, upgrade all of them before you restart SSV.
- Remote signing (ssv-signer + Web3Signer) doesn't cover the new Gloas signing types yet. Web3Signer has no request types for Gloas blocks, Gloas aggregate-and-proofs, PTC payload attestations, proposer preferences, execution-payload envelopes or builder request auth. On Gloas slots, an operator that signs remotely fails those duties. The cluster still completes them while no more than f of its operators sign remotely. Remote attestation and sync-committee signing now carries the Gloas fork in
fork_infoand is expected to keep working, but it hasn't been verified against a live Web3Signer on a Gloas network yet. - Validator registrations end at the Gloas fork. From the fork on, ePBS proposer preferences replace them: the scheduler stops producing them and message validation rejects them. In-protocol (enshrined) PBS also replaces the MEV-Boost / relay flow. SSV runs the new duties automatically, with no configuration needed.
- Shorter proposer QBFT round (SIP-102), active on every network. The proposer's per-round budget drops from 2s to 1.5s, so a round change still starts round 2 before Glamsterdam's earlier attestation deadline. This change is not fork-gated.
LegacyProposerRoundTimeout: true(env:LEGACY_PROPOSER_ROUND_TIMEOUT) restores 2s as an emergency rollback. It's a committee-wide parameter, not a local tuning knob: set it the same way on every operator of every shared committee. A rollback takes effect in a committee only once at most f of its operators still run the 1.5s budget, so coordinate the switch across the whole committee. - Explicit zero values in config are now honored. Before this release, a YAML/env value equal to the Go zero value (
false,0,"") was silently replaced by the default. Now it sticks:p2p.PubSubScoring: falseandp2p.DynamicMaxPeers: falsetake effect,db.GCInterval: 0disables GC, andp2p.MaxPeers: 0stays0. If your config sets any field to a zero value expecting the default, remove that line. - Exporter nodes run a DB migration (
migration_9) on first start. It rewrites stored committee duty traces to a role-aware key layout, which can take a while on a large archive DB. Back up the exporter DB before upgrading.
New features
ePBS (EIP-7732 / Gloas), SIP-94
Adds node-side support for every ePBS duty. It is gated only on the beacon node's GLOAS_FORK_EPOCH, so no network config change is needed.
- Fork retiming: at the fork, the slot interval shrinks from 1/3 to 1/4 of the slot. That interval sets duty deadlines, QBFT round-1 head starts, aggregation waits and attestation-fetch budgets.
- Attestations and aggregation: committees agree on a
GloasBeaconVotethat carries the beacon node's payload-status index, and aggregation uses the GloasAggregateAndProofcontainer end to end. - PTC (payload attestation): a new partial-signature-only runner fires at the payload-attestation cutoff. It abstains when no block was seen.
- Block proposal: blocks are produced via
produceBlockV4(a POST with aBuilderConfig, falling back to GET on older beacon nodes). QBFT agrees on the block plus the self-buildpayload_root. Every operator submits the decided block, and an "already known" answer from the beacon node counts as success. Proposals are slashing-protected. - Execution-payload envelope (self-build): there's no separate QBFT instance. Each operator signs the envelope root in the same post-consensus packet as the block, and only the operator whose beacon node built the block publishes the full envelope, by 50% of the slot.
- Proposer preferences: the node runs one duty per upcoming proposal slot across the lookahead (fee recipient and gas limit), and re-emits a preference only when the
dependent_rootchanges. These replace validator registrations from the fork on.
Tested on a hermetic Gloas devnet: attestations, PTC duties and block proposals were confirmed on-chain, the beacon node accepted the proposer preferences, and the envelope was published and landed with a Lodestar beacon node.
Direct-builder overlay (opt-in)
A new Builders config block (YAML only) adds authenticated direct-builder connections on top of enshrined PBS. The enshrined flow (gossiped bids plus local self-build) remains the fallback whenever the overlay fails or a builder is unavailable. The block must be identical on every operator of every committee that shares a validator. The builder request auth is threshold-signed, so if any operator's config differs, that builder is silently disabled. Up to 8 entries are allowed. See docs/EXTERNAL_BUILDERS.md.
ProposerDelayEPBS
ProposerDelayEPBS (env: PROPOSER_DELAY_EPBS) is the post-Gloas counterpart of ProposerDelay and applies from the fork on (ProposerDelay still applies before it). It's hard-capped at 1s, with no dangerous override. Default is 0 (off).
Libp2pTrace
A new p2p.Libp2pTrace option (env: LIBP2P_TRACE) routes go-libp2p logs through the SSV logger, in the same format and to the same file, at error,swarm2=debug,basichost=debug. When enabled, it overrides any GOLOG_LOG_LEVEL setting. When disabled (the default), libp2p logging works as before, including GOLOG_LOG_LEVEL.
What's Changed
ePBS (Gloas)
Adds the ePBS features above, plus fixes that aren't Gloas-specific:
- A bad partial signature in a quorum no longer fails the duty in any runner: the node drops it and the next honest share completes the duty.
- The sync-committee-contribution runner no longer drops the other subnets because of one bad root.
- Duty fetching retries when no validators are eligible yet.
- Beacon-node addresses given without a scheme are normalized.
Follow-up: Gloas block and envelope publishes now send Accept: application/json. Prysm beacon nodes had rejected them with 406, which would have lost the envelope for any cluster whose block was built on a Prysm node.
QBFT: per-role give-up round + round-change clarity
A QBFT instance now gives up at its role's round cap (round 3 for proposers) instead of the cluster-wide cutoff of 12. This stops about 6 minutes of round changes that no peer accepts. Round-change handling is also clarified, and the intentional round-change drop at the cutoff boundary is documented. The SIP-102 proposer round budget (see Operator notes) ships as part of #2901.
PRs: #3041, #2835, #2873, #3044 (SIP-102, merged into the ePBS branch and shipped with #2901)
Duty execution & scheduling
- Sync-committee duty fetching is reworked to match the attester/proposer rework in v2.4.3. It retries per period, so one transient beacon error no longer drops a whole period's duties, and it handles reorgs and index changes.
- Sync-committee contributions now use the
headblock root, so the duty no longer fails cluster-wide when the slot's block is missed. - Aggregators request the aggregate for the attestation data root the cluster actually attested with. This fixes sporadic 404
No aggregated attestationerrors. - Contribution ordering: contributions are sorted canonically by subnet, so the proposed value no longer depends on which operator leads.
- Validator registrations: the wire slot is decoupled from the local execution gate, as v2.4.3 did for voluntary exits. This narrows the window where a fast operator broadcasts before its peers have started the duty.
- Stale queue messages: when an idle runner starts a duty, a validator's queue drops messages left over for earlier slots. These drops are counted under a new
stalereason on the queue drop metric. - Empty committee duties: a committee duty whose validators all dropped out mid-duty (removed or liquidated) is now reported
not_requiredinstead of failed or stuck. - Cleanup: runner duty-state errors are reachable again, and their unreachable retry branches are removed.
PRs: #2769, #2885, #2888, #2859, #2858, #3039, #2988, #3029
Beacon client
Weighted attestation-data fetches now combine per-client errors the same way the proposal path does, with fixed log levels. Per-client failures, such as a beacon node refusing to attest while optimistically synced, log at DEBUG, and ERROR is reserved for a failed duty. The multi-client init comments are also clarified.
Message validation
When local validation drops the node's own outbound messages, the log level now depends on the outcome. Routine self-ignores (dedup, timing races, a round above the role's cap) log at DEBUG. Anything unexpected logs at WARN with the specific reason. could not publish p2p message โฆ validation ignored no longer logs as ERROR.
P2P & discovery
- Undecodable discv5 packets can no longer wedge discovery: they're drained through a buffer, and dropped packets are counted by
ssv.p2p.discovery.unhandled_packets.dropped. - Adds the new
Libp2pTraceoption. - Fixes flaky tests.
PRs: #2980, #2882, #2906, #3028, #3030
Execution layer / contract sync
- Logs from the same transaction are now packed in
logIndexorder, so nonce-ordered bulk registrations can't be rejected as malformed. - Fixes a
close of nil channelpanic on startup failure with multiple EL endpoints. - Benign bloom false-positive and query-subdivision logs are demoted to DEBUG. The bloom-recovery WARN stays.
- A share the remote signer can't decrypt is now classified as a malformed event and skipped, as local signing already did.
- Test cleanup and deflakes.
PRs: #2993, #3004, #2904, #2997, #3005, #2969, #2976
Remote signing (ssv-signer)
- Fixed-fork domains: voluntary-exit and validator-registration sign requests pin their fixed-fork
fork_info(Capella and the genesis builder fork, respectively). Exits now sign even when Web3Signer's--networkis misconfigured. - Clearer errors: ssv-signer now returns the upstream failure reason and passes through Web3Signer's real HTTP status. Previously every upstream failure came back as 500. The node includes the reason in its errors.
- Startup retry: the missing-keys check at startup retries for up to 2 minutes, so a Web3Signer that's still starting no longer crash-loops the node.
PRs: #2875, #3010, #3011, #3012
Node startup, shutdown & config
- Node startup is refactored into a testable build โ run flow.
- Fixes the P2P network never starting when
p2p.DynamicMaxPeersisfalse. - Failures during startup and in background services now go through one error path with a full teardown.
- The node shuts down gracefully on SIGINT/SIGTERM. The first signal triggers a clean shutdown with exit code 0, and a second one forces an exit.
- Config defaults moved from
env-defaulttags into code, so explicit zero values are honored (see Operator notes).
Observability
The node logs a WARN when a duty hasn't completed by the end of its slot, which surfaces silent failures such as a voluntary exit that never reaches quorum. Broadcasts log the gossipsub message ID and topic peer count at DEBUG.
PRs: #2879
Exporter
- Fixes a
pebble: closedpanic on archive-mode shutdown. - Committee duty traces are now keyed by committee and runner role (hence the
migration_9note above), and the API adds arolefield and arolesfilter. - Exporter packages are consolidated under
exporter/, and the websocket query bridge and validator message tracing are decoupled fromoperator.
PRs: #2884, #2908, #2928, #2936
Boole SSV fork (dormant)
Code for the Boole SSV fork. It isn't scheduled on any network, so none of it activates in this release.
PRs: #2941 (units: #2924, #2925, #2927, #2929, #2930, #2931, #2932, #2933, #2937, #2938, #2939, #2940, #2944, #2946, #2948, #2949, #2951, #2957, #2958, #2959, #2960, #2961, #2977), #2971, #2972, #2973, #2974, #2975, #2981, #2985, #2989, #3006
Build / CI / dependencies
- ssv-spec is pinned to an untagged v1.2.3 build that carries the Gloas constants. It will be re-pinned to a tagged release.
- Dependency updates: the SSV fork of go-eth2-client (now with Gloas types), eth2-key-manager, go-ethereum v1.17.5, dynamic-ssz v1.3.3, bls-eth-go-binary v1.37.0 and OpenTelemetry v1.41.0. go-bitfield moved to its
OffchainLabsmodule path. - Adds a pre-push lint hook (misspell + scoped golangci-lint).
- p2p and exporter API tests allocate ports more reliably.
[]byte(fmt.Sprintf)is replaced withfmt.Appendf.