Skip to content

fix: always include result member in JSON-RPC success responses - #24839

Closed
AztecBot wants to merge 986 commits into
merge-train/spartan-v5from
cb/jsonrpc-null-result
Closed

fix: always include result member in JSON-RPC success responses#24839
AztecBot wants to merge 986 commits into
merge-train/spartan-v5from
cb/jsonrpc-null-result

Conversation

@AztecBot

Copy link
Copy Markdown
Collaborator

Problem

Successful JSON-RPC responses whose handler returns undefined came back with neither a result nor an error member. For example aztec_getContract (which returns undefined when the contract is not found) produced:

{"jsonrpc":"2.0","id":"direct-aztec-getContract"}

The JSON-RPC 2.0 spec requires a successful response to always carry a result member. Some providers — dRPC in particular — reject responses that have neither result nor error, which broke calls proxied through them (they had to work around it by injecting result: null in a middle layer).

Root cause

In SafeJsonRpcServer.processRequest the success return was { jsonrpc, id, result }. When result is undefined, JSON.stringify drops the key entirely, so the serialized body loses result.

Fix

Coalesce an undefined handler return to null so the result key is always serialized:

return { jsonrpc, id, result: result ?? null };

?? null (not || null) is used so genuine falsy results — 0, false, "" — are preserved untouched; only undefined/null become null.

This is compatible with the existing client: safe_json_rpc_client already treats null and undefined results identically (returns undefined before schema parsing), so nothing downstream changes for handlers that legitimately return nothing.

Tests

  • Added a test asserting a handler returning undefined yields {"jsonrpc":"2.0","id":"…","result":null}.
  • Updated the existing single/batch clear-and-error cases that previously asserted the omitted-result behavior to expect result: null.

The change is a pure serialization path in @aztec/foundation. It was verified by reproducing the exact reported output before/after against the real jsonStringify implementation. The full jest suite was not run in this workspace: the monorepo install requires the generated noir/packages/* manifests from a noir/wasm bootstrap that isn't provisioned here.


Created by claudebox · group: slackbot · Slack thread

AztecBot and others added 30 commits July 1, 2026 18:43
BEGIN_COMMIT_OVERRIDE
chore(stdlib): remove dead code (#24423)
END_COMMIT_OVERRIDE
* fix 1: pin honk_key_gen Solidity VK emission to flavor entity count

Audit finding #1. The Solidity VK generator hand-wrote the precomputed-G1
emission list with no link to the flavor, so adding/removing a precomputed
entity would silently drift the generated on-chain VK out of sync with the
C++ layout. Drive the emission count from a (commitment, name) array and
static_assert it against the flavor's size(); add a test asserting the
generator emits exactly size() G1 points.

* fix 3: set beta_quartic in RelationParameters::compute_beta_powers

Audit finding #3. compute_beta_powers() set beta..beta_cube but left
beta_quartic at 0, so the test-only get_random() built
eccvm_set_permutation_delta with a zero domain-separation tag instead of the
production FIRST_TERM_TAG * beta^4. Set beta_quartic = beta_cube * beta so
test-infra parameters match the eccvm relation semantics.

* fix 4: reject wrong-size field input in VK deserialization

Audit finding #4. NativeVerificationKey_::from_field_elements and the
StdlibVerificationKey_ span constructor consumed only the fields they needed
and silently ignored trailing ones, so an oversize (malformed) VK deserialized
without error. Assert the input field count matches the VK layout exactly on
both paths so a malformed VK is rejected rather than masked.

* fix 6: add [[nodiscard]] to create_recursion_constraints

Audit finding #6. create_recursion_constraints returns the aggregated pairing
points and IPA claim the caller must deferred-accumulate to complete recursive
verification, but unlike its inner helper create_honk_recursion_constraints it
carried no [[nodiscard]] -- a caller could silently drop the result and skip
accumulation with no diagnostic. Add the attribute, matching the inner helper.

* fix 7: assert that hasZK and masking layout are consistent.

* fix: extend gemini-masking-layout assert to remaining ZK flavors

Finding #7's gemini_masking_layout_consistent<> static_assert was only on
Ultra/UltraZK/Mega/MegaZKFlavor. UltraKeccakZKFlavor, UltraZKRecursiveFlavor and
MegaZKRecursiveFlavor hand-declare both the masking flag and the AllValues layout,
so they can drift independently the same way -- MegaZKRecursiveFlavor most acutely,
since its HasGeminiMasking=false is decoupled from HasZK=true. Add the assert to
all three; all are currently consistent, so this is pure hardening.
…24440)

## Problem

The dedicated benchmark box pins `m6a.metal` (sole-tenant, to avoid
co-tenant memory-bandwidth variance). Metal capacity is thin, and
`create-fleet` can return `InsufficientInstanceCapacity` even on-demand.
The on-demand fallback in `aws_request_instance_type` tried **once** and
gave up, failing the bench run.

## Fix

Wrap the on-demand fallback in a time-budgeted retry loop, mirroring the
existing spot loop:
- `CI_ONDEMAND_TIMEOUT` (default **300s** = 5 min), `CI_ONDEMAND_POLL`
(default 20s).
- Retries the whole on-demand `create-fleet` until an instance is
acquired or the budget expires; logs the capacity error code per
attempt.
- Only reached when spot couldn't be had (unchanged), so normal
spot-first behavior is untouched.

## Verification

- Trigger a bench run (`ci.sh bench`) when metal capacity is tight;
confirm it now retries the on-demand request (logging
`InsufficientInstanceCapacity; retrying in 20s...`) rather than failing
immediately, and succeeds once capacity frees within 5 min.
chore: merge public-next into next (raw, conflict committed) [PR 1/2]
The interactions tracegen phase runs every lookup/permutation job via parallel_for (fill_trace_interactions). Lookups that share a destination-selector column can write the same (selector, row) cell from multiple threads, so the previous guarded read-modify-write (get(...) != 1 then set(...)) on that shared cell is a data race (undefined behavior).

Add an opt-in use_atomic_limbs flag to TraceContainer::set that stores the field's four limbs with relaxed atomic writes (4 plain movq on x86-64, no lock -- unlike a whole-field std::atomic_ref<FF>, whose 32 bytes exceed the lock-free width). Use it for the shared selector write and drop the guard read: the write is now an unconditional idempotent atomic store of 1. Because every writer stores the same value, per-limb atomicity is sufficient (no torn value is possible), and the hot non-atomic set() path is unchanged.
## What was wrong

The interactions tracegen phase runs every lookup/permutation job
concurrently: `AvmTraceGenHelper::fill_trace_interactions` concatenates
all builders' jobs and dispatches them with `parallel_for`. Lookups
whose fine-grained destination selector is a *shared* column
(`DST_SELECTOR != outer_dst_selector`) can resolve to the same `dst_row`
from different jobs, so multiple threads write the same `(selector,
row)` cell at once.

The previous code did a guarded read-modify-write on that shared cell:

```cpp
if (DST_SELECTOR != outer_dst_selector && trace.get(DST_SELECTOR, dst_row) != 1) {
    trace.set(DST_SELECTOR, dst_row, 1);
}
```

Both the `get` and the non-atomic 32-byte `set` race against the other
threads' writes to the same cell — a data race, i.e. undefined behavior.
In practice it produced the right value (every writer stores `1`), but
it is still UB.

## The fix

Add an opt-in `use_atomic_limbs` flag to `TraceContainer::set`. When
set, the field's four 64-bit limbs are written with **relaxed atomic
stores** — four plain `movq` on x86-64, no lock and no libatomic call.
(A whole-field `std::atomic_ref<FF>` is *not* an option on the hot path:
at 32 bytes it exceeds the hardware lock-free width and falls back to a
locked libatomic call.)

The shared selector write now uses it and drops the guard read:

```cpp
if (DST_SELECTOR != outer_dst_selector) {
    trace.set(DST_SELECTOR, dst_row, 1, /*use_atomic_limbs=*/true);
}
```

The write is an unconditional, idempotent atomic store of `1`. Because
every concurrent writer stores the *same* value, per-limb atomicity is
sufficient — no torn value is possible — so this is data-race-free
without the cost of whole-field atomicity. The default (non-atomic)
`set` hot path is untouched and keeps its sparse-column "zero = absent"
fast path.

## Performance (this PR vs baseline)

Mega bulk AVM tx, full proving, `HARDWARE_CONCURRENCY=16`. Tracegen
stage timings, median of runs (baseline n=3, this PR n=6):

| Stage | baseline (`next`) | this PR |
|---|---|---|
| tracegen traces | 1,536 ms | 1,537 ms |
| tracegen interactions | 350 ms | 329 ms |
| tracegen all | 1,917 ms | 1,936 ms |

No measurable cost — the safety fix is free. The per-limb atomic only
fires on the shared selector writes in the interactions stage; the
traces stage is byte-for-byte the same hot path as baseline.

Fixes
https://linear.app/aztec-labs/issue/AVM-276/interactions-tracegen-does-ub-write-to-destination-selector
BEGIN_COMMIT_OVERRIDE
chore: reduce parallelism for e2e check circuit (#24458)
END_COMMIT_OVERRIDE
…duces #24471) (#24472)

## What

Reproduces the changes in #24471 (originally opened from a fork) so it
runs under the org's CI/merge tooling. Corrects the testnet **Sponsored
FPC address** and the `v4.3.1` versioned getting-started page to the
live `5.0.0-rc.2` testnet values.

Two files, +5/−5 (identical to #24471 — resulting blob SHAs
`e7521e40cef` and `56c6a7445df` match):

- `docs/docs-developers/getting_started_on_testnet.md` —
`SPONSORED_FPC_ADDRESS` `0x261366…7880` →
`0x1969946536f0c09269e2c75e414eef4e21a76e763c5514125208db33d7d944d7`
-
`docs/developer_versioned_docs/version-v4.3.1/getting_started_on_testnet.md`
— install/warning version `4.3.1` → `5.0.0-rc.2`, `NODE_URL`
`https://rpc.testnet.aztec-labs.com` →
`https://v5.testnet.rpc.aztec-labs.com`, `SPONSORED_FPC_ADDRESS`
`0x08b888…f765b` → the same `0x1969…944d7`

## Validation

Verified against the **live rc.2 testnet**
(`https://v5.testnet.rpc.aztec-labs.com`, rollupVersion `2787991301`)
via `node_getContract`:

- `0x1969946536…944d7` → **deployed** (version 2, contractClassId
`0x095a9366d37ca82e92326aa9dea8c917d9a9c859ebdf6a116299c5a9e5f7ef3c`) —
the real Sponsored FPC ✅
- `0x261366…7880` → **null** (not deployed) — the wrong value previously
on `next`
- `0x08b888…f765b` → **null** (not deployed) — the older wrong value in
the versioned page

## Notes

- Supersedes fork PR #24471 — that one can be closed in favor of this.
- The same wrong FPC (`0x2613…`) is also present on `v5-next`'s
`getting_started_on_testnet.md`; a matching correction there is a
separate small PR (not included here).

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/59cd7d98b38b9d90) ·
group: `slackbot`*
A malicious proposer could store header or archive field values >= the BN254
scalar field modulus on L1. Off-chain archivers decode those storage slots into
Fr elements, so an out-of-range value bricks honest archivers' L1 sync.

Reject such values at propose time:
- validateHeader: blockHeadersHash, outHash, feeRecipient, accumulatedFees
- propose: the new checkpoint archive root

Other header fields are already safe (equality-checked against field-reduced
on-chain values, or type-bounded), so they are left unchecked.

This is the L1 half of A-1254; the archiver-side defense-in-depth is a separate
follow-up PR.

(cherry picked from commit 310c8ac)
…ield

run_rollup_upgrade.sh deploys with a random GENESIS_ARCHIVE_ROOT. The rollup now
rejects a genesis archive root >= the BN254 scalar field modulus
(Rollup__FieldElementOutOfRange), so a full 32-byte random value fails ~81% of the
time. Generate 31 random bytes with a zero top byte so the value is always a valid
field element.

(cherry picked from commit f6077f4)
feat: reject out-of-range checkpoint header fields at propose (port of #24199 to next)
feat(avm)!: Reduce maximum number of AVM operands
- read window fee stats from a single eth_feeHistory call (percentiles
  [0, 75]) plus header-only walks, instead of downloading every tx in the
  window; drop the two per-tx blob fields feeHistory cannot provide
- carry bigints end-to-end in FailedL1Tx: serialize with jsonStringify
  (identical bytes on disk) and parse back via a zod schema, removing the
  string-mapping layers at every write site
- always retain the gas-price ladder; remove the captureGasPriceHistory flag
- capture the fee environment and log it at warn on failure even when no
  failed-tx store is configured
- guard fee capture so an error cannot drop the record, remove the stale
  wait-for-next-block jsdoc, and collapse getBlockNumber fallbacks to
  .catch(() => 0n)
Add verification after proof generation in bbapi_ultrahonk
AztecBot and others added 25 commits July 17, 2026 15:06
…, refresh networks.md, deprecate v5.0.0/v4.3.1

# v5.0.1 docs release (Alpha + Testnet unified)

Runs the `/release-docs` workflow for the `v5.0.1` tag, using `https://v5.testnet.rpc.aztec-labs.com` as the network source of truth, per the request in #ecosystem.

## Versioning

- **Developer and network/operator docs** both cut at `v5.0.1`, with **both `mainnet` and `testnet` release channels pointing at it** (single "Alpha / Testnet (v5.0.1)" version in the dropdown, same as the v4.3.x unified precedent). Cut with `RELEASE_TYPE=mainnet` per that precedent.
- **Deprecated/removed**: `version-v5.0.0` (old testnet) and `version-v4.3.1` (old Alpha v4) developer + network snapshots and sidebars.
- The network snapshot is cut from `next`'s `docs-operate` source so the new **role-based operator documentation** (68c0042, which describes v5 as current) ships with this release instead of waiting for the next cut. Its macros are resolved at v5.0.1.

## networks.md

**Testnet column** (from live RPC + on-chain `cast` queries against the new rollup, all matching what was already on `next` post-rollup-upgrade): version → `5.0.1`; v5.0.1-canonical MultiCall Entrypoint and SponsoredFPC (below).

**Alpha (Mainnet) column** — version → `5.0.1`, RPC kept at dRPC per request. The mainnet Registry (`0x35b22e09…`) now has rollup **version 3 = `4248094967`** registered and canonical — the v5 deployment — so all per-rollup addresses were resolved on-chain from it (Rollup `0x91ff8bbd…`, Inbox, Outbox, Fee Juice Portal, Slasher, Tally Slashing Proposer, Slash Payload Cloneable, Honk Verifier, Reward Distributor, Reward Booster). Governance-level contracts (Registry, Governance, Governance Proposer, GSE, Fee Juice, Staking Asset, Coin Issuer) verified unchanged on-chain. L2 protocol addresses updated to the v5 layout (Class Registry `0x01`, Instance Registry `0x02`, Fee Juice `0x03`).

**Governance table**: slashing rows updated from on-chain values of both new Tally Slashing Proposers (quorum 65/128, round 4 epochs = 128 slots on both networks). Release-channel examples refreshed from 4.x to 5.x.

## L2 canonical addresses (derived with v5.0.1 tooling, cross-checked on a live v5.0.1 local network)

- **SponsoredFPC**: `0x1441491b59934ec64f8c98f17c91f23c01ca2a45dbb35caf123146ec76f9970c` (changed from 5.0.0's `0x0628…` — the aztec-nr partial-note fix in this patch changed the artifact). Applied to `networks.md` and `getting_started_on_testnet.md` (source + snapshot).
- **MultiCall Entrypoint**: `0x246d60af8b79a5dceece7d2388921203401c0df02ce674c5781c6c2162922986` (changed from 5.0.0 — pinned standard contracts were regenerated in this patch).

## Generated references (all regenerated at the tag)

- Aztec.nr + TypeScript API docs into **both** `static/*-api/mainnet` and `static/*-api/testnet` (both networks now run v5.0.1).
- `aztec`, `aztec-wallet`, `aztec-up` CLI references (via the release wrapper, so `init`/`new`/`test` are included; wallet usage lines now correctly read `aztec-wallet`).
- Node JSON-RPC API reference (65 methods) and the operator `aztec start --help` CLI reference.

## Migration notes

Source file restructured to match what shipped: new `## 5.0.1` section (history-note nullification helper rename, `set_as_fee_payer` setup-phase assert, PXE per-`(l1ChainId, rollupAddress, schemaVersion)` stores), and the published v5.0.0 snapshot's `## 5.0.0` section adopted verbatim (the prior release had only moved TBD→5.0.0 in the snapshot, not the source).

## Reconciliation with `next` (skill step 12)

Ported into the v5.0.1 snapshot: fees.md Fee Juice bridging section (predates the 5.0.0 cut but was missed by it), counter-tutorial scaffold-test note, `typescript@^5.3.3` pin, `@aztec/viem@2.38.2` in the token-bridge install line. Fixed stale `MessageDelivery` API-reference links in source + snapshot. Skipped next-side changes not valid at v5.0.1 (e.g. removal of the `generated/default.json` step, which is only obsolete after #24434). Tag-newer content (initializerless accounts, key-derivation docs) is kept in the snapshot and left untouched in `next`'s source.

## Validation

- `yarn build` passes on this branch: 0 broken redirect targets, 0 broken API-ref links, 0 spellcheck issues. (Known non-fatal `valkeys` anchor warning remains, plus pre-existing docker-compose anchor warnings from the operator restructure source.)
- Functional smoke test on a **v5.0.1 local network built from the tag**: sponsored-FPC registration at salt 0, `create-account` with `fpc-sponsored` payment, `TokenContract` deploy, `mint_to_public` (revertCode 0), `simulate balance_of_public` → `100n`, exactly as the getting-started guide documents. The node also registered MultiCall at `0x246d60af…`, confirming the networks.md value.

## Follow-ups for the release operators

1. **The new testnet SponsoredFPC (`0x1441…`) must be deployed and funded on testnet** when the network upgrades to 5.0.1 — the currently funded FPC is 5.0.0's `0x0628…`.
2. The dRPC Alpha endpoint currently still serves the old rollup (nodeVersion 4.4.0); the Alpha column describes the new canonical v5 rollup, which nodes will follow after upgrading.
3. Mainnet **Staking Registry** kept at the v4 value `0x042dF8f4…` (no on-chain getter; bytecode verified still present) — please confirm it carries over to the v5 deployment.

---
*Created by [claudebox](https://claudebox.work/v2/sessions/08b04eb0669bcfbb/jobs/1) · group: `slackbot` · [Slack thread](https://aztecfoundation.slack.com/archives/C0B24G1GFGB/p1784247618790429?thread_ts=1784247618.790429&cid=C0B24G1GFGB)*
…, refresh networks.md, deprecate v5.0.0/v4.3.1 (#24763)

# v5.0.1 docs release (Alpha + Testnet unified)

Runs the `/release-docs` workflow for the `v5.0.1` tag, using
`https://v5.testnet.rpc.aztec-labs.com` as the network source of truth,
per the request in #ecosystem.

## Versioning

- **Developer and network/operator docs** both cut at `v5.0.1`, with
**both `mainnet` and `testnet` release channels pointing at it** (single
"Alpha / Testnet (v5.0.1)" version in the dropdown, same as the v4.3.x
unified precedent). Cut with `RELEASE_TYPE=mainnet` per that precedent.
- **Deprecated/removed**: `version-v5.0.0` (old testnet) and
`version-v4.3.1` (old Alpha v4) developer + network snapshots and
sidebars.
- The network snapshot is cut from `next`'s `docs-operate` source so the
new **role-based operator documentation** (68c0042, which describes
v5 as current) ships with this release instead of waiting for the next
cut. Its macros are resolved at v5.0.1.

## networks.md

**Testnet column** (from live RPC + on-chain `cast` queries against the
new rollup, all matching what was already on `next`
post-rollup-upgrade): version → `5.0.1`; v5.0.1-canonical MultiCall
Entrypoint and SponsoredFPC (below).

**Alpha (Mainnet) column** — version → `5.0.1`, RPC kept at dRPC per
request. The mainnet Registry (`0x35b22e09…`) now has rollup **version 3
= `4248094967`** registered and canonical — the v5 deployment — so all
per-rollup addresses were resolved on-chain from it (Rollup
`0x91ff8bbd…`, Inbox, Outbox, Fee Juice Portal, Slasher, Tally Slashing
Proposer, Slash Payload Cloneable, Honk Verifier, Reward Distributor,
Reward Booster). Governance-level contracts (Registry, Governance,
Governance Proposer, GSE, Fee Juice, Staking Asset, Coin Issuer)
verified unchanged on-chain. L2 protocol addresses updated to the v5
layout (Class Registry `0x01`, Instance Registry `0x02`, Fee Juice
`0x03`).

**Governance table**: slashing rows updated from on-chain values of both
new Tally Slashing Proposers (quorum 65/128, round 4 epochs = 128 slots
on both networks). Release-channel examples refreshed from 4.x to 5.x.

## L2 canonical addresses (derived with v5.0.1 tooling, cross-checked on
a live v5.0.1 local network)

- **SponsoredFPC**:
`0x1441491b59934ec64f8c98f17c91f23c01ca2a45dbb35caf123146ec76f9970c`
(changed from 5.0.0's `0x0628…` — the aztec-nr partial-note fix in this
patch changed the artifact). Applied to `networks.md` and
`getting_started_on_testnet.md` (source + snapshot).
- **MultiCall Entrypoint**:
`0x246d60af8b79a5dceece7d2388921203401c0df02ce674c5781c6c2162922986`
(changed from 5.0.0 — pinned standard contracts were regenerated in this
patch).

## Generated references (all regenerated at the tag)

- Aztec.nr + TypeScript API docs into **both** `static/*-api/mainnet`
and `static/*-api/testnet` (both networks now run v5.0.1).
- `aztec`, `aztec-wallet`, `aztec-up` CLI references (via the release
wrapper, so `init`/`new`/`test` are included; wallet usage lines now
correctly read `aztec-wallet`).
- Node JSON-RPC API reference (65 methods) and the operator `aztec start
--help` CLI reference.

## Migration notes

Source file restructured to match what shipped: new `## 5.0.1` section
(history-note nullification helper rename, `set_as_fee_payer`
setup-phase assert, PXE per-`(l1ChainId, rollupAddress, schemaVersion)`
stores), and the published v5.0.0 snapshot's `## 5.0.0` section adopted
verbatim (the prior release had only moved TBD→5.0.0 in the snapshot,
not the source).

## Reconciliation with `next` (skill step 12)

Ported into the v5.0.1 snapshot: fees.md Fee Juice bridging section
(predates the 5.0.0 cut but was missed by it), counter-tutorial
scaffold-test note, `typescript@^5.3.3` pin, `@aztec/viem@2.38.2` in the
token-bridge install line. Fixed stale `MessageDelivery` API-reference
links in source + snapshot. Skipped next-side changes not valid at
v5.0.1 (e.g. removal of the `generated/default.json` step, which is only
obsolete after #24434). Tag-newer content (initializerless accounts,
key-derivation docs) is kept in the snapshot and left untouched in
`next`'s source.

## Validation

- `yarn build` passes on this branch: 0 broken redirect targets, 0
broken API-ref links, 0 spellcheck issues. (Known non-fatal `valkeys`
anchor warning remains, plus pre-existing docker-compose anchor warnings
from the operator restructure source.)
- Functional smoke test on a **v5.0.1 local network built from the
tag**: sponsored-FPC registration at salt 0, `create-account` with
`fpc-sponsored` payment, `TokenContract` deploy, `mint_to_public`
(revertCode 0), `simulate balance_of_public` → `100n`, exactly as the
getting-started guide documents. The node also registered MultiCall at
`0x246d60af…`, confirming the networks.md value.

## Follow-ups for the release operators

1. **The new testnet SponsoredFPC (`0x1441…`) must be deployed and
funded on testnet** when the network upgrades to 5.0.1 — the currently
funded FPC is 5.0.0's `0x0628…`.
2. The dRPC Alpha endpoint currently still serves the old rollup
(nodeVersion 4.4.0); the Alpha column describes the new canonical v5
rollup, which nodes will follow after upgrading.
3. Mainnet **Staking Registry** kept at the v4 value `0x042dF8f4…` (no
on-chain getter; bytecode verified still present) — please confirm it
carries over to the v5 deployment.

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/08b04eb0669bcfbb/jobs/1)
· group: `slackbot` · [Slack
thread](https://aztecfoundation.slack.com/archives/C0B24G1GFGB/p1784247618790429?thread_ts=1784247618.790429&cid=C0B24G1GFGB)*
…es of truth (#24770)

Generalizes the verification lessons from the v5.0.1 docs release
(#24763) — specifically from cross-checking the machine-derived
`networks.md` values against the hand-written ones in #24756 — into the
`/release-docs` and `/release-network-docs` skills, so every future
release re-checks all of it against sources of truth instead of trusting
carried-forward or hand-transcribed values.

The two discrepancies that cross-check caught, which motivate the rules:

- The mainnet rollup version was hand-converted from `0xfd39c8f7` and
shipped wrong (`4248094967` instead of `4248422647`).
- The Alpha Execution Delay was carried forward as 30 days when the live
`Governance.getConfiguration()` says 2 days — the governance table had
no re-verification step at all.

## What the skills now require, every release

A new **"Re-verify every figure against its source of truth"**
subsection in `/release-docs` Step 9 (referenced from
`/release-network-docs` Step 4), plus a Key Point:

- **EIP-55 checksums**: every L1 address goes through `cast
to-check-sum-address` before landing in the tables.
- **Decimal conversions**: on-chain hex is converted with `cast to-dec`,
never by eye.
- **Rollup version**: read from each network's rollup via `getVersion()`
and cross-checked against the RPC's `rollupVersion`; in the pre-release
flow the target rollup's on-chain value wins.
- **L1 chain id**: `cast chain-id` must agree with the docs row and the
node RPC's `l1ChainId`.
- **Governance parameters table** (previously never mentioned by the
skills): queried on-chain for both columns — Proposer Quorum from the
Governance Proposer (`QUORUM_SIZE`/`ROUND_SIZE`), Voting/Execution
delays from `Governance.getConfiguration()` decoded against the tag's
`IGovernance` struct (with a warning about the 256-second compressed
time fields), Slashing Quorum/Round Size from the Tally Slashing
Proposer (`QUORUM`, `ROUND_SIZE`, `ROUND_SIZE_IN_EPOCHS`).
- **Cross-check human-owned data**: when the network team has a parallel
deployment update in flight, diff every value against it and resolve
discrepancies by querying the chain, then reconcile with the owner
before shipping.

Stacked on #24763 (which already added the `cast to-dec` note and the
migration-notes TBD rule); once that merges this PR retargets to `next`
and carries only these two skill files.

---
*Created by
[claudebox](https://claudebox.work/v2/sessions/08b04eb0669bcfbb/jobs/4)
· group: `slackbot` · [Slack
thread](https://aztecfoundation.slack.com/archives/C0B24G1GFGB/p1784247618790429?thread_ts=1784247618.790429&cid=C0B24G1GFGB)*
Adds `client9` (`mainnet-rpc-consumer-client9`) to the mainnet RPC
consumers, following #24693 (client8).

The GCP Secret Manager secret is already created and this has been
`terraform apply`-ed to the mainnet environment — the plan was exactly
the two expected resources (KongConsumer + ExternalSecret) and is now
live. Rate limit 0 = unlimited, matching the other consumers.
The mainnet SLASH_GRACE_PERIOD_L2_SLOTS default was raised from 1200 to
8400 slots in #21451, but that commit landed directly on the v4 release
branch and never reached next. v5 therefore inherited the old 1200 slot
(24h at a 72s slot) value.

Restore 8400 slots (7 days) and update the operator docs to match.
## Summary

Restores the mainnet `SLASH_GRACE_PERIOD_L2_SLOTS` default from `1200`
to `8400` slots in `spartan/environments/network-defaults.yml`.

At the mainnet `AZTEC_SLOT_DURATION` of 72s:
- `1200 × 72s = 86,400s` = **exactly 24 hours** (the value v5 shipped
with)
- `8400 × 72s = 604,800s` = **exactly 7 days** (the intended value)

## Why

This value was already raised to 8400 in #21451 ("tune mainnet slasher
penalties and sequencer allocation"), but that commit landed directly on
the v4 release branch and never made it onto `next`. `v5` therefore
inherited the stale 1200 from `next`.

Confirmed by diffing the branches:

| branch | mainnet grace | at 72s slot |
| --- | --- | --- |
| `v4-next` | 8400 | 7 days |
| `next` / `v5-next` / `merge-train/spartan` | 1200 | 24 hours |

## Scope notes

- **Only the `networks.mainnet` preset is changed.** The top-level
`slasher` anchor (`0`) and the `devnet` preset (`0`) are unchanged.
- **`testnet` (64 slots) is deliberately left alone.** `v4-next` has
3600 there, but that value traces back to the original `refactor:
centralize network defaults in YAML` commit on the `next` line rather
than to the lost #21451 change — so it is a separate long-standing
divergence, not part of this regression. Worth a follow-up decision, but
out of scope here.
- No generated files are committed:
`yarn-project/slasher/src/generated/` and the CLI network presets are
gitignored and produced at build time from this YAML.
- Operator docs updated to match (8,400 slots / ~7 days). The
`network_versioned_docs/version-v5.0.1` snapshot is intentionally left
untouched, since it documents what v5.0.1 actually shipped.

## Caveat

This changes a **baked-in default for future builds/deployments**. It
does not retroactively alter the grace period on the already-running v5
network — nodes there need `SLASH_GRACE_PERIOD_L2_SLOTS` set explicitly
or a redeploy.

## Test plan

- [x] YAML parses; mainnet resolves to exactly 7.00 days at a 72s slot
- [x] No test or `spartan/environments/*.env` file pins the old `1200`
value


---
*Created by
[claudebox](https://claudebox.work/v2/sessions/849a625af4f2c309/jobs/1)
· group: `slackbot` · [Slack
thread](https://aztecprotocol.slack.com/archives/C0AU8BULZHC/p1784543473010009?thread_ts=1784543473.010009&cid=C0AU8BULZHC)*
## What

Restores a **public v6 nightly** and repoints the nightly consumers (next-net deploy, spartan benches, ci3 scenario tests) at it. Also fixes the bench-inclusion-sweep validation error.

## Why

After `next` bumped to 6.0.0 and `v5-next` split off (release-machinery port, `7ac407c909`), the public repo:
- narrowed nightly **tagging** to `v5-next` only → no public `6.0.0-nightly` image was ever built (`aztecprotocol/aztec:6.0.0-nightly.*` = 404), and
- gated every **consumer** (next-net, spartan benches, ci3 `ci-network-scenario`) to `aztec-packages-private` + the internal registry.

Net effect: from the public side, nightly deploys/tests/benches looked stopped. The public repo still published `v5.0.0-nightly` daily, but nothing public produced or consumed a v6 nightly.

## Changes

- **`nightly-release-tag.yml`** — public repo now tags `next` (v6) as well as `v5-next`. The tag push runs `ci-release`, which publishes `aztecprotocol/aztec:6.0.0-nightly` (the public `release` path has no v5 gate).
- **`deploy-next-net.yml`** — public-gated; derives the version from `next`'s manifest; `wait-for-ci3` blocks on the release build; deploys the public image (dropped `use_internal_docker_registry`).
- **`nightly-spartan-bench.yml`** — private→public gates; checks out `next`; public registry; added a `wait-for-ci3` gate so the three deploy tracks don't race the release build (replaces the point-in-time image-existence check).
- **`ci3.yml`** (`ci-network-scenario`) — gate flipped to `aztec-packages` and `v6.`, so nightly scenario tests run in the public repo on the v6 tag (runs inside the tag's ci3 run, gated on the release job).
- **delete `nightly-release-tag-v5-next.yml`** — redundant now that the matrix tags `v5-next` in the public repo.
- **`nightly-bench-inclusion-sweep.yml`** — pass `skip_notify_on_failure: true` (the renamed `deploy-network` input) instead of the removed `notify_on_failure`, fixing the "Invalid input" workflow error.

## Notes / side effects

- v6 nightly now publishes publicly to **DockerHub _and_ npmjs/crates.io** (same as v5 today) — inherent to publishing a public v6 nightly.
- `weekly-proving-bench.yml` needs no change — it already targets `next`+public, so it starts working once the v6 image publishes.
- Scenario tests now run on **v6 only**; v5 is still deployed via `deploy-staging-*` but no longer scenario-tested nightly.
- Worth confirming the public repo's `GCP_SA_KEY` can deploy next-net to `CLUSTER=aztec-gke-private` (staging-public deploys fine from public creds).

Co-authored-by: Phil Windle <philip.windle@gmail.com>
#24727)

## What

Restores a **public v6 nightly** and repoints the nightly consumers
(next-net deploy, spartan benches, ci3 scenario tests) at it. Also fixes
the bench-inclusion-sweep validation error.

## Why

After `next` bumped to 6.0.0 and `v5-next` split off (release-machinery
port, `7ac407c909`), the public repo:
- narrowed nightly **tagging** to `v5-next` only → no public
`6.0.0-nightly` image was ever built
(`aztecprotocol/aztec:6.0.0-nightly.*` = 404), and
- gated every **consumer** (next-net, spartan benches, ci3
`ci-network-scenario`) to `aztec-packages-private` + the internal
registry.

Net effect: from the public side, nightly deploys/tests/benches looked
stopped. The public repo still published `v5.0.0-nightly` daily, but
nothing public produced or consumed a v6 nightly.

## Changes

- **`nightly-release-tag.yml`** — public repo now tags `next` (v6) as
well as `v5-next`. The tag push runs `ci-release`, which publishes
`aztecprotocol/aztec:6.0.0-nightly` (the public `release` path has no v5
gate).
- **`deploy-next-net.yml`** — public-gated; derives the version from
`next`'s manifest; `wait-for-ci3` blocks on the release build; deploys
the public image (dropped `use_internal_docker_registry`).
- **`nightly-spartan-bench.yml`** — private→public gates; checks out
`next`; public registry; added a `wait-for-ci3` gate so the three deploy
tracks don't race the release build (replaces the point-in-time
image-existence check).
- **`ci3.yml`** (`ci-network-scenario`) — gate flipped to
`aztec-packages` and `v6.`, so nightly scenario tests run in the public
repo on the v6 tag (runs inside the tag's ci3 run, gated on the release
job).
- **delete `nightly-release-tag-v5-next.yml`** — redundant now that the
matrix tags `v5-next` in the public repo.
- **`nightly-bench-inclusion-sweep.yml`** — pass
`skip_notify_on_failure: true` (the renamed `deploy-network` input)
instead of the removed `notify_on_failure`, fixing the "Invalid input"
workflow error.

## Notes / side effects

- v6 nightly now publishes publicly to **DockerHub _and_
npmjs/crates.io** (same as v5 today) — inherent to publishing a public
v6 nightly.
- `weekly-proving-bench.yml` needs no change — it already targets
`next`+public, so it starts working once the v6 image publishes.
- Scenario tests now run on **v6 only**; v5 is still deployed via
`deploy-staging-*` but no longer scenario-tested nightly.
- Worth confirming the public repo's `GCP_SA_KEY` can deploy next-net to
`CLUSTER=aztec-gke-private` (staging-public deploys fine from public
creds).
BEGIN_COMMIT_OVERRIDE
chore(spartan): restore 7 day mainnet slash grace period (#24804)
END_COMMIT_OVERRIDE
## Summary

Adds a generic **`port-to-next`** label — the mirror image of the
existing `backport-to-*` labels, but with a single fixed target.

When a merged PR carries `port-to-next`, its merge commit is
cherry-picked onto an accumulating `port-to-next-staging` branch, which
opens/updates one PR directly into `next`. This gives us a one-click way
to forward-port a fix landed on a release line into `next`.

## How it works

Reuses the existing backport machinery rather than building a parallel
system:

- **`scripts/backport_to_staging.sh`** — honours optional
`STAGING_BRANCH` / `STAGING_PR_TITLE` / `STAGING_PR_LABELS` env
overrides; defaults preserve today's `backport-to-*` behaviour, so the
`/backport` skill and manual callers are unaffected. Labels are applied
on both PR creation and a pre-existing staging PR.
- **`.github/workflows/backport.yml`** — the label check now matches
`backport-to-,port-to-next`. A resolve step maps the label family to
`(target, staging branch, PR title, labels, verb)`: `port-to-next` →
target `next`, staging `port-to-next-staging`, labels `ci-no-squash`.
`port-to-next` takes precedence if both families are present.
Success/failure comments and the Slack + ClaudeBox conflict dispatch use
the resolved values.
- **`merge-train-update-pr-body.yml`** — `port-to-next-staging` added to
the push triggers so the PR body's commit list stays current.
- **`merge-train-auto-merge.yml`** — a new `BRANCH_PATTERN=port-to-next`
(8h inactivity) auto-merge job, matching the backport-train job.
- **`.claude/claudebox/backport.md`** + **merge-train-infra skill** —
document the port variant.

The `port-to-next` GitHub label has been created on the repo.

## Daily forward-port sweep

In addition to the per-PR label, a scheduled job keeps `next` fed with
everything on the `v5-next` release line:

- **`.github/workflows/port-v5-next-to-next.yml`** — runs daily at 06:30
UTC (and on `workflow_dispatch`, with an optional `source_branch`
input).
- **`scripts/port_to_next.sh`** — checks out the long-lived
`port-v5-next-to-next` branch, merges both `next` and `v5-next` into it,
and — if that produces a delta — opens/updates one `ci-no-squash` PR
into `next`.

The branch is long-lived and accumulating, so any conflict resolution
pushed to it is preserved across runs (fast-forward push). Once the PR
is merged (the branch becomes an ancestor of `next`), the next run
rebuilds it fresh from `next` with a `--force-with-lease` push; a run
with no delta over `next` closes the stale PR.

On a **merge conflict** the run does not bail: it commits the conflicted
merge (markers included) so the PR is still opened/updated as a
resolution target, and posts the PR link + conflicted files to
`#backports`. Resolve by checking out the port branch, fixing the
markers, and pushing. This PR is intentionally **not** auto-merged — it
is left for human review.

## Notes

- The staging PR targets `next`, which enforces squashed PRs, so it
carries `ci-no-squash` to allow the accumulated commits through
`squashed-pr-check.yml`.
- Tradeoff (shared with the backport staging branches): ports accumulate
into one staging PR, so a single conflicting port can hold up the batch
until resolved.

## Testing

Label-resolution logic exercised locally for all cases (port-only,
backport, precedence, no-match); the `CREATE_ARGS` label plumbing,
script syntax (`bash -n`), verb capitalisation, and YAML validity all
checked.
BEGIN_COMMIT_OVERRIDE
feat: add port-to-next label for forward-porting merged PRs (#24753)
END_COMMIT_OVERRIDE
@AztecBot AztecBot added ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR. labels Jul 21, 2026
@spalladino

Copy link
Copy Markdown
Contributor

Closing in favor of #24840

@spalladino spalladino closed this Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-draft Run CI on draft PRs. ci-no-fail-fast Sets NO_FAIL_FAST in the CI so the run is not aborted on the first failure claudebox Owned by claudebox. it can push to this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.