feat(aztec-node): force sentinel for validators + offense collection#24202
Merged
PhilWindle merged 3 commits intoJun 23, 2026
Conversation
…m gating from prover A node running a validator now always creates the sentinel regardless of SENTINEL_ENABLED, since the sentinel is required to reach consensus on slashing offenses. Non-validators continue to respect SENTINEL_ENABLED (default false). Subsystem gating (sentinel, slashing watchers, slasher) is no longer tied to prover-only mode but to validator status. Non-validators can opt into running the watchers plus a read-only slasher via the new OFFENSE_COLLECTION_ENABLED flag to collect and serve offenses over the admin RPC. The spartan deploy enables it by default, mirroring SENTINEL_ENABLED. Fixes A-1242
…andler for non-validator offense collection Lifts the slotsWithInvalidProposals / slotsWithProposalEquivocation tracking out of ValidatorClient and into ProposalHandler, which now implements InvalidProposalSlotSource (hasInvalidProposals / hasProposalEquivocation). The handler marks these slots from its all-nodes block and checkpoint proposal handlers, so any node that re-executes proposals (the default) populates them, not only validators. The attested-invalid-proposal watcher is now wired to the proposal handler (validator-owned or standalone) instead of the validator client, so a non-validator offense collector (OFFENSE_COLLECTION_ENABLED) can detect attested-to-invalid-checkpoint-proposal offenses. ValidatorClient delegates its has/mark calls to the handler, preserving validator behavior.
Drop the now-redundant invalid-checkpoint slot mark in ValidatorClient: the all-nodes checkpoint handler already marks the slot before invoking the failure callback. The FifoSet add was idempotent so the double-mark was harmless, but the validator-side call is dead. Guard non-validator invalid-block marking with the escape-hatch check, matching the validator path that intentionally disables invalid-block slashing while the escape hatch is open. Mark proposal equivocation from the p2p duplicate-proposal callback in ProposalHandler.register. p2p detects duplicate proposals without routing them through the proposal handlers, so without this a non-validator offense collector could mark a slot invalid without the matching equivocation mark and false-positive slash attesters. Validators overwrite this callback with their own richer handler.
aminsammara
approved these changes
Jun 22, 2026
PhilWindle
approved these changes
Jun 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
The sentinel is required for the network to reach consensus on slashing offenses — it's a core duty of participating in consensus, not an optional add-on. Yet
SENTINEL_ENABLEDdefaulted tofalse, so a validator could run without one and silently degrade the network's ability to enforce its own rules.While fixing that, two adjacent issues surfaced:
enableProverNode && disableValidator). That coupling is wrong: those subsystems should depend on validator status, not on whether the prover is enabled.Approach
createSentinelnow self-gates: if the node runs a validator it always creates the sentinel (ignoringSENTINEL_ENABLED); otherwise it respectsSENTINEL_ENABLED(defaultfalse). It logs which case applies so operators understand why aSENTINEL_ENABLED=falseis being overridden.proverOnlyguard. The slashing-detection watchers and the slasher are now gated oncollectOffenses = !disableValidator || enableOffenseCollection.OFFENSE_COLLECTION_ENABLEDflag lets a non-validator run the watchers plus a read-only slasher client (it never writes to L1 — voting/execution flow through the sequencer publisher, which a non-validator lacks) to collect and serve offenses over the existinggetSlashOffensesadmin RPC. The spartan deploy enables it by default, mirroringSENTINEL_ENABLED.ValidatorClientintoProposalHandler, which now implementsInvalidProposalSlotSource. The handler populates this from its all-nodes proposal handlers, so any node that re-executes proposals (the default) can feed the watcher.API changes
enableOffenseCollection(envOFFENSE_COLLECTION_ENABLED, defaultfalse). Named distinctly from the existing L1-deployAZTEC_SLASHER_ENABLEDto avoid confusion.SENTINEL_ENABLED.Changes
createSentinelforces the sentinel for validators and logs the reason;server.tsremovesproverOnly, gates watchers + a split-out read-only slasher oncollectOffenses, and wires the attested-invalid-proposal watcher to the proposal handler.enableOffenseCollection/OFFENSE_COLLECTION_ENABLEDflag and env-var entry.ProposalHandlernow owns the invalid-proposal / equivocation slot tracking and implementsInvalidProposalSlotSource;ValidatorClientdelegates to it, preserving validator behavior.OFFENSE_COLLECTION_ENABLEDwired through the chart value, pod template, network defaults, terraform variable, and deploy script, defaulting on (mirrorsSENTINEL_ENABLED).Fixes A-1242