Skip to content

feat: network-wide consensus config with validation and override protection (A-1168)#23977

Open
spalladino wants to merge 7 commits into
merge-train/spartan-v5from
spl/a-1168-identify-all-new-config-values-needed-at-network-level
Open

feat: network-wide consensus config with validation and override protection (A-1168)#23977
spalladino wants to merge 7 commits into
merge-train/spartan-v5from
spl/a-1168-identify-all-new-config-values-needed-at-network-level

Conversation

@spalladino

@spalladino spalladino commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Identifies and enforces the configuration values that must be identical across all nodes of a network (A-1168), sourcing per-network values from the generated network config. Prevents operators from overriding them unless a new ALLOW_OVERRIDING_NETWORK_CONFIG flag is set.

Also:

  • Adds a validation step in CI for the generated network configs.
  • Fixes a parse error for per-block allocation multipliers.
  • Enshrines max blocks per checkpoint as a consensus-wide config entry, checking it is sound wrt block times.

Network-wide consensus values

stdlib/src/config/network-consensus-config.ts defines NETWORK_CONSENSUS_ENV_VARS, the env vars required to be the same for every node of a network, in three categories:

  • Timing/protocol consensus: ETHEREUM_SLOT_DURATION, AZTEC_SLOT_DURATION, AZTEC_EPOCH_DURATION, SEQ_BLOCK_DURATION_MS, MAX_BLOCKS_PER_CHECKPOINT, CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS.
  • Network identity / L1-posted deployment params: chain id, committee size, lags, staking thresholds, mana target, proving cost, governance/slashing contract params, slash amounts.
  • Node-side slashing offense params (SLASH_*): validators must agree on these to reach slashing quorum.

Per-network values live in spartan/environments/network-defaults.yml (the source of cli/src/config/generated/networks.ts). This PR adds the two missing ones — MAX_BLOCKS_PER_CHECKPOINT: 10 and CHECKPOINT_PROPOSAL_SYNC_GRACE_SECONDS: 12 — to the shared prodlike section, and makes devnet's AZTEC_SLASHING_QUORUM: 17 / AZTEC_GOVERNANCE_PROPOSER_QUORUM: 151 explicit (values match the Solidity vm.envOr defaults, so deployment behavior is unchanged). maxBlocksPerCheckpoint is an explicit network value rather than derived per node, so nodes with different operational budgets cannot diverge on checkpoint geometry; mainnet/testnet/devnet geometry (72s slots, 12s L1 slots, 6s blocks) derives exactly 10.

NetworkConsensusConfig is composed by Picking fields from L1ContractsConfig and SequencerConfig, and getConsensusConfigFromNetworkEnv derives env names and parsing from the canonical config mappings, so each field is parsed exactly as the node's config layer would parse it.

Enforcement layers

  • Compile time: chain_l2_config.ts asserts (via satisfies) that every generated network config defines every consensus-critical var; a @ts-expect-error compile gate in the test file proves the assertion actually rejects configs missing a var.
  • CI: cli/src/config/chain_l2_config.test.ts validates each generated network config with validateNetworkConsensusConfig, which requires MAX_BLOCKS_PER_CHECKPOINT to be exactly what a ProposerTimetable at the production default budgets derives, plus basic geometry soundness (slot multiples, sub-slot fits in slot, etc.).
  • Startup (cli path): enrichEnvironmentWithChainName calls the pure checkConsensusEnvOverrides before enriching: a consensus var already set in the env to a value diverging from the network config makes startup throw, unless ALLOW_OVERRIDING_NETWORK_CONFIG=1 is set (then it warns and keeps the operator value). The check returns canonical rewrites for numerically-equal-but-noncanonical values (e.g. 6e3, which parseInt-based config parsing would read as 6), which the cli enrichment layer applies to the env.
  • Startup (node): AztecNodeService verifies the rollup contract reports the same aztecSlotDuration/aztecEpochDuration the node is configured with, and throws on mismatch. These are the only L1-timing fields the node config carries that the rollup exposes; the other rollup params (committee size, lags, proof submission epochs, mana limit) are read from L1 directly rather than from config.

Where maxBlocksPerCheckpoint applies

  • Proposer: the sequencer's ProposerTimetable computes the locally achievable count from operational budgets and clamps it down to the network value when the network value is lower; sub-slot selection never starts a block past the effective count. When local budgets compute more than the network allows, the timetable warns through an injected logger.
  • Gossip validation: proposal_validator.ts rejects (and penalizes peers for) block proposals with indexWithinCheckpoint >= min(maxBlocksPerCheckpoint, MAX_ATTESTABLE_BLOCKS_PER_CHECKPOINT).
  • Attestation: proposal_handler.ts refuses to attest to checkpoint proposals with more blocks than the configured value; checkpoint_builder.ts caps the blocks it assembles.
  • Gossipsub scoring: peer-rate thresholds are sized from the network config value directly; the gossip layer now uses a plain ConsensusTimetable and no longer depends on proposer operational budgets (which were also dropped from P2PConfig).

Also in this PR

  • MIN_PER_BLOCK_ALLOCATION_MULTIPLIER = 1.2 / MIN_PER_BLOCK_DA_ALLOCATION_MULTIPLIER = 1.5 live in @aztec/constants; the sequencer rejects multipliers below the minimum, and SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER switched from numberConfigHelper (parseInt truncated 1.5 to 1) to floatConfigHelper (mirrors fix(gas)!: client fallback limits track network per-block budget (A-1154) #23947; deliberate copy, conflicts to be resolved when either lands).
  • Removed the redundant checkpointProposalSyncGraceSeconds defaulting in node createAndSync; every consumer (archiver factory, sequencer, p2p timetable) has its own fallback.

Spartan deployments

Existing spartan networks that intentionally diverge from the generated defaults keep deploying: devnet.env (36s slots, committee size 1) and testnet.env (slashing round size 2 epochs) now set ALLOW_OVERRIDING_NETWORK_CONFIG=true, plumbed through deploy_network.sh into both the deploy-rollup-contracts job env and every aztec-image helm release (new global.allowOverridingNetworkConfig rendered by the shared aztec-node pod template). AZTEC_SLOT_DURATION/AZTEC_EPOCH_DURATION are also passed through to node pods so devnet nodes carry the real deployed 36s value and pass the rollup cross-check instead of inheriting the generated 72s default. mainnet/staging/next-net set no conflicting consensus vars and are untouched, so enforcement stays loud by default.

Known limitations

  • MIN_PER_BLOCK_DA_ALLOCATION_MULTIPLIER documents the network minimum only; its operator knob and runtime enforcement land with fix(gas)!: client fallback limits track network per-block budget (A-1154) #23947.
  • The remote network_config.json enrichment runs before enrichEnvironmentWithChainName, so a consensus value pushed via the networks repo that diverges from the binary's generated defaults will also be refused at startup (the live JSON sets no consensus values today).
  • ethereumSlotDuration cannot be cross-checked against the rollup contract (no getter); it is enforced via env only on named networks.

@spalladino spalladino changed the title feat: network-wide consensus config with validation and override protection feat: network-wide consensus config with validation and override protection (A-1168) Jun 10, 2026
…cement

- Cross-check all preset consensus fields (not just slot duration) at node
  startup, covering nodes that bypass the cli env enrichment such as the
  standalone aztec-node binary and programmatic embedders.
- Report instead of crash when the achievability probe derives fewer than one
  block, and reject non-finite config values instead of silently passing.
- Validate preset multipliers against the network minimums rather than >= 1.
- Canonicalize numerically-equal operator env values so parseInt-based config
  parsers cannot diverge from the Number-based equality check (e.g. 6e3).
- Record NETWORK from the --network flag so the startup cross-check applies to
  cli users, and tolerate unknown NETWORK values in embedded contexts.
- Parse SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER as a float; parseInt truncated 1.5
  to 1, which the new minimum-multiplier guard would have turned into a fatal
  startup error.
- Skip the achievability warning for the intentionally-high default cap.
…ults

Replace the in-code per-network consensus presets with values sourced from the
generated network config (cli/src/config/generated/networks.ts, generated from
spartan/environments/network-defaults.yml). The stdlib module now exposes only
the required-env-var list, types, a config extractor, a self-consistency
validate function, and an override-check function.

Override enforcement moves to cli enrichEnvironmentWithChainName, gated by a
compile-time check that every generated network config carries every
consensus-critical var. The node startup check is reduced to verifying the
rollup contract reports the same slot and epoch durations the node is
configured with. ProposerTimetable now warns (and logs) only when local budgets
compute more blocks per checkpoint than the network value allows.
@spalladino spalladino force-pushed the spl/a-1168-identify-all-new-config-values-needed-at-network-level branch from 100fb3e to 8e6bb08 Compare June 10, 2026 19:04
- Move MIN_PER_BLOCK_*_ALLOCATION_MULTIPLIER constants to @aztec/constants.
- Compose NetworkConsensusConfig by picking fields from L1ContractsConfig
  and SequencerConfig, and derive getConsensusConfigFromNetworkEnv env names
  and parsing from the canonical config mappings.
- Make checkConsensusEnvOverrides pure: it returns the canonical env writes
  instead of mutating env; the cli enrichment layer applies them.
- Add a compile-time ts-expect-error gate proving ConsensusComplete rejects
  configs missing a consensus-critical var.
- Drop the redundant checkpointProposalSyncGraceSeconds defaulting in the
  node createAndSync (every consumer has its own fallback).
- Switch the p2p gossip layer from ProposerTimetable to ConsensusTimetable
  and feed gossipsub scoring the network maxBlocksPerCheckpoint directly,
  dropping the now-unused proposer-budget config fields from p2p.
@spalladino spalladino added the S-do-not-merge Status: Do not merge this PR label Jun 10, 2026
…ng from generated defaults

The network-consensus-config enforcement throws at startup when a node, the
deploy-rollup-contracts job, or any pod running the aztec entrypoint with a
known NETWORK sets a consensus-critical env var that differs from the generated
network defaults. devnet (36s slots, committee size 1) and testnet (slashing
round size 2 epochs) intentionally diverge, so they now set
ALLOW_OVERRIDING_NETWORK_CONFIG=true.

Plumb that flag from the env files through deploy_network.sh into both the
deploy-rollup-contracts job env and the deploy-aztec-infra helm releases (via a
new global rendered by the shared aztec-node pod template, reaching validators,
rpc/full nodes, prover, fisherman, bootnode and bots). Also pass
AZTEC_SLOT_DURATION/AZTEC_EPOCH_DURATION into node pods so devnet nodes carry the
real deployed 36s slot value and pass the rollup cross-check instead of inheriting
the generated 72s default.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-do-not-merge Status: Do not merge this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant