feat: merge-train/spartan-v5 - #23975
Merged
Merged
Conversation
…ted block (#23967) ## Motivation On a staging HA validator, an archiver orphan prune triggered a storm of thousands of duplicate `chain-checkpointed` events out of p2p's `L2BlockStream`. The local tips store keeps a block number per cursor and derives the checkpoint number from a `block -> checkpoint` map that is only populated for the last block of each confirmed checkpoint. `handleChainPruned` moved the `checkpointed` and `proposedCheckpoint` cursors to the prune target unconditionally. That target is the new tip of the *proposed* chain and can be an uncheckpointed block with no mapping (in the incident, a block belonging to a not-yet-confirmed checkpoint, sitting ahead of the checkpointed tip). `getCheckpointId` then resolved that cursor to checkpoint zero, the stream computed `nextCheckpointToEmit = 0 + 1 = 1`, and it replayed every checkpoint from 1 up to the source tip. ## Approach A prune is a rollback, so checkpoint-bearing cursors may only move *backward*. `handleChainPruned` now sets `proposed` unconditionally and clamps `checkpointed`/`proposedCheckpoint`/`proven` to the prune target only when they are ahead of it (generalizing the guard `proven` already had). In the incident the checkpointed cursor is left untouched and keeps resolving to its real checkpoint, so there is nothing to replay. Surfacing a missing mapping *loudly* (rather than silently reporting checkpoint zero) is intentionally deferred to a stacked follow-up: doing it safely requires per-tip checkpoint ids so the store can fail loudly on genuine corruption without bricking legitimate skipped-history prunes (which would otherwise throw on the next `getL2Tips`). This PR is the minimal, behavior-preserving fix for the storm. ## Changes - **stdlib**: `handleChainPruned` clamps checkpoint-bearing cursors backward only instead of forcing them onto the (possibly uncheckpointed) prune target. - **stdlib (tests)**: store-level regression that a prune to an uncheckpointed block ahead of the checkpointed tip leaves the cursor intact and resolving to its real checkpoint; stream-level regression asserting no `chain-checkpointed` replay after such a prune. Fixes A-1167
…ration (#23821) ## Motivation The production sequencer kept two legacy escape hatches: `enforceTimeTable=false` (unbounded block building with no deadlines) and `blockDurationMs=undefined` (single-block-per-slot mode). Both existed only to satisfy tests and the sandbox, complicated the timetable with dead branches, and let most e2e tests run under timing that production never uses. ## Approach The timetable now always enforces sub-slot deadlines with a concrete `blockDurationMs` (required config, default 3000 ms). The only non-enforced path left is the `AutomineSequencer`: the local sandbox switches to it, which makes `AnvilTestWatcher` deletable — it was already inert across the e2e suite since every e2e path runs anvil in interval mining. The e2e PIPELINING preset flips to enforced real timing at exactly 2 blocks per slot. ## Fee prediction changes `sequencer-client/src/global_variable_builder/fee_provider.ts` now treats the current L1 fee snapshot as part of the predicted-fee set exposed by the node. `getPredictedMinFees()` returns the current minimum fees first, followed by the future-slot predictions from the fee predictor. This matters for local automine because a freshly mined checkpoint can make the node current minimum fees higher than the predictor's future samples; including the current value prevents clients from quoting below what tx validation will accept. `getCurrentMinFees()` also bypasses viem's cached block number by calling `getBlockNumber({ cacheTime: 0 })`, so automine fee snapshots observe newly mined L1 blocks immediately instead of reusing a stale L1 block number. ## Public simulation global variables `aztec-node/src/aztec-node/server.ts` no longer calls `buildGlobalVariables()` for `simulatePublicCalls`. Instead it computes a simulation target slot from local chain state and calls `buildCheckpointGlobalVariables()` with that slot, then combines those checkpoint globals with the requested simulation block number. The target slot is the max of: - the slot corresponding to the next L1 timestamp from the epoch cache, - the slot after the proposed checkpoint loaded from the block source, - the latest proposed block slot when it is ahead of the proposed checkpoint. This keeps public simulation aligned with the same checkpoint-global construction used for block building, while avoiding a rollup-contract lookup on the simulation path. ## Automine sequencer: proving and recovery The `AutomineSequencer` now drives epoch proving for the sandbox without a prover. `aztecNode.prove(upToCheckpoint?)` synthetically settles each checkpointed epoch — computing its out-hash, writing the outbox root and proven checkpoint to L1 via cheat codes, then calling `markAsProven` — with partial-epoch support (it can settle a prefix up to a requested checkpoint). Because that settlement mines no L1 block, it then mines one empty block so the archiver (which short-circuits its L1 sync while the block hash is unchanged) observes the new proven tip immediately, mirroring a real epoch proof landing an L1 verify tx. An optional auto-settle loop (`AUTOMINE_ENABLE_PROVE_EPOCH`, on by default for the local network) proves epochs as they close, replacing the standalone `EpochTestSettler` that used to race the build loop. On a wrong-slot or failed publish the sequencer returns the failed block's txs to the pool and retries the build rather than reorging L1, using a new `archiver.discardProposedCheckpointsAfter` to drop proposed-but-uncheckpointed blocks during recovery. ## Changes - **stdlib**: `blockDuration` required in the checkpoint timing model, single-block branches removed; `DEFAULT_BLOCK_DURATION_MS = 3000` as single source of truth. - **sequencer-client**: `SequencerTimetable` loses the `enforce` field; `canStartNextBlock` always returns a concrete deadline; config drops `enforceTimeTable`. - **automine sequencer**: `prove(upToCheckpoint?)` synthetically settles epochs (partial-epoch capable) and an optional auto-settle loop (`AUTOMINE_ENABLE_PROVE_EPOCH`) advances the proven tip, mining an empty L1 block so the archiver observes it; failed/wrong-slot publishes return txs to the pool and retry instead of reorging L1 (new `archiver.discardProposedCheckpointsAfter`). - **fees**: node fee predictions now include the current minimum fees as the first entry before future-slot predictions, and current fee snapshots bypass cached L1 block numbers so local automine fee quotes see freshly mined checkpoints. - **p2p**: `blockDurationMs` required in proposal/attestation validators, the pipelining window, and gossipsub topic scoring. - **foundation / aztec-node / validator-client**: `SEQ_ENFORCE_TIME_TABLE` env var removed; dead `blockDurationMs === undefined` branches simplified. - **aztec (sandbox)**: local network runs the `AutomineSequencer` by default, including p2p-enabled local runs; local-network is not a mode for connecting to an existing Aztec network. `AnvilTestWatcher` deleted, and the standalone `EpochTestSettler` is replaced by the AutomineSequencer auto-settle loop. - **end-to-end (tests)**: PIPELINING preset sets `blockDurationMs: 3000` (2 blocks/slot); ~30 `enforceTimeTable` call sites removed; watcher manual-proving call sites replaced with `cheatCodes.rollup.markAsProven()`; bench given explicit slot headroom; block-building regression test fixed for a min-txs remainder livelock that enforced deadlines exposed. - **docs**: sequencer-client and gossipsub READMEs updated to the always-enforced model; sandbox/local-network docs updated to describe automine block production and the removal of `SEQ_ENFORCE_TIME_TABLE` for v5. Breaking: `SEQ_ENFORCE_TIME_TABLE` is removed and `SEQ_BLOCK_DURATION_MS` now defaults to 3000 ms (previously unset, meaning single block per slot). The `SEQ_ENFORCE_TIME_TABLE` wiring in `spartan/` (deploy script, terraform, env files) is removed as well. Fixes A-1148
PhilWindle
approved these changes
Jun 9, 2026
PhilWindle
enabled auto-merge
June 9, 2026 20:50
…g test (#23976) ## Problem CI on `merge-train/spartan-v5` (commit 609014a, [log](http://ci.aztec-labs.com/1781038207169152)) failed in the `yarn-project` build at the `yarn tsgo -b --emitDeclarationOnly` step: ``` end-to-end/src/e2e_epochs/epochs_optimistic_proving.parallel.test.ts(222,9): error TS2353: Object literal may only specify known properties, and 'enforceTimeTable' does not exist in type 'EpochsTestOpts'. ``` (also at lines 366, 473, 558, 646, 780) ## Root cause PR #23821 (*always enforce timetable with concrete block duration*) made timetable enforcement unconditional and removed the `enforceTimeTable` option from `EpochsTestOpts`/`SetupOptions`, deleting ~30 `enforceTimeTable: true` call sites. `epochs_optimistic_proving.parallel.test.ts` landed on the v5 line separately and still passed `enforceTimeTable: true` at six sites, so it no longer type-checks. ## Fix - Remove the six now-invalid `enforceTimeTable: true` properties. Each call site already sets a concrete `blockDurationMs: 8000`, so the change is behavior-preserving — the same deletion the PR applied to every other e2e test. Verified in CI: `yarn-project` now type-checks and `epochs_optimistic_proving.parallel.test.ts` passes. - Temporarily `it.skip` the HA test `should distribute work across multiple HA nodes` in `composed/ha/e2e_ha_full.test.ts`, which fails under the always-enforced timetable (sequencer misses slots: `BlockOrCheckpointSlotExpiredError` / `no_blocks_built` / `Fork not found`). Skipped at Santiago's request, to be re-enabled after the HA block-building interaction with #23821 is fixed.
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Jun 10, 2026
PhilWindle
enabled auto-merge
June 10, 2026 07:23
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Jun 10, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to failed status checks
Jun 10, 2026
Fixes A-1157. Addresses security advisory GHSA-h4vv-85x5-6hmh.
## Problem
Peer scores decay toward zero (~0.9/minute). A peer whose score crossed
the ban threshold (`MIN_SCORE_BEFORE_BAN = -100`) recovered to a healthy
score within approximately 1 hour.
## Fix
Record a ban when a peer's score drops below the ban threshold and hold
it for a configurable duration (default 24h). Bans are kept **in memory
only** and are cleared on restart — a restarted node re-learns bad peers
from their behaviour rather than carrying stale bans across runs.
- **`PeerScoring`** records `{ score, expiry }` in an in-memory
`bannedPeers` map, so `getScore`/`getScoreState` stay **synchronous**
(required by the peer-manager hot paths, including a `.sort()`
comparator).
- While banned, `getScore` returns the **ban score** regardless of
decay, so a peer cannot recover its way out of the ban early — even
after `decayAllScores` cleans up the decayed live-score entry. Once the
ban expires it is lifted and the live (decayed) score takes over,
letting the peer recover.
- Expired bans are lifted lazily on the next score query
(`getActiveBanScore`) and swept proactively each heartbeat via
`pruneExpiredBans()`, so a banned peer that disconnects and is never
queried again does not linger in the map.
## Configuration
New `P2P_PEER_BAN_DURATION_SECONDS` (config field
`peerBanDurationSeconds`), default `86400` (24h). Registered in
`foundation` env vars and the P2P config mappings.
## Tests
`peer_scoring.test.ts` covers the full lifecycle, asserting both score
**values** and states:
- ban floor held through banned → recovered-live-score → expiry
transitions;
- `peerBanDurationSeconds` drives the window (60s case);
- the advisory regression: after decay cleans up the live-score entry,
`getScore` still returns the `-150` ban score (not `0`), keeping the
peer Banned;
- a peer whose previous ban has expired can be re-banned;
- `pruneExpiredBans` removes expired bans but keeps active ones.
Existing `peer_manager` and `peer_scoring` suites pass; the previously
existing "returns to Healthy after improving score" assertion was
updated to reflect the new intended behaviour (a banned peer stays
banned for the full window).
## Summary - Rename JSON-RPC namespaces from `node_*` / `nodeAdmin_*` / `nodeDebug_*` to `aztec_*`, `aztecAdmin_*`, and `aztecDebug_*` on both client schemas and `aztec start` server registration. - Stop mounting the standalone `p2p_*` namespace; add `getPeers` and `getCheckpointAttestationsForSlot` to `AztecNode` and delegate from the node server. - Update node API reference generation, regenerated operator docs, e2e forward-compatibility config, and a migration note under TBD. Fixes [A-1010](https://linear.app/aztec-labs/issue/A-1010/archiver-flag-silently-ignored-when-combined-with-node-archiver-rpc)
…all clock (#23978) The prepare-for-slot loop in p2p client was **not** synced with the `L2BlockStream` events, meanining the `unprotect` call could trigger before the blocks-added flagged the txs as mined. One solution could've been to add a new event to the blockstream on `slot-synced`, but it's easier to just remove the polling, and unprotect slots when a block proposal that protected the txs fails. As a safeguard, we still call unprotect based on slot numbers on mined blocks. ## Problem The tx pool **protects** txs referenced by an in-flight block proposal: on gossip receipt, the proposal's txs are keyed to its slot and removed from the pending indices, so the local builder cannot re-select them and eviction cannot drop them while the proposal may still land. `prepareForSlot(S)` releases protections from slots before `S`, revalidates the txs, and returns them to pending. Release was driven by a wall-clock slot monitor polling the epoch cache every tick. Three problems: - **Race against mined-marking.** The monitor can fire after a proposal's checkpoint lands on L1 but before the block stream delivers `blocks-added`. The just-landed txs are unprotected into pending, where eviction or nullifier-conflict resolution can delete them; when the block then syncs there is nothing left to mark mined, and after a later reorg `handlePrunedBlocks` has nothing to restore — the tx is lost to the pool. - **Clock dependency.** The epoch cache is wall-clock derived and explicitly depends on system clock sync; unprotection correctness should depend on observed chain state instead. - **Pipelining blind spot.** Gossiped proposals carry future target slots during proposer pipelining, so wall-clock release frees them late. (The old target-slot branch that tried to address this read `proposedCheckpoint` from the local tips store, where it can never lead the checkpointed tip — removed in #23968 as dead code.) ## Change The protection lifecycle becomes fully event-driven and the slot monitor is deleted: - **Protect** on gossip receipt of a block proposal (unchanged). - **Release on local validation failure**: a proposal that fails validation immediately releases the protections it created — only entries still keyed to that proposal's slot, so a tx also referenced by a live proposal at another slot stays protected. - **Resolve via chain events** (unchanged): `blocks-added` marks txs mined, superseding protection; `chain-pruned` un-mines them back to pending. Proposals that landed as proposed-but-unconfirmed checkpoints and are later orphaned are fully handled by this existing lifecycle. - **Collect silent deaths via synced block slots**: `prepareForSlot` now runs inside the `blocks-added` handler with the slot of the last synced block, after mined-marking. Any block landing at slot S releases protections from all earlier slots — covering proposals that never reached L1 at all (no quorum, proposer crash, dropped L1 tx), for which no chain event can ever fire. Because it is ordered after mined-marking in the same handler, the unprotect-before-mined race is impossible by construction. - **Proposers are unaffected**: the sequencer already calls `prepareForSlot(targetSlot)` directly before building, which remains the one legitimate ahead-of-chain preparation. ## Trade-off accepted During a multi-slot stall with no blocks landing anywhere, non-proposer pools retain protections until the first block lands (the wall clock used to release them mid-stall). There is no user-visible cost — there is no chain to include txs in during a stall — and the memory held is bounded and self-healing on the first `blocks-added`. Proposers self-serve via the direct sequencer call. Protections are in-memory only, so a restart clears them. Fixes A-1173
## Motivation #23967 stopped the checkpoint-replay storm at its source (a prune must not advance checkpoint-bearing cursors onto an uncheckpointed block). This PR makes the local tips store never *silently* report checkpoint zero for a real block, removes the machinery and degenerate fields that made the silent path possible, and closes the gaps found in review: a store-upgrade path that would brick p2p nodes, a transient proven-tip overshoot on prune, and world-state fabricating checkpoint ids it never had. Fixes A-1174 ## Commits **1. `fix(p2p): resolve checkpoint tips from stored ids and fail loudly on corruption`** - `chain-proven`/`chain-finalized` carry their `CheckpointId`; the store records a checkpoint id per cursor. `getCheckpointId` resolves genesis → stored id → (back-compat) `block→checkpoint` mapping → **throw**, so a real-block cursor with no resolvable checkpoint fails loudly instead of degrading to a replay. - A `proven`/`finalized` cursor can legitimately lead the locally-checkpointed frontier (batch lag / `startingBlock`); carrying the id lets it resolve without a local mapping, so the throw only fires on genuine corruption (never on a legitimate skipped-history prune). **2. `refactor(p2p): drop the block→checkpoint mapping and checkpoint-object store`** - With per-cursor stored ids, the `block→checkpoint` mapping and the checkpoint-object store are dead weight (they existed only to feed `getCheckpointId`). Both backing maps are removed from the KV and memory stores. - `chain-pruned` now carries `checkpointed: L2TipId` (the source's confirmed checkpointed tip) instead of a bare `CheckpointId`. The prune handler clamps any checkpoint-bearing cursor that leads that tip down to it, always landing on a block with a recorded id — no genesis-clamp, no mapping lookup. `handleChainFinalized` collapses to pruning block hashes below the lowest live tip. **3. `refactor(stdlib): drop proposedCheckpoint from the local L2 tips provider`** - `proposedCheckpoint` is degenerate in the local stores (always equal to `checkpointed`) and no consumer reads it — the one reader, `p2p_client`'s `maybeCallPrepareForSlot`, was a dead branch (always false). `L2TipsProvider.getL2Tips` now returns `LocalL2Tips = Omit<L2Tips, 'proposedCheckpoint'>`; the local stores stop maintaining the cursor; the dead p2p branch is removed. - `L2BlockSource.getL2Tips` is a separate interface and keeps the full `L2Tips` with `proposedCheckpoint`, which the sequencer and node still read from the archiver. **4. `fix(p2p): bump p2p store schema version for the per-tip checkpoint id layout`** - An upgraded p2p store would keep its old tips with an empty per-cursor id map, making `getL2Tips` throw on every read with no way to self-heal — failing `P2PClient.start()` outright. Bumping the store schema version (3 → 4) resets the store on upgrade instead. **5. `fix(p2p): clamp the proven tip to the source proven tip on prune`** - `chain-pruned` carried only the checkpointed tip, so a prune that rolled back the proven chain clamped the local proven cursor onto the (higher) checkpointed tip, transiently reporting unproven blocks as proven until the corrective `chain-proven` event landed at the end of the same sync iteration. The event now also carries `proven: L2TipId` and each cursor clamps to its own source tip. **6. `refactor(world-state): stop fabricating checkpoint ids in the world-state tips provider`** - The stream's local-data-provider contract demanded full checkpoint-bearing tips, forcing world-state to hardcode genesis checkpoint ids and a `checkpointed` tip at block zero (violating `finalized ≤ checkpointed`) that nothing ever read. The provider contract is narrowed to `LocalChainTips` — the tips the stream actually consumes, with `checkpointed` required only when emitting checkpoint events — and the stream fails loudly if checkpoint emission is enabled without one. World-state now reports only the proposed/proven/finalized blocks it genuinely tracks; `L2TipsProvider` keeps the full `LocalL2Tips` shape for the p2p/pxe tips stores. **7. `fix(prover-node): consume the reshaped chain-pruned and checkpoint-bearing events`** - The CheckpointStore redesign landed a prover-node consumer of `chain-pruned` (written against the old event shape) on the merge train while this branch was in flight. The prune handler now reads `event.checkpointed.checkpoint` (same semantics as the old field) and the test event constructors are updated to the new shapes. **8. `refactor(world-state): report unresolvable tip hashes as undefined instead of fabricating them`** - World-state's `getL2Tips` fabricated values for hashes it could not resolve: an empty string for the proven/finalized tips and a non-null assertion for the proposed tip. The honest missing case is real (a proven tip ahead of the synced range has no archive leaf to resolve from), so `LocalChainTips` now carries block ids with an optional hash and world-state returns resolved hashes as-is. Local tips stores are unaffected (`LocalL2Tips` with required hashes remains assignable), and the stream reads only block numbers from local tips. ## Breaking / operational notes - `PXE_DATA_SCHEMA_VERSION` bumped: existing PXE DBs are wiped and resync on first open. - p2p store schema version bumped: existing p2p data dirs (including the tx pool) are wiped and resync on upgrade. - `L2BlockStreamEvent` shape changes (internal API): `chain-proven`/`chain-finalized` gain `checkpoint`; `chain-pruned` carries `checkpointed`/`proven` tips instead of a bare `checkpoint`. ## Deferred `maybeCallPrepareForSlot`'s target-slot preparation (prepare the target slot when a proposed checkpoint exists) never worked, because the local store cannot represent a proposed checkpoint ahead of the checkpointed tip. This is handled in #23978.
…g anvil (#23979) Fixes the flaky HA full suite (`e2e_ha_full`) seen in http://ci.aztec-labs.com/8e1e980c4886df0d, where "should distribute work across multiple HA nodes" timed out awaiting a trigger tx. Also re-enables the suite, which #23976 had skipped. ## Root cause The HA compose suite was the only block-building suite running against an L1 with no self-advancing clock. Its anvil container ran in automine with no `--block-time`, and being external, it was excluded from the `TestDateProvider` sync that locally-spawned anvils get. L1 chain time only moved when something mined, while the shared sequencer clock free-ran. #23821 removed the `AnvilTestWatcher` that used to couple the two clocks in this mode and replaced it with per-iteration nudges in the test (clock warp + blind `mine(8)`). Two consequences, both visible in the failed run's logs: - The `mine(8)` overshoot put L1 ~1.5 slots ahead of the test clock, so each iteration's first propose raced its slot boundary and was silently dropped, followed by a prune that destroyed the pipelined builders' forks (`Fork not found` on all surviving nodes). This race was lost in passing runs too. - Recovery then required the proposers' archiver-sync gate to clear, but the gate's deadline runs on the free-running test clock while nothing mines L1 during the test's `waitForTx` — `Archiver did not sync L1 past slot 109 before slot 110 expired, discarding pipelined work`, repeated until the jest timeout. Whether a run passed or failed came down to seconds of margin on this gate. ## Fix Stop emulating L1 time in the test and run the suite in the same regime as every other block-building e2e (e.g. `e2e_epochs`): - Drop the anvil container and `ETHEREUM_HOSTS` from the HA compose file. With no external L1 configured, `setup()` spawns anvil in-proc with interval mining (`--block-time = ethereumSlotDuration`) and keeps the `TestDateProvider` snapped to L1 block timestamps via the existing stdout listener. The sibling web3signer compose suite already works this way. - Add `automineL1Setup: true` so L1 contract deployment runs under temporary automine before interval mining starts. - Delete all time scaffolding from the test (clock warps, cheat-mining heartbeats, archiver sync nudges). Tests submit a tx and wait, in real time. No assertions change. No production code changes: with a self-advancing L1, the sequencer and publisher behave exactly as on a real network. ## Parallelization The suite file is renamed to `e2e_ha_full.parallel.test.ts`, so CI runs each of its 8 tests as an isolated job in its own compose stack instead of one 15+ minute serial job: - `bootstrap.sh` expands the HA suite per test name (same mechanism as the existing `.parallel` simple tests). - `run_test.sh` forwards the test name into the compose stack and namespaces the docker compose project per test so concurrent jobs on one host don't collide. - `sendTriggerTx` now starts the HA sequencers idempotently, since under per-test isolation the governance/reload/distribute tests run without the first test (previously the only caller of `startHASequencers`). - Three clock-skew test titles contained parentheses, which jest's `--testNamePattern` interprets as regex groups (the filter would silently match nothing); they are retitled. ## Teardown fix (follow-up to the first CI round) The first CI round passed every test body but three jobs (produce-blocks, governance, reload) hung in `afterAll` until the job timeout. Two compounding causes, both fixed here: - `afterAll` reset the shared `TestDateProvider` *before* stopping nodes. The reset rewinds the clock from chain time to wall time — minutes apart after the automine deploy burst — so vote submissions armed against the rewound clock pushed sequencer stops out by that gap. The old 30s abandon-race then gave up, and the abandoned nodes outlived the jest environment, keeping the worker alive until the CI timeout (jest runs without `forceExit`). `afterAll` now stops sequencers first, awaits every node stop fully, and resets the clock last. These three jobs are the ones whose tests end with sequencers still running; the distribute test (which stops nodes in-test, before any reset) passed for the same reason. - Ports #23990 from `merge-train/spartan` (not previously on the v5 line): `CheckpointProposalJob.interrupt()` now propagates to the publisher, cancelling the `sendRequestsAt` slot-deadline sleep on sequencer stop, so a pending vote submission can never block shutdown. The original PR's `e2e_ha_full` teardown changes are superseded by the rework above and were not ported. ## Verification - Three full local runs of the suite via `run_test.sh ha` (all 8 tests each): green in 255s / 254s / 268s of jest time (the old warp-based suite ran 10+ minutes), with zero occurrences of the old failure signatures (`Fork not found`, `Archiver did not sync`, `discarding pipelined work`) — passing runs of the old code showed 12+ `Fork not found` errors even when green. - One per-test CI-style run (`run_test.sh ha <file> "should distribute work across multiple HA nodes"`): the originally flaky test passes standalone in its own compose stack (7 skipped, 1 passed), exercising the full `TEST_NAME` plumbing. - `yarn build`, `yarn format`, `yarn lint` clean; `sequencer-client` unit tests pass (back to the pre-change suite after the revert).
…154) (#23947) ## Motivation A tx sent for real without gas estimation gets fallback gas settings, whose DA gas limit was hardcoded to assume **4 blocks per checkpoint** (`APPROXIMATE_MAX_DA_GAS_PER_BLOCK = MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT / 4 = 196608`). The sequencer's real per-block DA allocation, however, divides the checkpoint budget by the **timetable-derived** blocks-per-checkpoint, which on v5 mainnet (72s slots, 6s blocks) is **10**, not 4. When the real value exceeds 4, a default-gas tx declares more DA than any single block admits, so the proposer prefilter — which checks the declared limit, not actual usage — skips it forever. This is what stranded account/contract deploys in the pipelining e2e runs. Separately, the largest tx we want to support — a maximal contract class registration (~97k DA gas / ~3k blob fields) — does not fit a block at 10 blocks/checkpoint with the general `perBlockAllocationMultiplier` of 1.2 (per-block DA cap 94,372; blob cap 2,949). ## Approach - The node derives the **most a single tx may declare on the network** and advertises it in `getNodeInfo` as `txsLimits`. This is a *network admission limit*: a function of network-wide inputs only — the timetable-derived blocks-per-checkpoint, the per-checkpoint budgets, and the network-minimum per-block multipliers (1.2 general / 1.5 DA). It is computed by shared stdlib helpers (`computeNetworkTxGasLimits` / `getNetworkTxGasLimits` in `stdlib/src/gas/tx_gas_limits.ts`) and never depends on a node's local block-gas caps or its (possibly higher) configured multipliers, so advertising (`getNodeInfo`), enforcement (RPC tx acceptance, gossip validation, pending-pool admission), and the wallet all compute the same value. Reqresp and block-proposal tx validation are intentionally left on well-formedness-only checks. - The DA admission budget scales with blocks-per-checkpoint via `getDaCheckpointBudgetForTxs`, which subtracts blob-encoding overhead (checkpoint-end marker + first-block and subsequent block-end fields) from the raw blob capacity. At v5 mainnet geometry (10 blocks per checkpoint) this yields **117,668 DA gas** as the per-tx admission limit. The builder uses the same basis, so a tx admitted by the DA limit always fits the first block's blob-field cap. - The wallet reads `txsLimits` **once** (cached for the wallet's lifetime) and uses it internally: as the fallback gas limits when the caller declares none, to clamp the limits it derives from its own pre-send simulation, and to validate caller-declared limits — a declared limit above the admission limit fails fast in the wallet with a descriptive error, mirroring the node's inbound validation. The limits are **not** exposed through the wallet API: apps that really need them ask the node (`getNodeInfo().txsLimits`). `txsLimits` is now a **required** field on `NodeInfo`; clients built against this version cannot talk to pre-field nodes. - Gas-limit padding is removed from aztec.js: the `estimateGas` / `estimatedGasPadding` simulate fee options and the `estimatedGas` result field are gone. `simulate({ includeMetadata: true })` exposes the raw `gasUsed` instead, and apps that want explicit limits pad it themselves. Wallets that simulate before send (embedded, CLI) keep their own internal padding defaults. - A new DA-specific per-block multiplier (default 1.5), applied to DA gas and blob fields only, lets the largest contract class deploy fit a single block at 10 blocks/checkpoint while leaving the general L2 multiplier untouched. Checkpoint-level capping still bounds the tail. - `GasSettings.fallback` now requires explicit `gasLimits` (wallets pass the node-advertised limit); the teardown limit is derived from the effective total so teardown DA can never exceed total DA. - The sequencer fails startup (and runtime config updates) only when its per-block allocation *multipliers* are below the network minimums — such a node would admit txs over RPC/gossip it can never pack. Merely restrictive absolute caps (`maxL2BlockGas` / `maxDABlockGas`) are a supported operator knob (the node just builds smaller blocks and leaves larger txs in the pool for other proposers), so they only log a warning. ## API changes - `NodeInfo.txsLimits` is now a **required** field (breaking): `{ gas: { daGas, l2Gas } }` — the most a single tx may declare on the network. Clients that connect to older nodes missing this field will fail. - Wallets validate caller-declared `gasLimits` against the network per-tx admission limit and throw before sending (e.g. `Declared DA gas limit (X) exceeds the maximum this network allows per tx (Y)`). When no limits are declared, the wallet fills in the admission limit. No new wallet API is introduced. - Removed the `estimateGas` / `estimatedGasPadding` simulate fee options and the `estimatedGas` simulation result field (breaking): `simulate({ includeMetadata: true })` now returns the raw `gasUsed` (`totalGas` / `teardownGas`) and apps derive their own limits from it. - `getGasLimits` is no longer exported from `@aztec/aztec.js` (breaking): it moved to `@aztec/wallet-sdk/base-wallet` with signature `(gasUsed, maxTxGasLimits, pad?)`, clamping padded estimates to the admission limit and throwing early if simulated usage exceeds it. A companion `assertGasLimitsWithinNetworkLimits` implements the wallet-side validation. - `GasSettings.fallback` now requires explicit `gasLimits` — read them from the node's `txsLimits.gas` if constructing settings manually. - New sequencer config `perBlockDAAllocationMultiplier` (env `SEQ_PER_BLOCK_DA_ALLOCATION_MULTIPLIER`, default 1.5). - Removed from `@aztec/stdlib`: `getDefaultNetworkTxGasLimits`, `getDefaultMaxBlocksPerCheckpoint`, `DEFAULT_MAINNET_AZTEC_SLOT_DURATION`, `DEFAULT_MAINNET_ETHEREUM_SLOT_DURATION`, `DEFAULT_MAINNET_BLOCK_DURATION_MS`, `APPROXIMATE_MAX_DA_GAS_PER_BLOCK`, `FALLBACK_TEARDOWN_L2_GAS_LIMIT`, `FALLBACK_TEARDOWN_DA_GAS_LIMIT`. Renamed `DEFAULT_PER_BLOCK_ALLOCATION_MULTIPLIER` → `MIN_PER_BLOCK_ALLOCATION_MULTIPLIER` and `DEFAULT_PER_BLOCK_DA_ALLOCATION_MULTIPLIER` → `MIN_PER_BLOCK_DA_ALLOCATION_MULTIPLIER`. ## Changes - **stdlib**: shared `buildProposerTimetable` (timetable); `computeNetworkTxGasLimits` / `getNetworkTxGasLimits` / `getDaCheckpointBudgetForTxs` + per-block multiplier constants (gas); `NodeInfo.txsLimits` is now required; `GasSettings.fallback` requires explicit `gasLimits` and derives teardown from the effective total; `perBlockDAAllocationMultiplier` added to `SequencerConfig` and `BlockBuilderOptions`. - **constants**: re-exports `MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT` with a JSDoc documenting that it is the raw, unattainable blob capacity and that tx-data consumers must subtract the encoding overhead. - **aztec-node**: `getNodeInfo` populates `txsLimits` from `getNetworkTxGasLimits`; the RPC tx-acceptance validator enforces the same network limit it advertises. - **p2p**: gossip and pending-pool tx validators enforce the network admission limit (`maxTxL2Gas` / `maxTxDAGas`) instead of the node's local block-gas caps; uses the shared `buildProposerTimetable`. - **validator-client**: `checkpoint_builder` applies the DA multiplier to DA gas and blob fields. - **sequencer-client**: config default + env mapping; threads the multiplier through the checkpoint proposal job; startup/runtime guard throws only on sub-minimum allocation multipliers and warns on restrictive absolute block-gas caps. - **wallet-sdk**: `BaseWallet` caches node info for its lifetime, fills in missing gas limits from `txsLimits.gas`, and validates caller-declared limits via `assertGasLimitsWithinNetworkLimits`; `getGasLimits` lives here now. - **aztec.js**: `Wallet` interface and method schemas lose the estimation surface; `ContractFunctionInteraction`, `BatchCall`, and `DeployMethod` return raw `gasUsed` in simulate metadata instead of padded estimates. - **wallets / cli-wallet / bot**: the embedded wallet keeps its internal pre-send estimation (padding default 0.1) now clamped to the admission limit; the cli-wallet fee path reads `txsLimits` from the node and derives estimate-only output via a `CLIWallet.estimateGasLimits` helper; the bot sends without explicit limits and lets the wallet derive them. - **foundation**: registers the new env var. - **tests**: `tx_gas_limits` and `gas_settings` unit tests (incl. the teardown invariant and the multiplier/cap distinction); a `checkpoint_builder` red/green test that the largest contract class deploy fits at 1.5 but not at 1.2; wallet-side validation tests in `base_wallet` and `embedded_wallet`. - **docs**: migration notes for the breaking `txsLimits` field, the removed estimation options, `getGasLimits` relocation, `GasSettings.fallback`, removed constants, and the new operator env var. Builds on #23933 (A-1162), which introduced `MAX_TX_DA_GAS`. Fixes A-1154
spalladino
requested review from
IlyasRidhuan,
MirandaWood and
jeanmon
as code owners
June 11, 2026 12:21
…ection (A-1168) (#23977) ## 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 `Pick`ing 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 #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 #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.
…idates multiple checkpoints` (#24017) Fixes a flake in `proposer invalidates multiple checkpoints` (`e2e_epochs/epochs_invalidate_block.parallel.test.ts`) reported on `v5-next`: [failed run](http://ci.aztec-labs.com/e4076dd86c434c6f). Replaces #24016 (was based on `merge-train/spartan`; this one targets the v5 line where the flake fired and restructures the test instead of just resizing the timeout). ## Root cause of the flake `TimeoutError: Operation timed out after 256000ms` — the bare 8-slot `timeoutPromise` waiting for the two bad checkpoints. The bad-slot search from #23608 rejects any candidate pair whose proposer also owns an earlier un-snapshotted pipelined slot, and the rejection window grows with each attempt. In the failed run the current slot was 21 and the search rejected (24,25)…(29,30) before accepting slots **30/31** — 9–10 slots out. The fixed 256s wait expired at 22:48:55, before slot 30 even began (~22:49:00), while the chain healthily mined checkpoints at slots 22–28 underneath; the run was unwinnable at selection time. The race's `.then(() => [CheckpointNumber(0), …])` fallback was also dead code, since `timeoutPromise` rejects. ## Fix: search first, then warp Instead of starting the sequencers and waiting in real time for whatever slots the search lands on: - With sequencers stopped, search for a `warpSlot` such that the proposers of the three lead-in slots `warpSlot+1..warpSlot+3` are not the proposers of the bad slots `warpSlot+4`/`warpSlot+5`. A far-away candidate now costs a warp instead of a real-time wait, and `EpochNotStable` during the search is handled by warping forward one epoch (same pattern as the `archiver skips a descendant` test in this file). - Warp to one L1 block before `warpSlot`, so sequencers get a full L2 slot to boot before the first pipelined build window we rely on (end of `warpSlot`, targeting `warpSlot+1`). - Start the sequencers and wait for the first good checkpoint (lands at `warpSlot`, or up to `warpSlot+2` on a slow start). - Apply the malicious config to the bad-slot proposers. The three good lead-in slots guarantee no pipelined job before `badSlot1` can snapshot it, since jobs snapshot config during the last L1 slot of the previous L2 slot. - Fail fast with a clear assertion if config application was somehow late enough to reach `badSlot1`'s build window, rather than timing out opaquely. - The 8-slot wait for the bad checkpoints is now correctly sized by construction (`badSlot2` is at most ~6 slots from the wait start), and gets a descriptive timeout message. Worst case the wait phase is bounded at ~6 slots regardless of how many candidates the search rejects, where previously each rejected candidate pushed the bad checkpoints one slot further past the fixed timeout. --- *Created by [claudebox](https://claudebox.work/v2/sessions/d509a218614bf4ac) · group: `slackbot`*
AztecBot
enabled auto-merge
June 11, 2026 18:56
Collaborator
Author
|
🤖 Auto-merge enabled after 4 hours of inactivity. This PR will be merged automatically once all checks pass. |
## Motivation
The bot waits for its Fee Juice bridge claim with
`waitForL1ToL2MessageReady` and then immediately simulates the account
deployment that consumes the claim. Readiness was always evaluated
against the `latest` block, but the bot's embedded PXE can be configured
to sync to a slower tip (e.g. `syncChainTip=checkpointed`). When the
tips diverge, readiness passes while the PXE simulation anchors to an
older block whose message tree does not contain the message yet, and
simulation fails with `No L1 to L2 message found for message hash ...`,
sending the bot into a crash loop where it repeatedly validates a claim
it cannot consume.
## Approach
Make readiness answer the question the consumer actually needs: is the
message present at the same chain tip the consuming PXE will anchor its
simulation to?
- `isL1ToL2MessageReady` / `waitForL1ToL2MessageReady` accept an
optional chain tip (`BlockTag`), defaulting to `latest` so existing
callers are unaffected. The helper compares the message checkpoint
against the block at the requested tip.
- The bot does not get a new config knob and no wallet APIs change:
`addBot` extracts `syncChainTip` from the same PXE options its callers
use to build the embedded wallet, and threads it through `BotRunner` →
bot `create` → `BotFactory`. This keeps the readiness tip from drifting
from the PXE's actual config. Polling the node at the PXE's configured
tip (rather than exposing the PXE anchor) is required for the wait to
make progress, since the PXE synchronizer is pull-on-demand and its
anchor only advances on `pxe.sync()`.
- All bot readiness checks now pass the tip: the stored-claim
revalidation and the new-claim wait in `BotFactory`, the cross-chain
setup wait, and the steady-state message selection in `CrossChainBot`.
## API changes
`isL1ToL2MessageReady(node, msgHash, chainTip?)` and
`waitForL1ToL2MessageReady(node, msgHash, { timeoutSeconds, chainTip?
})` in `@aztec/aztec.js/messaging` accept an optional `BlockTag`
(default `'latest'`, preserving previous behavior). Their node
dependency narrowed from `getBlock` to the cheaper `getBlockData`.
## Changes
- **aztec.js**: tip-aware readiness helpers in `utils/cross_chain.ts`;
new unit tests covering the latest fallback and the tip-aware path.
- **bot**: `BotRunner`, `Bot`/`AmmBot`/`CrossChainBot.create`, and
`BotFactory` accept the PXE sync tip and use it at every L1-to-L2
readiness check.
- **aztec**: `addBot` extracts `syncChainTip` from the PXE options and
passes it to `BotRunner`.
Fixes A-1155
rangozd
pushed a commit
to rangozd/aztec-packages
that referenced
this pull request
Aug 5, 2026
…mmitted (AztecProtocol#23975) Cherry-pick -m 1 of public v5-next merge ab5413c (296 files, ~13 PRs: p2p checkpoint-replay fix AztecProtocol#23967, sequencer timetable rework AztecProtocol#23821, peer-ban persistence A-1157 AztecProtocol#23922, aztec_* JSON-RPC rename AztecProtocol#23909, tx-protection release AztecProtocol#23978, checkpoint tips AztecProtocol#23968, gas fallback A-1154 AztecProtocol#23947, consensus config A-1168 AztecProtocol#23977, e2e/bot fixes). RAW state: 46 conflicted paths committed as git left them (list in /dev/null — see the fix(port) commit diff for the full set; markers in text files). The fix(port) commit is the complete hand-written resolution.
rangozd
pushed a commit
to rangozd/aztec-packages
that referenced
this pull request
Aug 5, 2026
…al: alignment to the source train Every path in this commit is byte-identical after this commit to public v5-next at the train merge (ab5413c), including deletions of files the train does not have. Nothing here is hand-judged beyond the block's standing resolve-to-v5 policy; verify with: git fetch https://github.com/AztecProtocol/aztec-packages.git ab5413c git diff ab5413c <this commit> -- <any path in this commit> # empty Accumulated across CI rounds 1-8: the 46 conflict resolutions, the v5 pipelined-timetable redesign consumers aligned wholesale (the 3-way auto-merges produced stale old/new hybrids with no conflict markers), type providers, gov_proposal / sequencer_config / aztec-node server tests, tx_collection tx_source (includeProof for prover-node collection), the epoch e2e suite's l1PublishingTime parameterization, libp2p receive-window clock pins, test_epoch_cache nowMs = slot start, restored stdlib checkpoint.test.ts, aztec-node schema proof-options coverage, automine includeProof:false, and the sequencer README.
rangozd
pushed a commit
to rangozd/aztec-packages
that referenced
this pull request
Aug 5, 2026
…s: import v5's generated MAX_TX_BLOB_DATA_SIZE_IN_FIELDS The previous resolution of the constants.ts conflict took neither side: it re-derived MAX_TX_BLOB_DATA_SIZE_IN_FIELDS by hand in TypeScript, duplicating the Noir formula in tx_blob_data.nr. spartan-v5 deliberately removed that duplication — AztecProtocol#23933 taught the constants generator to extract MAX_TX_BLOB_DATA_SIZE_IN_FIELDS from tx_blob_data.nr into constants.gen.ts, and constants.ts imports the generated value. Take v5's side: - constants.in.ts: port the ADDITIONAL_NOIR_CONSTANT_FILES extraction mechanism (AztecProtocol#23933), so the generator emits MAX_TX_BLOB_DATA_SIZE_IN_FIELDS from tx_blob_data.nr. - constants.gen.ts: MAX_TX_BLOB_DATA_SIZE_IN_FIELDS = 8475 (the generated value). - constants.ts: import MAX_TX_BLOB_DATA_SIZE_IN_FIELDS from ./constants.gen.js instead of re-deriving it; MAX_TX_DA_GAS = MAX_TX_BLOB_DATA_SIZE_IN_FIELDS * DA_GAS_PER_FIELD. All three files are now byte/line-faithful to the source train (ab5413c). MAX_TX_DA_GAS is unchanged at 271200; this is a structural fix removing the duplicated single-source-of-truth derivation, not a value change.
rangozd
pushed a commit
to rangozd/aztec-packages
that referenced
this pull request
Aug 5, 2026
* docs: complete and correct the proving historic state page
Add the missing history::storage module (public_storage_historical_read),
a data-availability caveat (pruning/archive node, 24h anchor window), and a
block-header getter section. Fix the Archive-tree framing (inclusion proofs
are against the note hash / nullifier / public data tree roots committed in a
block header; the Archive tree holds block-header hashes), and correct the
nullifier helpers to say siloed rather than raw nullifier.
* chore(bb-prover): wire BB_DEBUG_OUTPUT_DIR through AvmProvingTester
Pass debugDir and a logger to BBJsFactory so that running the AVM
proving tests with BB_DEBUG_OUTPUT_DIR set actually dumps avm_inputs.bin
and the equivalent bb-avm CLI command to disk (via DebugBBJsInstance).
Without this the env var was silently ignored by these tests.
* fix(docs): fable review
Fix critical issues found in a full docs audit, in both the source docs
and the published v4.3.1 versioned docs:
- counter tutorial: add the missing 'clear the scaffold placeholder test'
note (renaming Main->Counter broke aztec compile with 6 errors)
- token bridge tutorial: correct artifact import paths and bytecode field
for the Hardhat layout, fix the run command (npx tsx), add a note to
update the @aztec/l1-contracts tag, fix a broken relative link
- aztec CLI reference: write the missing 'aztec start' section
- aztec-wallet CLI reference: remove leaked generator-machine defaults
(/home/josh/.aztec/wallet, host.docker.internal)
- sequencer governance/slashing pages: replace removed contract getters
(M/N/yeaCount/proposals -> ROUND_SIZE/QUORUM_SIZE/signalCount/getProposal),
correct the ejection threshold description (rollup localEjectionThreshold,
not '98% / max 3 slashes'), fix 36s->72s slot math
- aztec-nr docs: replace nonexistent APIs (emit_public_log ->
emit_public_log_unsafe, RetrievedNote/HintedNote -> ConfirmedNote,
history::contract_inclusion -> history::deployment), correct the Storage
struct naming claim
- outbox.md (source only): update IOutbox signatures to the
checkpoint-based interface
* docs: correct aztec start source reference
* docs: regenerate v4.3.1 aztec cli reference
* fix(docs): complete truncated v4.3.1 aztec start reference, review fixes
The regenerated v4.3.1 aztec start section was cut off mid-generation:
the --p2pBootstrap.queryForIp description ended mid-word ("Defau"),
which failed cspell and broke the docs deploy preview, and the
TELEMETRY, BOT, PXE, and TXE categories were missing entirely. Restored
from the real v4.3.1 `aztec start --help` output, including the dropped
P2P SUBSYSTEM / P2P BOOTSTRAP category headers.
Also:
- Backtick the setup allow-list format strings so Docusaurus stops
parsing `:selector` as an unused markdown directive.
- outbox.md: update consume() edge-case error signatures to the current
Epoch-typed forms (Outbox__NothingToConsumeAtEpoch, Outbox__AlreadyNullified).
- counter tutorial (both copies): fix stub-comment URL that 404s
(/aztec-nr/... -> /developers/docs/aztec-nr/...).
* fix(docs): correct stale slashing grace period values
The 'First 128 slots' grace period was stale in both copies. The actual
mainnet SLASH_GRACE_PERIOD_L2_SLOTS deployment default is 8,400 slots
(~7 days) at v4.3.1 and 1,200 slots (~1 day) on next, anchored at the
CanonicalRollupUpdated event (spartan/environments/network-defaults.yml,
yarn-project/slasher/src/config.ts).
* chore: add create-issue skill for filing Linear issues
## Summary
Adds a generic `create-issue` skill at `.claude/skills/create-issue/SKILL.md` for turning a unit of work into a well-formed Linear issue.
The skill encodes our conventions so issues are consistent and actionable:
- **Self-contained context** — every issue must contain enough for a fresh agent (no prior conversation) to execute end-to-end: summary, evidence, root cause / approach with `file:line` references, the specific change, and references.
- **1/2/3/5 point estimates** — what each value means, with a reminder to state the reasoning so it can be overridden.
- **Required acceptance criteria** — concrete, objectively checkable, including negative criteria.
- **Two modes** — standalone (ask for team/project/labels/priority) vs. planning a project breakdown (inherit the project's conventions, link issues via parent/`blocks`/`blockedBy`).
Docs-only change (a Claude Code skill); no code or build impact.
## Backport
Labeled `backport-to-v5-next` so the skill is also available on the v5 line.
* feat: add alerts for internal networks (#24090)
Fix A-1139
Alert on:
- any slashing round execution
- missed slots
- checkpoint proposal failures
- L1 failures
- slow gossip validation
- spike in tx validation
- attestation validation issues
- parent checkpoint mismatch
* feat(docs): serve markdown + llms.txt for agent readiness
Improve the docs site's Fern/afdocs "agent score" by making pages
agent-readable:
- Replace docusaurus-plugin-llms with @signalwire/docusaurus-plugin-llms-txt,
covering all four docs instances and emitting a .md sibling per route plus
llms-full.txt (links now point to .md).
- Add a Netlify edge function for `Accept: text/markdown` content negotiation.
- Inject a hidden llms.txt link into every page's <body> and an llms.txt
pointer into every generated page .md (afdocs discovery directives).
- Scope the auto-generated API reference out of the sitemap (drop
augment_sitemap.js) and exclude utility routes, aligning the coverage
denominator with real doc pages; the API stays discoverable via the existing
scoped hub-and-spoke llms.txt.
- Make append_api_docs_to_llms.js idempotent on re-runs.
* fix(docs): negotiate markdown for doc routes ending in a version number
The edge function treated any path ending in .<alnum> as a static file,
so doc routes whose last segment is a version (e.g. a changelog page like
.../changelog/v2.0.2 or v4.2) skipped markdown negotiation. Match only known
static-file extensions instead.
* feat: setup RPC monitoring (#24103)
Fix A-1137. Adds Grafana Cloud monitoring for RPC mainnet deployments.
No alerts are enabled yet.
* docs: point robots.txt at llms.txt for agent discovery
* chore: update Noir to v1.0.0-beta.22 (v5-next, redo of #23870) (#23886)
## Summary
Redo of #23870 against the current `v5-next` (after it was reverted in `9e53e1f` "revert two bad automerges").
Cherry-pick of the original PR head `884e84e8` (the noir submodule bump + Rust/Noir source fixes) plus a second commit that regenerates `yarn-project/yarn.lock`. That lockfile refresh was the explicit "Remaining knock-on" the original PR called out as needing CI/maintainer work; without it, CI's `yarn install --immutable` rejects the mismatched `@aztec/noir-noir_js` file: hash and the `npm:1.0.0-beta.21` references for the noir-* packages.
## Changes
Commit 1 (cherry-pick of `884e84e8`, original PR #23870):
- **`noir/noir-repo`** → `c57152f91260ecdb9faad4efc20abb14b6d2ece7` (`v1.0.0-beta.22`), replacing the off-mainline `temp-serialization-tag` commit (`f1a4575`, "Fixes") that `v5-next` was pinned back to after the revert.
- **`avm-transpiler/Cargo.lock`** → noir crates `1.0.0-beta.21` → `1.0.0-beta.22` (adds `msgpack_tagged`, `serde_bytes`, `bs58`, `tinyvec`; bumps `darling` 0.23, `serde_with` 3.20).
- **`noir-projects/aztec-nr`** → replace the now-deprecated `BoundedVec::from_parts_unchecked` with `BoundedVec::from_parts` in `note_getter.nr` and `utils/array/subbvec.nr` (`aztec-nr` CI runs `nargo check --deny-warnings`, so the deprecation is otherwise a hard failure).
Commit 2 (new):
- **`yarn-project/yarn.lock`** → regenerated against the v5 noir commit `c57152f` (`1.0.0-beta.22`) via `yarn install --mode=update-lockfile` (noir-* package versions `1.0.0-beta.21` → `1.0.0-beta.22`; `@aztec/noir-noir_js@file:` hash `294c27` → `893a3e`; checksum updated).
## Notes
- Same diff shape as the original PR (4 files, +91/-38) plus the `yarn-project/yarn.lock` regen. The yarn.lock change is binary in `git diff --stat` due to the `.gitattributes` `-diff` setting; the textual change is the noir-* version bump + the `file:` hash and checksum update, matching what the `merge-train/fairies-v5` lockfile already carries.
- This is the same lockfile regeneration the parallel fix in #23875 (against `merge-train/fairies-v5`) used, sourced from the prebuilt `noir-packages-7c3d4e0f9363947d.tar.gz` build-cache artifact.
- Tracking label `private-port-next` and `C-noir` mirror the original. `ci-draft` so CI runs while the PR is in draft.
---
*Created by [claudebox](https://claudebox.work/v2/sessions/c29eb43af6cd3071) · group: `slackbot`*
* chore(port): fix(avm-transpiler): lowered cmov was clobbering false branch (AztecProtocol/aztec-packages-private#226)
Forward-port of #226 (merged to v5-next) onto next. Reorders the lowered
ConditionalMov so destination is written once on the taken branch, fixing the
case where destination == source_b clobbered the false branch.
* chore(port): fix(kernel): reject squashing a zero-valued note hash (AztecProtocol/aztec-packages-private#239)
Forward-port of #239 (merged to v5-next) onto next. kernels-audit #538:
validate_squashable_note_hash_nullifier_pair now rejects a zero-valued note
hash linkage, preventing the settled-note nullifier double-spend.
* chore(port): feat: merge-train/fairies-v5 — RAW pick, conflicts committed (AztecProtocol/aztec-packages#23881)
Cherry-pick -m 1 of public v5-next merge b8ac769b1 (193 files, ~12 PRs).
RAW state: the 11 conflicted paths below are committed as git left them
(markers in text files, 'ours' for binaries); the next fix(port) commit
is the complete hand-written resolution.
Conflicted paths:
- noir-projects/aztec-nr/aztec/src/oracle/version.nr
- noir-projects/aztec-nr/aztec/src/standard_addresses.nr
- noir-projects/noir-contracts/contracts/protocol/aztec_sublib/src/oracle/version.nr
- noir-projects/noir-contracts/contracts/protocol/aztec_sublib/src/standard_addresses.nr
- noir-projects/noir-contracts/pinned-standard-contracts.tar.gz
- yarn-project/pxe/src/contract_function_simulator/oracle/interfaces.ts
- yarn-project/pxe/src/contract_function_simulator/oracle/oracle.ts
- yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts
- yarn-project/pxe/src/oracle_version.ts
- yarn-project/standard-contracts/src/standard_contract_data.ts
- yarn-project/txe/src/oracle/txe_oracle_top_level_context.ts
* fix(port): merge-train/fairies-v5 (#23881) — conflict resolution + CI fixups + regenerated standard-contracts artifacts
The complete hand-written part of the #23881 port, on top of the RAW pick:
- resolve all 11 conflicts to the incoming public version (oracle
version/interface hash, pxe/txe oracle imports)
- pinned-standard-contracts.tar.gz REGENERATED from this branch's sources
with this branch's own toolchain (nargo beta.22 + private bb-avm built
from the branch): carries the delivery-mode DiscoveredHandshake
get_handshakes return (98 fields) AND private-bb chonk VKs (5216 bytes)
— fixes both the handshake TXE failure (Expected 98 got 66) and the
earlier BBApiException VK mismatch
- standard_contract_data.ts + both standard_addresses.nr twins rewritten
by the standard-contracts generator (generate_data.ts) from the
regenerated tarball, so the committed derived values match the new
artifacts (addresses change because the handshake artifact changed)
- delete orphaned pxe oracle.ts (deleted upstream by #23915; the
modify/delete conflict otherwise keeps it)
- dedup utilityExecutor in txe_oracle_top_level_context.ts (TS1117)
* chore(port): fix(kernel): bound private-log squashing to the claimed length (AztecProtocol/aztec-packages-private#240)
Forward-port of #240 (merged to v5-next) onto next. kernels-audit #529:
validate_log_squashing forces slots beyond logs.length to be treated as kept,
preventing a planted out-of-length slot from inflating the squashed count and
silently dropping a real kept private log.
* chore(port): feat(pxe): constrained-secret search discipline in syncTaggedPrivateLogs (AztecProtocol/aztec-packages#23948 / #23942)
Forward-port of public merge-train #23948 (merged to aztec-packages:v5-next),
net content = #23942. Cherry-picked merge 0ac07a13 (-m 1): pxe
sync_tagged_private_logs.ts + test (+253/-60). No conflicts.
* chore(port): feat(noir): optionally install nargo from the matching official release (AztecProtocol/aztec-packages#23949)
Forward-port of public #23949 (merged to v5-next). Adds a noir/bootstrap.sh dev
opt-in: with a noir-from-release.flag file and the noir/noir-repo commit pinned
to an official release tag, build_native fetches released nargo instead of
compiling. Cherry-picked 0ae1e7a6 (-m 1): .gitignore + noir/bootstrap.sh +
contract-snapshots/bootstrap.sh (+91/-1). No conflicts.
* chore(port): fix(pxe): prevent contract sync deadlock on nested syncs (AztecProtocol/aztec-packages#23961 / #23951)
Forward-port of public merge-train #23961 (net content = #23951). Cherry-picked
72824f3d (-m 1): pxe contract_sync_service.ts + test (+101/-19). No conflicts.
* chore(port): feat: merge-train/spartan-v5 — RAW pick, conflicts committed (AztecProtocol/aztec-packages#23965)
Cherry-pick -m 1 of public v5-next merge 7baab8368b0 (76 files):
- refactor(prover-node): CheckpointStore + SessionManager redesign (#23552)
- fix: pin getAttesters reads to a single L1 block (A-819) (#23920)
- test: always capture local network logs for compose tests (#23912)
- docs(stdlib): clarify checkpoint capacity ceiling is the provable max (#23952)
RAW state: the 3 conflicted paths below are committed with markers; the
next fix(port) commit is the complete hand-written resolution + the
dependency alignment this pick needs to compile.
Conflicted paths:
- yarn-project/end-to-end/bootstrap.sh
- yarn-project/end-to-end/scripts/docker-compose.yml
- yarn-project/stdlib/src/deserialization/index.ts
* fix(port): merge-train/spartan-v5 (#23965) — mechanical: conflict resolution to source
Resolves the RAW pick's 3 conflicts to public v5-next post-merge, verbatim:
e2e bootstrap.sh + docker-compose.yml log-capture wiring, stdlib
deserialization constants. No hand judgment beyond taking the source side;
every path here matches public v5-next post-#23965.
* fix(port): merge-train/spartan-v5 (#23965) — decisions: A-1156 stdlib alignment
Independent of the conflicts but required to compile — the judgment call in
this block: the train's docs commit (#23952) removes
MAX_BLOCKS_PER_CHECKPOINT, renamed publicly by the unlabeled, never-ported
#23934 (A-1156); private's checkpoint.ts/validate.ts still imported it.
Aligned stdlib/checkpoint/{checkpoint,validate,validate.test}.ts + added
deserialization.test.ts to public. Rename + compat-extending option only;
the A-1156 archiver-ingest BEHAVIOR change is deliberately NOT ported.
* chore(port): feat: initializerless schnorr account contract (AztecProtocol/aztec-packages#23974 / #23962)
Clean cherry-pick (-m 1) of public v5-next merge train 6f5a42147, which
carried a single PR: feat: initializerless schnorr account contract
(#23962). 31 files, no conflicts.
* chore(port): feat(avm): lock-free sharded TraceContainer (AztecProtocol/aztec-packages-private#312)
Clean cherry-pick (-m 1) of private v5-next merge 1e3cfb32b2e: replaces
the AVM TraceContainer's per-column shared_mutex + hash-map storage with
a lock-free sharded design (~4x faster tracegen, ~20% lower peak memory).
2 files (vm2 tracegen trace_container .hpp/.cpp), no conflicts.
* chore(port): feat: merge-train/fairies-v5 r3 — RAW pick, conflicts committed (AztecProtocol/aztec-packages#23992)
Cherry-pick -m 1 of public v5-next merge 951b1fc149c (46 files):
- chore: improve noir contract test tooling (#23946)
- feat(aztec-nr): extend OnchainDelivery builder for secret origin (#23865)
- feat(aztec-nr): wire handshake secret discovery into contract sync (#23938)
- fix(ci): run noir-projects nargo fmt check in CI (#24003)
RAW state: the 4 conflicted paths below (the standard-contracts generated
set — the train changes handshake source, so public regenerated its
artifacts while this branch carries its own regen) are committed as git
left them (markers in text files, 'ours' for the binary tarball); the
next fix(port) commit is the regeneration from this branch's post-pick
sources.
Conflicted paths:
- noir-projects/aztec-nr/aztec/src/standard_addresses.nr
- noir-projects/noir-contracts/contracts/protocol/aztec_sublib/src/standard_addresses.nr
- noir-projects/noir-contracts/pinned-standard-contracts.tar.gz
- yarn-project/standard-contracts/src/standard_contract_data.ts
* fix(port): merge-train/fairies-v5 r3 (#23992) — standard-contracts regen to fixed point
The complete hand-written part of the #23992 port, on top of the RAW
pick. All 4 conflicts are the standard-contracts generated set (the
train changes handshake/aztec-nr source, so artifacts and addresses
move): resolved by REGENERATING from this branch's post-pick sources
with this branch's own toolchain (nargo beta.22 + private bb-avm), then
iterating pin-standard-build + the standard-contracts generator until
the stamp->artifact->address chain reached its fixed point (no drift;
converged on pass 3). Tarball carries the post-#23938 handshake
artifacts with private-bb chonk VKs; standard_contract_data.ts and both
standard_addresses.nr twins are the converged generator output.
* chore(port): fix: bump Grumpkin LIBRA_UNIVARIATES_LENGTH to 4 — RAW pick, conflicts committed (AztecProtocol/aztec-packages-private#304)
Cherry-pick -m 1 of private v5-next merge c73cdde8a99 (8 files): fully
mask committed sumcheck round univariates for Grumpkin (L=4 Libra) +
CHONK_RECURSION_GATES bump + regenerated mock-protocol-circuits pin.
RAW state: conflicted paths below committed as git left them (markers /
'ours' for the binary); the fix(port) commit carries the resolution and
the pinned-artifact regens this change requires.
Conflicted paths:
- barretenberg/cpp/src/barretenberg/dsl/acir_format/gate_count_constants.hpp
- noir-projects/mock-protocol-circuits/pinned-build.tar.gz
* fix(port): Grumpkin L=4 Libra masking (#304) — re-measured gate counts + mock pin regen
The complete hand-written part of the #304 port, on top of the RAW pick:
- gate_count_constants.hpp: both conflicted constants are MEASURED values,
re-derived on this tree by running the pinning tests with a bb built
from this branch + the fix:
CHONK_RECURSION_GATES 1369085 (ours 1368429 / theirs 1367968)
ECCVM_RECURSIVE_VERIFIER_GATE_COUNT 234909 (ours 234253 / theirs 233791)
Neither parent's number is valid here: private bb's gate counts differ
from v5's, and the L=4 fix adds +656 gates on both branches (the same
delta v5 measured). ChonkRecursionConstraintTest.GateCountChonkRecursion
and ECCVMRecursiveTests.SingleRecursiveVerification are green locally
with these values.
- mock-protocol-circuits/pinned-build.tar.gz (binary conflict, both
branches regenerate it): regenerated from this branch's post-pick
sources with this branch's bb (pin-build, clean).
- pinned-standard-contracts.tar.gz: verified UNCHANGED — regenerated and
the extracted contents are byte-identical to the committed tarball
(matches upstream's 'Pinned Chonk VKs unchanged'), so no churn is
committed; the standard-contracts generator also reports no drift.
* chore(port): feat: merge-train/spartan-v5 r2 — RAW pick, conflicts committed (AztecProtocol/aztec-packages#23975)
Cherry-pick -m 1 of public v5-next merge ab5413c72dc (296 files, ~13 PRs:
p2p checkpoint-replay fix #23967, sequencer timetable rework #23821,
peer-ban persistence A-1157 #23922, aztec_* JSON-RPC rename #23909,
tx-protection release #23978, checkpoint tips #23968, gas fallback
A-1154 #23947, consensus config A-1168 #23977, e2e/bot fixes).
RAW state: 46 conflicted paths committed as git left them (list in
/dev/null — see the fix(port) commit diff for the full set; markers in
text files). The fix(port) commit is the complete hand-written
resolution.
* fix(port): merge-train/spartan-v5 r2 (#23975) — mechanical: alignment to the source train
Every path in this commit is byte-identical after this commit to public
v5-next at the train merge (ab5413c72dc5377107943b8614130ec8050bf06c),
including deletions of files the train does not have. Nothing here is
hand-judged beyond the block's standing resolve-to-v5 policy; verify with:
git fetch https://github.com/AztecProtocol/aztec-packages.git ab5413c72dc
git diff ab5413c72dc <this commit> -- <any path in this commit> # empty
Accumulated across CI rounds 1-8: the 46 conflict resolutions, the v5
pipelined-timetable redesign consumers aligned wholesale (the 3-way
auto-merges produced stale old/new hybrids with no conflict markers),
type providers, gov_proposal / sequencer_config / aztec-node server tests,
tx_collection tx_source (includeProof for prover-node collection), the epoch
e2e suite's l1PublishingTime parameterization, libp2p receive-window clock
pins, test_epoch_cache nowMs = slot start, restored stdlib checkpoint.test.ts,
aztec-node schema proof-options coverage, automine includeProof:false, and
the sequencer README.
* fix(port): merge-train/spartan-v5 r2 (#23975) — constants: import v5's generated MAX_TX_BLOB_DATA_SIZE_IN_FIELDS
The previous resolution of the constants.ts conflict took neither side: it re-derived
MAX_TX_BLOB_DATA_SIZE_IN_FIELDS by hand in TypeScript, duplicating the Noir formula in
tx_blob_data.nr. spartan-v5 deliberately removed that duplication — #23933 taught the
constants generator to extract MAX_TX_BLOB_DATA_SIZE_IN_FIELDS from tx_blob_data.nr into
constants.gen.ts, and constants.ts imports the generated value.
Take v5's side:
- constants.in.ts: port the ADDITIONAL_NOIR_CONSTANT_FILES extraction mechanism (#23933),
so the generator emits MAX_TX_BLOB_DATA_SIZE_IN_FIELDS from tx_blob_data.nr.
- constants.gen.ts: MAX_TX_BLOB_DATA_SIZE_IN_FIELDS = 8475 (the generated value).
- constants.ts: import MAX_TX_BLOB_DATA_SIZE_IN_FIELDS from ./constants.gen.js instead of
re-deriving it; MAX_TX_DA_GAS = MAX_TX_BLOB_DATA_SIZE_IN_FIELDS * DA_GAS_PER_FIELD.
All three files are now byte/line-faithful to the source train (ab5413c72dc).
MAX_TX_DA_GAS is unchanged at 271200; this is a structural fix removing the duplicated
single-source-of-truth derivation, not a value change.
* fix(rebase): re-derive measured/generated artifacts after rebases onto advancing next
Round 1 — next advanced 15 merges (incl. the barretenberg merge-train
#273, custom arithmetic gates for kernels: re-measured gate constants,
VK format 5216 -> 4832 bytes). Stack rebased onto f77812b6a17; artifacts
re-derived with a branch-built toolchain: CHONK_RECURSION_GATES measured
1373940 (next's 1373283 + the #304 delta), ECCVM unchanged 234909,
other constants restored to next's values, mock pin + standard-contracts
set regenerated to fixed point (stale ~/.bb vk_cache cleared — it was
injecting old-format VKs into fresh artifacts).
Round 2 — next advanced 8 more merges (incl. #335, translator
delta-range lower anchor: chonk base +25). Stack rebased onto
2fbbe4c5f80; re-measured on this tree: CHONK_RECURSION_GATES = 1373965
(ChonkRecursionConstraintTest green), ECCVM unchanged 234909
(SingleRecursiveVerification green); all other constants at next's
current values; mock pin + standard-contracts set regenerated to fixed
point with this base's bb (converged pass 1).
Note: private#336 (ECCVM msm_pc interior-skew pin, port of #208 to
v5-next) needed NO port — #208 merged into next directly; its
cherry-pick is content-empty here apart from these same re-derived
artifacts.
* feat: merge-train/fairies-v5 (#24020)
BEGIN_COMMIT_OVERRIDE
feat: use initializerless accounts (#23973)
fix: remove type assertion (#24023)
feat: richer EphemeralArray and TransientArray APIs (#23982)
fix: merge train conflicts (#24047)
fix: restore v5-next merge ancestry on fairies merge train (re-open
#24047) (#24049)
fix: client flows benchmarks (#24055)
END_COMMIT_OVERRIDE
* fix(port): merge-train/fairies-v5 r4 (#24020) — standard-contracts pin regen
The pick applied cleanly, but its aztec-nr changes (unconstrained_array
module + richer Ephemeral/Transient array APIs) alter the compiled
standard-contract artifacts, so pinned-standard-contracts.tar.gz is
regenerated from the post-pick sources with the branch toolchain.
Address stamps did NOT move (generator converged with no drift on
pass 1), so only the tarball changes. Workspace typecheck clean of
stack-attributable errors.
CI round 8: align e2e_bot.test (hardcoded-gas test declares MAX_TX_DA_GAS,
the per-tx cap, not next's checkpoint-wide MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT
which inbound validation now rejects) and epochs_test (v5-at-r4 harness
defaults; the l1PublishingTime parameterization the epoch suite's v5 files
no longer pass) to this block's source state.
* chore(port): fix(noir-protocol-circuits): fail when pinned VKs do not match — RAW pick, conflicts committed (AztecProtocol/aztec-packages-private#364)
Cherry-pick -m 1 of 96912451ca4. Conflicted paths (markers committed as git
produced them):
- noir-projects/noir-protocol-circuits/bootstrap.sh
* fix(port): fail when pinned VKs do not match (#364) — extraction-style resolution
The only conflict was the pinned-build extraction: this branch's pin tarball
stores artifacts at the archive root (created with 'tar czf ... -C target .'),
so extraction keeps 'mkdir -p target && tar xzf pinned-build.tar.gz -C target'
where the source extracts in place. The VK-consistency gate is appended
verbatim after extraction; generate_vk/check_pinned_vk refactor applied clean.
noir-protocol-circuits does not track a pinned-build.tar.gz on this branch
today, so the gate is dormant here until a pin is committed — ported to keep
the safety net consistent with v5-next.
The v5-only chonk repro fixture deletions (chonk_fail_input,
public_chonk_verifier_repro.test.ts) were no-ops: those files never existed
on this branch.
* chore(port): reject non-canonical x coordinate (native affine_element) — RAW pick, conflicts committed (AztecProtocol/aztec-packages#24029)
Cherry-pick -m 1 of 5fd61870609. Source code (affine_element from_compressed
range check + regression test, grumpkin SRS v2 rename across crs scripts/ts,
ECCVM fixed VK) auto-merged onto our content. Binary conflicts committed as
git left them:
- noir-projects/mock-protocol-circuits/pinned-build.tar.gz (content)
- noir-projects/noir-protocol-circuits/pinned-build.tar.gz (modify/delete; our branch does not track it)
* fix(port): reject non-canonical x coordinate (#24029) — pin resolutions + mock pin regen
Block 17 (aztec-packages#24029) switches the build to the grumpkin SRS v2
(grumpkin_g1_v2.dat), which moves the mock-protocol-circuits chonk VKs even
though their bytecode is unchanged. The mock pin was previously kept at its
pre-v2 form so the CI mock-protocol-circuits leg would confirm the staleness
before spending a bb rebuild; it did (check_pinned_vk mock_rollup_tx_base_private
mismatch).
Regenerated noir-projects/mock-protocol-circuits/pinned-build.tar.gz with this
branch's bb/bb-avm (clang20) via `bootstrap.sh pin-build` — all 13 mock circuits
recompiled and re-keyed (mock_rollup_root ultra_honk, mock_rollup_tx_base_public
GoblinAvm included), zero failed jobs. noir-protocol's pin stays deleted
(introducing v5-next's would trip the #364 VK-consistency gate against our bb).
* chore: fix next-net dns
* fix(telemetry): raise span queue size and make telemetry shutdown idempotent (#24121)
* refactor: sticky session based on IP (#24120)
Pin session by client ID rather than cookie, add Kong healtchecks and
clean up namespaces.
* feat(ci3): run uploadable benchmarks on a dedicated on-demand instance
> [!IMPORTANT]
> Depends on the IAM change aztec-labs-eng/iac#6 (grants `ci3-build-instance-role` the launch/SSM/PassRole surface). **That must apply first**, else the build instance's `create-fleet` hits `UnauthorizedOperation`.
## Problem
Spot diversification (create-fleet) means build instances now land on variable EC2 types — m6a/m7a/m6i/r6a/r7a at 16/32/48xlarge, AMD vs Intel. The in-build benchmark phase runs on that box, so wall-time numbers vary by hardware family far more than the 105% regression alert threshold → false regressions. (The instance type isn't even recorded in the bench JSON.)
## Approach
Only the canonical **merge-queue→next** series (the one used for real regression tracking) runs benches on a **dedicated, fixed, on-demand m6a.16xlarge**. PR `ci-full` runs keep running benches inline on the contended build box purely as a **breakage check** — no dedicated box, no upload.
Benches are scheduled by the existing test engine: when the build completes in `build_and_test` (full builds only),
- **upload runs** (`SHOULD_UPLOAD_BENCHMARKS=1`): launch the dedicated box via `./ci.sh bench` as a backgrounded, colored, denoised job (logged like the test engine) and `wait` on it (non-fatal) before returning;
- **otherwise**: `bench_cmds >> $test_cmds_file` — benches become ordinary test commands.
`ci.sh bench` → `bootstrap_ec2` blocks until the remote `ci-bench` finishes (ending in `cache_upload bench-<treehash>`), so the `wait` is the whole rendezvous. Results reach the GA `Upload benchmarks` step unchanged via that cache key (`ci3_success.sh` `gh-bench`).
## Changes
- **`bootstrap.sh`**: drop inline `bench` from `ci-full`/`ci-full-no-test-cache`; add the `build_and_test` launch/append hook + non-fatal `wait`; new `ci-bench` mode = cache-hit `make full` + `bench` (no test engine).
- **`ci.sh`**: new `bench` launcher — `AWS_INSTANCE=m6a.16xlarge NO_SPOT=1` (pins a fixed on-demand type; `CPUS` not needed since `AWS_INSTANCE` bypasses pool sizing).
- **`ci3/bench_engine`**: drop the 8-core OS isolation / HT-disable / pinning. Dedicated box → benches use the full machine, honouring per-bench `CPUS` via the strict scheduler (defaults to `nproc/2` without `BENCH_CPU_COUNT`). This is what lets the 64-vCPU 16xlarge satisfy the `CPUS=32` bb rollup bench.
- **`.github/ci3_labels_to_env.sh`**: scope `SHOULD_UPLOAD_BENCHMARKS` to merge-queue→next (it now also gates the dedicated box). **`ci3/bootstrap_ec2`**: pass it through to the instance.
## Notes
- **One-time baseline shift** in `bench/next`: different machine + no isolation changes absolute numbers once; stable thereafter. May want to annotate the series.
- **Soft failure**: a bench-box failure is logged and the run proceeds (no fresh numbers) rather than blocking the merge.
- **PR benches-as-tests**: `:PARALLEL=0` serial benches lose one-at-a-time isolation and run contended — fine for breakage-only; real numbers come from the dedicated box's `bench_engine` path.
- Validated: all touched scripts pass `bash -n`; the `AWS_INSTANCE`+`NO_SPOT` fixed-on-demand launch mechanism was verified live during the create-fleet work. Full e2e is exercised by a merge-queue→next run once the iac PR lands.
* chore: disable v4-nightlies (#24125)
.
* fix(ci): refresh stale mock_hiding pinned VK in mock-protocol-circuits
* feat(ipc): add IPC runtime and codegen foundation
Introduce ipc-runtime (msgpack-over-UDS/SHM transports for C++, TS, Rust, Zig)
and ipc-codegen (schema-driven client/server/dispatch generator for the same
four languages), plus the echo example and its cross-language wire-compat
test matrix.
Runtime:
- UDS and shared-memory transports (single-client SPSC and multi-client MPSC
rings) behind a common IpcClient/IpcServer interface, with NAPI bindings.
- Unified constants and timeout semantics, max-frame guards, frame-desync
detection, and shutdown/cancellation via futex wake (SHM) / fd close (UDS).
- NAPI lifecycle hardening: clean close/join, no TSFN leak, the process exits
when no calls are in flight.
Codegen:
- Human-authored JSONC schema format: a single per-service object
(service/aliases/types/error/commands with shorthand type refs) that lowers
to the internal named_union IR the four generators consume, so output is
identical across the friendly and legacy positional forms. Naming derives
from the 'service' field; aliases support bin32 (nominal) and scalar synonyms.
- Generators hand-roll the [name, payload] msgpack framing keyed on
MSGPACK_SCHEMA_NAME (no C++ schema reflection).
- Schema validation, unified server error wrapping, and per-language wire
fixes (rust Option<bytes>/[bytes;N], ts u64 bigint + bin32, zig signed-int
tolerance), with a golden corpus pinning canonical msgpack output.
Full echo test matrix (golden x4, UDS 4x4, SHM, ts_package) passes.
* refactor(wsdb): migrate to generated ipc package
Generate the @aztec/wsdb TS package and the wsdb C++ client/server from
wsdb_schema.jsonc via ipc-codegen instead of the hand-written bindings.
Add a "bin" entry to the generated package.json (when the package wraps a
native binary) so the binary lands on the user's PATH on install. The bin
target is a generated JS launcher (src/bin.ts -> dest/bin.js) that resolves the
native binary via the same per-arch resolution as the spawned client and execs
it forwarding argv/stdio/exit code — the binary itself ships in the per-arch
optional-dependency packages, and npm only links the main package's own bin.
* chore(ci): run nightly spartan bench namespaces from private repo only
* ci: reusable network-teardown action that runs on GitHub runners
* ci: use OIDC role for nightly spartan benchmarks
The nightly spartan bench jobs authenticated to AWS with long-lived
IAM user keys (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY for user/adam),
which lack iam:PassRole on ci3-build-instance-role and fail with
UnauthorizedOperation when CI3 launches build instances.
Switch all six AWS-touching jobs (benchmark, proving-benchmark,
block-capacity-benchmark and their cleanup jobs) to the GitHub OIDC
role already used by ci3.yml and already trusted for this repo in the
Labs iac repo (terraform/oidc, policy ci3-pipeline-exec-full.json,
which grants PassRole). Each job now sets id-token: write and assumes
the role via aws-actions/configure-aws-credentials; downstream steps
inherit the credentials from the job env.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(prover-node): provers dashboard checkpoint metrics
* fix(ci): nightly spartan bench reports correct PASSED/FAILED in Slack
* feat: enable v5 testnet RPC (#24165)
.
* docs: point testnet docs at v5.0.0-rc.1 and refresh networks.md testnet addresses
* update PR #24168
* Add custom bytecode tests for SET_FF with overflowing value
* Move getInstructionSize() to instruction_serialization.ts
* docs: finish v5.0.0-rc.1 testnet cut (TS API, CLI/node-API refs, FPC + L1 addresses)
Completes the v5.0.0-rc.1 testnet docs release that was blocked in the prior
environment:
- Generate the TypeScript API for testnet (static/typescript-api/testnet/,
9 packages) from the v5.0.0-rc.1 tag source.
- Regenerate CLI references from the installed v5.0.0-rc.1 binary (the
tag-committed copies were stale): the three developer refs, the operator
cli-reference.md, and the node JSON-RPC API reference.
- Set the canonical SponsoredFPC address (CLI-computed) in networks.md, the
v5 snapshot, and the live testnet getting-started page.
- Resolve two L1 periphery addresses on-chain: Reward Booster (via
Rollup.getRewardConfig) and Slash Payload Cloneable (via
SlashingProposer.SLASH_PAYLOAD_IMPLEMENTATION).
- Fix broken MessageDelivery API-reference links in the v5 snapshot's
state_variables.md (global.MessageDelivery -> struct.MessageDelivery) and
add "uncheckpointed" to the cspell dictionary.
* docs: mark testnet Register New Rollup Version Payload as N/A
The v5 testnet canonical rollup (registry.getCanonicalRollup()) is the
registry's genesis rollup, not registered via a governance payload. None of
the four on-chain governance proposals registers it; the previously-listed
address was an unrelated executed rehearsal proposal that registered a
different rollup.
* feat(avm): per-column sizes for public inputs in recursive verifier
Replace the single AVM_PUBLIC_INPUTS_COLUMNS_MAX_LENGTH (applied to all four
public input columns) with per-column lengths, so the AVM recursive verifier
no longer hashes or MLE-evaluates the trailing zeros of the shorter columns.
Per-column lengths: col0=4685, col1=4683, col2=522, col3=99 (combined 9989
vs 18740), removing 8751 trailing-zero elements. This saves ~221,692 gates in
the two-layer recursive verifier and the public base rollup that embeds it.
The committed public-input columns remain pinned to zero beyond each column's
length by the MLE consistency check, so the change is sound; tracegen, the
prover/verifier Fiat-Shamir hashing, the Noir serialize_to_columns and the
C++ flat_to_columns all switch to per-column lengths consistently.
* fix(avm): regenerate mock pinned-build for per-column public input length
The mock-protocol-circuits pin freezes compiled bytecode (restored in CI instead
of recompiling). The per-column change reduced AVM_PUBLIC_INPUTS_COLUMNS_COMBINED_LENGTH
to 9989, but the committed pinned-build.tar.gz still embedded the old 18740, so the
freshly-built bb-avm aborted check_pinned_vk for mock_rollup_tx_base_public with
'Flattened public inputs vector size does not match the expected combined length'.
Regenerated via 'bootstrap.sh pin-build' so the pinned mock bytecode (and VKs) match
the new 9989 length. Verified check_pinned_vk passes for all mock circuits.
* test(avm): guard public-input column lengths against silent truncation
serialize_to_columns (Noir) copies only rows [0, COLUMN_i_LENGTH) of each column, so a
field mapped past a column's length is silently dropped from the AVM proof — a latent
soundness footgun that the IMPORTANT comment in constants.nr was the only guard against.
Add out-of-circuit invariant tests (no gate impact):
- Noir: deserialize a maximally-populated AvmCircuitPublicInputs (all fields non-zero,
covering future fields automatically) and assert to_columns()[i] is zero for every row
in [COLUMN_i_LENGTH, MAX_LENGTH), i = 1,2,3.
- C++: to_columns() returns columns sized exactly at their per-column length (jagged), so
the equivalent invariant is tightness — populate each column's last row and assert sizes
match the constants and the final cell is non-zero. A field past Lᵢ is then an
out-of-bounds write caught under assert/sanitizer builds.
* Add comments related to writing accumulated data
* docs(avm): address PR review comments on public-input column length tests
- prover.cpp: point the trailing-zeros note at the consistency check (evaluate_public_input_column).
- avm_io.test.cpp / avm_circuit_public_inputs.nr: trim the wordy test comments.
* feat: merge-train/fairies-v5 (#24117)
BEGIN_COMMIT_OVERRIDE
chore: remove obsolete no_predicates wrappers (#7729) (#24093)
feat!: change for_each iteration order in CapsuleArray, EphemeralArray,
TransientArray (#24021)
END_COMMIT_OVERRIDE
* feat: merge-train/spartan-v5 (#24053)
BEGIN_COMMIT_OVERRIDE
refactor(stdlib)!: thin chain-checkpointed event, collapse sync (#24007)
refactor!: remove proposedCheckpoint tip (#24008)
fix(sequencer): wait for previous L1 block before publishing (#24037)
test(e2e_fees): bridge fee juice from a dedicated L1 account (#24054)
fix(aztec-node): pipelining-aware slot and fee simulation in
simulatePublicCalls (#24031)
refactor: move registerContractFunctionSignatures to the node debug API
(#24066)
fix: resolve v5-next → merge-train/spartan-v5 conflict (#24072)
chore: merge v5-next into merge-train/spartan-v5 (raw, conflict markers)
(#24071)
test(ci): mark e2e_epochs/epochs_mbps_redistribution as flaky (#24098)
fix: isolate cross-chain L1 writes from publisher nonce (#24104)
test(world-state): make delayed-close fork queue-cleanup wait
deterministic (#24106)
fix(kv-store): lazy-load skipped browser benchmark deps (#24108)
feat(p2p): slash proposers exceeding max blocks per checkpoint (A-1166)
(#24041)
fix(stdlib): fix race conditions in L2BlockStream (#24042)
test(prover-node): make checkpoint store pruning test deterministic
(#24130)
END_COMMIT_OVERRIDE
* feat: merge-train/fairies-v5 (#24134)
BEGIN_COMMIT_OVERRIDE
fix(simulator): make circuit recorder concurrency-safe via
AsyncLocalStorage (#24112)
refactor(pxe): restore satisfies-typed oracle registries (#24132)
END_COMMIT_OVERRIDE
* feat: merge-train/fairies-v5 (#24144)
See
[merge-train-readme.md](https://github.com/AztecProtocol/aztec-packages/blob/next/.github/workflows/merge-train-readme.md).
This is a merge-train.
* feat: merge-train/fairies-v5 (#24152)
BEGIN_COMMIT_OVERRIDE
fix: allow prover mode autodetection (#24151)
fix(pxe): repoint broken debugging docs link in PXE error messages
(#24145)
END_COMMIT_OVERRIDE
* feat: merge-train/fairies-v5 (#24176)
BEGIN_COMMIT_OVERRIDE
fix(ci): import initializerless account in CLI acceptance test (#24175)
END_COMMIT_OVERRIDE
* update rpc
* feat: merge-train/spartan-v5 (#24148)
BEGIN_COMMIT_OVERRIDE
fix(test): reliably find target proposer in sentinel_status_slash
(A-1217) (#24143)
fix(test): wait for full gossip mesh before committee produces (A-1219)
(#24149)
fix: init bb.js sync singleton before subsystems start in createAndSync
(#24147)
feat(prover-node): capture checkpoint-level proving metrics (#24051)
fix: stabilize scenario invalidation timing (#24128)
fix: set default inbox lag to 2 (#24127)
test(spartan): wait for proposed instead of checkpointed in
performTransfers (#24123)
fix(validator): make block-number guard reorg-aware (A-1218) (#24141)
fix(test): pin AZTEC_INBOX_LAG=1 in sandbox compose envs (#24162)
chore(sequencer): downgrade insufficient-txs block log to verbose
(#24164)
fix(test): use in-memory file store for TxFileStore tests (A-1211)
(#24167)
fix(test): handle default inbox lag of 2, remove temporary inboxLag=1
pins (A-1250) (#24170)
fix(world-state): clean up queues for destroyed forks (#24178)
END_COMMIT_OVERRIDE
* docs: clean up and align v5.0.0-rc.1 migration notes
Migration-notes review for the v5.0.0-rc.1 release (developer snapshot +
unversioned source):
- Restructure: fold `## TBD` + `## Unreleased (v5)` into a single
`## 5.0.0-rc.1` heading (frozen snapshot); the unversioned source keeps an
empty `## TBD` on top for future entries. Remove a stray git conflict marker
in the snapshot.
- Merge three superseded intermediate entries into their accurate siblings
(verified against the v5.0.0-rc.1 source), preserving their unique guidance:
- `set_sender_for_tags` "scoped" -> "oracle removed" (account-contract /
`sendMessagesAs` guidance kept).
- `emit_*_unsafe` "deprecated" -> "now take BoundedVec" (array->BoundedVec
conversion examples kept).
- `aztec-up` "transitive npm bins" -> "bundled binaries no longer bare"
(shell-profile cleanup steps kept).
- Fix three accuracy bugs: `public_checks` demotion slot 6 -> 4;
`ContractDeployer.deploy` prose (args first, instantiation second);
`LogResult` now lists the required `txIndexWithinBlock` field.
- Sync the unversioned source's v5 section to match the snapshot (it was
missing ~10 v5 entries); its `## 4.3.0`+ history (with macros) is unchanged.
* docs: re-resolve v5.0.0-rc.1 developer snapshot include_code from the v5 tag
The developer versioned snapshot's `#include_code` snippets had been resolved
against the `next` (v6) working tree rather than the v5.0.0-rc.1 tag, so 23
pages embedded v6 example/contract code instead of what shipped in v5 (e.g.
`MessageDelivery::onchain_constrained` where v5 uses `onchain_unconstrained`).
Re-cut the developer snapshot from a v5.0.0-rc.1 worktree (preprocess +
docs:version run against v5 source so includes resolve correctly), then
re-applied the artifacts that are intentionally newer than the tag: the CLI
references (regenerated from the v5 binary), the node JSON-RPC reference, the
cleaned migration notes, the canonical SponsoredFPC address, and the
MessageDelivery API-reference link fix.
Scope verified: only the developer snapshot was affected. The operator/network
snapshot, aztec-nr API (delivery/ structure), and TypeScript API were already
generated from v5. Full `yarn build` passes (no broken links in the snapshot).
* docs: fix dead testnet RPC URL in getting started guide
Point NODE_URL at https://v5.testnet.rpc.aztec-labs.com, matching the
endpoint in networks.md. The previous host rpc.testnet.aztec-labs.com
no longer serves requests, so the guide failed at the first step.
* update PR #425
* Update discard.pil
* docs: fix testnet getting-started and bridge/counter tutorials
- Drop the stale '~36 seconds' block-time row from the testnet getting
started comparison (block time is variable, not a fixed value).
- Add @aztec/viem@2.38.2 to the token bridge tutorial install command;
its scripts import @aztec/viem, which is versioned off the Aztec
release line (mirrors upstream viem) and has no 5.0.0-rc.1 build.
- Add a 'clear the scaffold test' note to the counter tutorial so
'aztec compile' stays clean after renaming the contract to Counter
(matches the existing note in the token tutorial).
* docs: note @aztec/viem off-release versioning in release-docs skill
Future docs cuts must not rewrite @aztec/viem to the release version: it
mirrors upstream viem (e.g. 2.38.2) and has no Aztec-release-line build,
yet type-checks in CI via the auto-linked workspace copy, so the missing
installable version slips through. Tutorials importing @aztec/viem must
list it at its own pinned version in their install command.
* docs: update release-docs skill for the dedicated testnet getting-started page
Step 10 said no getting_started_on_testnet.md page exists; it does now.
Document updating NODE_URL/SPONSORED_FPC_ADDRESS/version there, keeping
NODE_URL in sync with the networks.md RPC endpoint (they drift apart),
and avoiding fixed block-time figures. Add the page and the NODE_URL
check to the Step 12 review.
* docs: drop block-time guidance from release-docs skill testnet section
* docs: tighten release-docs skill prose
* docs: correct v5.0.0-rc.1 migration notes
- Fix swapped protocol-contract slot numbers: multi_call_entrypoint was
hardcoded at 4 (not 6) and public_checks at 6 (not 4) in v4.3.1; reorder
the compaction sentence's contract list to match slots 1, 4, 6.
- Correct the PublicKeys entry: v5 PublicKeys has 6 fields (adds the new
mspk_m_hash and fbpk_m_hash), so the ContractInstancePublished event is
15 fields and the TS constructor takes 6 args (were 13 / 4).
- Remove the stale 'sandbox' keyword/tag from the frontmatter.
* chore: top-level tenstet DNS record
* feat: merge-train/spartan-v5 (#24181)
BEGIN_COMMIT_OVERRIDE
fix(ethereum): skip unfunded publishers in selection (#24180)
test(e2e): deflake epochs_mbps_redistribution (#24182)
feat(prover-node)!: wire prover JSON-RPC API to the admin endpoint
(#24189)
END_COMMIT_OVERRIDE
* chore: testnet-v4
* fix: resolve public-next → next merge conflict
* fix: resolve public-next -> next merge conflicts
Resolves the 6 conflicts from the raw merge (cb/merge-public-next-raw):
- .github/ci3_labels_to_env.sh: keep private-repo release safety gate, adopt
public's updated bench-upload comment.
- .github/workflows/nightly-spartan-bench.yml: adopt public's network-teardown
composite action for all 3 teardown steps (pure gcloud, no EC2 build instance).
- Makefile: union the fast test-target list (keep private contract-snapshots-tests
and public ipc-codegen-tests).
- barretenberg/.../bbapi/bbapi_chonk.cpp: keep private BB_HAS_BATCH_VERIFIER_SERVICE
macro guard and INT_MAX write-chunk (Windows/MinGW aware), consistent with the
rest of the file.
- docs/.../migration_notes.md: keep private TBD notes, drop a stray committed
conflict-marker artifact, take public's '4' for the multi_call_entrypoint index.
- yarn-project/world-state/src/native/ipc_world_state_instance.ts: accept public's
deletion (file is orphaned; no importers in next or public-next).
* feat(ipc): concurrent wsdb server — async handlers + per-fork ordering
Asynchronous server-handler codegen across C++/Rust/Zig (TS already async):
the generated dispatch hands each handler a respond callback, so a handler may
run inline or defer to a thread pool and respond when ready. The wire protocol
is unchanged. ipc-runtime gains run_reactor (a non-blocking reactor that owns
all ring I/O, is the sole sender, and reorders responses per connection) plus
notify()/wait_for_data_or_ready for completion wakeups, and the run() serial
loop is unchanged.
The wsdb C++ server adopts this: each of the 40 handlers declares its own
ordering via schedule_read / schedule_write (reads concurrent, committed reads
unordered, writes exclusive per fork), and WsdbScheduler implements the
read-batch / write-barrier model with an inline fast path when idle and a
dispatch pool distinct from WorldState's intra-op pool.
This is the IPC-machinery layer that the wsdb cutover builds on; it is
independent of the world-state IPC consumer. Includes the single-connection
parallel-read benchmark (transport-agnostic).
* feat: Poseidon2 -2 rows/perm
## What
Poseidon2 **bridge-row compaction**: merge all five Poseidon2 gate kinds into the single `poseidon2_quad_internal` block so each permutation's rows are contiguous, letting the existing `v_k = w_shift` round relations bind directly across the external↔internal boundary. Removes **2 unconstrained bridge rows per permutation** (the propagate row after the first external group, and the standard-transition row after the internal rounds) — a pure commitment win, zero added sumcheck, proof length unchanged.
## Scope (rebased onto current `next`)
Applied across **all four** Mega chonk flavors — `MegaFlavor`, `MegaZKFlavor`, **`MegaAppFlavor`**, **`MegaKernelFlavor`**:
- **flavor-codegen**: reassign the external/initial poseidon2 relations to `gateBlockName: "poseidon2_quad_internal"` in `mega.ts` / `mega_zk.ts` / `mega_app.ts` / `mega_kernel.ts`; keep `poseidon2_external` as an empty block in the shared Mega trace; regenerate all flavor + trace headers.
- **builder**: a Mega `create_poseidon2_external_gate` override + redirected initial gate emit into the merged block.
- **permutation**: contiguous row emission, dropping the propagate-after-first-group row and the standard-transition row.
## ⚠️ Audit
This edits the audited `poseidon2_permutation.cpp`; its audit-status header is **reset to `not started`** — the bridge-row layout change needs re-audit (internal + Spearbit). The malicious-prover soundness suite (`poseidon2.bridge_row_soundness.test.cpp`) and `Poseidon2QuadInternalSoundnessTests` pin the new boundary handoffs and pass; `boomerang_value_detection` confirms the duplicate-provenance tagging is intact.
## Validation (local, freshly-derived VKs)
- `stdlib_poseidon2_tests` 29/29 (incl. bridge-row malicious-prover soundness)
- `chonk_tests` 40/40 (Mega IVC prove+verify, recursive verifier, ZK hiding kernel, bad-proof + tampering rejection)
- `boomerang_value_detection` 161/161 · `dsl_tests` + `goblin_tests` gate-count suites green
Rotates every kernel VK; pinned Chonk inputs refreshed (`chonk-inputs.hash` → `8bd693632a8b97e6`). Mega gate-count pins re-derived on this base (Honk recursion, Hypernova kernels, `POSEIDON2_PERMUTATION`, BatchMerge `VERIFIER_NUM_GATES`).
Co-authored-by: iakovenkos <sergey.s.yakovenko@gmail.com>
* fix(wsdb): regenerate yarn.lock to capture aztec-wsdb bin entry
* fix update inputs
* chore(noir-contracts): repin standard contracts with poseidon2 bb-avm
Regenerate pinned-standard-contracts.tar.gz with the AVM-enabled bb so the
standard-contract VKs reflect the poseidon2 bridge-row change. build() extracts
this pin and skips recompiling standard/ contracts, so their precomputed VKs
(e.g. MultiCallEntrypoint:entrypoint) never refreshed on the backend change,
causing the chonk capture VK gate to reject deploy flows. Also document this
repin step in the chonk-inputs skill.
* docs: apply fable review fixes to v5.0.0-rc.1 versioned docs
Port the developer/operator doc corrections from PR #24005 into the
v5.0.0-rc.1 versioned snapshot: ConfirmedNote rename, emit_public_log_unsafe,
history::deployment assert_contract_* API, Outbox partial-proof signatures,
governance getProposal/ROUND_SIZE/QUORUM_SIZE/signalCount, mainnet slashing
values, and token_bridge tutorial fixes. Verified against the v5.0.0-rc.1 tag.
* chore: update yarn.lock
* chore(standard-contracts): regenerate address stamps after poseidon2 repin
The standard-contracts repin (12309df15a) rotated standard contract VKs ->
privateFunctionsRoot -> classId -> address, but did not regenerate the derived
address constants. Regenerate the three generator outputs so dependent Noir
contracts and TS consume the new MultiCallEntrypoint/AuthRegistry/PublicChecks/
HandshakeRegistry addresses.
* ci: route staging-internal deploy failures to #alerts-staging-public
* Apply suggestion from @ciaranightingale
Co-authored-by: ciaranightingale <52419674+ciaranightingale@users.noreply.github.com>
* docs: clarify private historical public reads and sync v5 page
Distinguish reading historical public storage from a private function
(no enqueued public call needed) from reading the live value, and explain
that PublicImmutable/DelayedPublicMutable private reads go through
public_storage_historical_read via WithHash. Define what a siloed
nullifier is for the history table. Mirror the same changes into the
v5.0.0-rc.1 versioned page.
* fix(standard-contracts): re-pin against regenerated addresses to a fixpoint
The earlier repin (12309df15a) compiled the pinned standard contracts against the
pre-rotation address stamps, so MultiCallEntrypoint baked in the OLD HandshakeRegistry
address; after the stamps were regenerated, the pinned entrypoint still called the old
address and account-deployment capture failed with 'Function artifact not found'.
Standard contracts cross-reference each other's addresses (entrypoint -> registries), so
pinning requires iterating pin-standard-build + address regeneration until generation
reports no drift. Re-pin to that fixpoint and commit the consistent pin + stamps.
* upd skill
* chore(bb): refresh pinned Chonk IVC inputs to 24371d103174077c
Generated by ci-refresh-chonk.
Only the pinned Chonk input hash is committed here; the immediate follow-up CI run is skipped intentionally.
--ci-skip
* remove nonexistent hn cpp
* fix(chonk-inputs): build only the bb-avm target in capture
The capture-time AVM build used `bootstrap.sh build_preset "$bb_preset" --target bb-avm`,
but build_preset ignores extra args, so it rebuilt the whole preset and only incidentally
produced bb-avm. Use cmake_build, which forwards --target, to build just bb-avm.
* fix noir test
* fix(docs): remove duplicate markdown-negotiation edge function declaration
The edge function declares its own path via the inline config export in
markdown-negotiation.js, so the [[edge_functions]] entry in netlify.toml was
redundant and could run the function twice per request.
* Update noir-projects/noir-contracts/contracts/standard/handshake_registry_contract/src/test.nr
Apply the suggestion from @nchamo
Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
* chore: update private kernel reset costs and add prettierignore
* chore: repin mock protocol circuit artifacts
* chore(bb): refresh pinned Chonk IVC inputs to a1a47cdde7622d32
Generated by ci-refresh-chonk.
Only the pinned Chonk input hash is committed here; the immediate follow-up CI run is skipped intentionally.
--ci-skip
---------
Co-authored-by: critesjosh <jc@joshcrites.com>
Co-authored-by: jeanmon <jean@aztec-labs.com>
Co-authored-by: PhilWindle <60546371+PhilWindle@users.noreply.github.com>
Co-authored-by: Alex <alexghr@users.noreply.github.com>
Co-authored-by: AztecBot <tech@aztecprotocol.com>
Co-authored-by: Aztec Bot <49558828+AztecBot@users.noreply.github.com>
Co-authored-by: Ilyas Ridhuan <ilyasridhuan@gmail.com>
Co-authored-by: Michael Connor <mike@aztec.foundation>
Co-authored-by: Maxim Vezenov <mvezenov@gmail.com>
Co-authored-by: AztecBot <tech@aztec-labs.com>
Co-authored-by: ludamad <adam.domurad@gmail.com>
Co-authored-by: Gregorio Juliana <gregojquiros@gmail.com>
Co-authored-by: Facundo <fcarreiro@users.noreply.github.com>
Co-authored-by: charlielye <5764343+charlielye@users.noreply.github.com>
Co-authored-by: ludamad <domuradical@gmail.com>
Co-authored-by: Randy Quaye <randyquaye@Randys-MacBook-Pro.local>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: randyquaye <69855400+randyquaye@users.noreply.github.com>
Co-authored-by: Jean M <132435771+jeanmon@users.noreply.github.com>
Co-authored-by: josh crites <critesjosh@gmail.com>
Co-authored-by: ciaranightingale <52419674+ciaranightingale@users.noreply.github.com>
Co-authored-by: ledwards2225 <l.edwards.d@gmail.com>
Co-authored-by: ledwards2225 <98505400+ledwards2225@users.noreply.github.com>
Co-authored-by: Nicolas Chamo <nicolas@chamo.com.ar>
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.
BEGIN_COMMIT_OVERRIDE
fix(p2p): stop checkpoint-replay storm when pruning to an uncheckpointed block (#23967)
refactor(sequencer)!: always enforce timetable with concrete block duration (#23821)
fix(e2e): drop removed enforceTimeTable option from optimistic proving test (#23976)
feat: persist peer bans for a configurable duration (A-1157) (#23922)
refactor!: rename node JSON-RPC to aztec_* prefixes (#23909)
fix(p2p): drive tx protection release from synced blocks instead of wall clock (#23978)
fix(p2p)!: resolve checkpoint tips from stored ids (#23968)
fix: deflake HA full e2e suite by switching to in-proc interval-mining anvil (#23979)
fix(gas)!: client fallback limits track network per-block budget (A-1154) (#23947)
feat: network-wide consensus config with validation and override protection (A-1168) (#23977)
test(e2e): pick bad slots upfront and warp to them in
proposer invalidates multiple checkpoints(#24017)fix(bot): check L1-to-L2 message readiness against PXE sync tip (#24004)
fix: Merge Conflicts (#24014)
END_COMMIT_OVERRIDE