chore(release): merge v5-next into v5 for v5.1.0 - #24897
Merged
Merged
Conversation
Managed to corrupt my DB 🤷
BEGIN_COMMIT_OVERRIDE fix: handle corruption errors (#24739) END_COMMIT_OVERRIDE
…l validation (#24694) ## Problem On a live mainnet node, checkpoint-proposal validation could throw an uncaught error out of the gossipsub message handler whenever it ran while the world-state synchronizer trailed the archiver (block source) by a block: ``` ERROR world-state:database Call CREATE_FORK failed: Error: Unable to initialize from future block: 117860 unfinalizedBlockHeight: 117859. Tree name: NullifierTree ERROR p2p:libp2p_service Error handling gossipsub message: Error: Unable to initialize from future block: 117860 unfinalizedBlockHeight: 117859. Tree name: NullifierTree ``` The archiver already had block N (so the block lookups inside checkpoint validation succeeded), but world state's `unfinalizedBlockHeight` was still N-1. When `validateCheckpointProposal` forked world state at the parent block before it had been applied, the raw tree error escaped as an uncaught ERROR-level gossipsub message. The node lost that checkpoint validation/attestation for the round and spammed error logs; it self-healed the next tick, but it should not happen. ## Root cause The two world-state fork sites were asymmetric. The block re-execution path (`reexecuteTransactions`) syncs world state *before* forking. The checkpoint validation path (`validateCheckpointProposal`) forked via `checkpointsBuilder.getFork` *without* a preceding sync. The checkpoint path does sync the block source (archiver) earlier, but that does not advance the world state, so the gap remained. ## Fix - Move the sync-before-fork invariant into `FullNodeCheckpointsBuilder.getFork`: it now calls `worldState.syncImmediate(blockNumber, blockHash)` before `worldState.fork(blockNumber)`, so the single fork helper owns the invariant rather than each caller. `syncImmediate` blocks until world state reaches the block, or throws a typed error if it genuinely cannot, instead of leaking the raw tree error. - In `validateCheckpointProposal`, look up the parent block's hash from the block source and pass it through so the sync re-syncs on a world-state reorg. Wrap the fork in a try/catch that maps any failure to a clean, non-slashable `world_state_not_synced` result, so a sync/fork failure never surfaces as an uncaught ERROR-level gossipsub message. - As a second, independent guard, check that the forked world state's archive root matches the proposal's `lastArchiveRoot` before rebuilding the checkpoint. A mismatch means world state forked from a different chain than the proposal was built on, so we fail fast with a clean, non-slashable `initial_archive_mismatch` result — mirroring the block-proposal re-execution check — instead of a confusing downstream header/archive mismatch. Both new reasons record an `unvalidated` outcome and are non-slashable, matching the other "we couldn't validate right now" / local-state-divergence reasons. Other checkpoint-builder fork sites were reviewed and need no change: the proposer's `checkpoint_proposal_job` forks at its own already-synced, coherence-checked world-state tip, and the block-proposal re-execution path already syncs before forking and performs the equivalent archive-root check. ## Tests - `checkpoint_builder.test.ts`: `getFork` syncs world state to the block before forking, and propagates a sync failure without forking. - `proposal_handler.test.ts`: forks at the parent block number passing its block hash; a fork failure returns `world_state_not_synced`; and a fork whose archive root diverges from the proposal returns `initial_archive_mismatch`. ## Notes The same bug exists on the v4 line — the v4 site is the same function, forking via `this.worldState.fork(parentBlockNumber)` directly without a preceding `syncImmediate`. This fix should be ported there as well. Fixes A-1421
The `docs/examples/bootstrap.sh execute` step is failing CI. The example runner does an unpinned `yarn add -D typescript tsx`, and `typescript@latest` on npm is now `7.0.2` (the native port). Its package layout has no `lib/_tsc.js`, so Yarn 4's builtin compat patch fails to apply: ``` Error: typescript@patch:...npm%3A7.0.2...: ENOENT: no such file or directory, lstat '.../lib/_tsc.js' ``` Pin the install to `typescript@^5.3.3` — the same line the rest of the monorepo uses (resolves to 5.9.3) and matching the existing pin in `docs/examples/ts/bootstrap.sh`. Verified with Yarn 4.13.0: the unpinned add reproduces the `_tsc.js` error, the pinned add applies the compat patch cleanly.
BEGIN_COMMIT_OVERRIDE fix(validator): sync world state before forking in checkpoint proposal validation (#24694) END_COMMIT_OVERRIDE
Prevents multi-tab concurrency issues in SQLite store creation by guarding it with weblocks. Closes F-829
This is a defensive measure in case more than one SQLite page file is found pointing to the same logical name, which could cause undefined behavior. This could happen with old, pre-weblock controlled versions of wallet/pxe (see #24740), so it's unlikely to be found in the wild, but it gives us graceful coverage if that happens. We detect if a pool contains two valid .opaque files mapped to the same logical SQLite path, then: 1. Acquire the pool Web Lock. 2. Copy the entire pool byte-for-byte into: .aztec-sqlite-quarantine/<timestamp-random>/ 3. Verify the copied directory and file contents. 4. Write a quarantine.json describing the duplicate mappings. 5. Delete the original active pool. 6. Open a new, empty database under the original pool name. 7. Emit a warning log containing the quarantine location. The caller receives a successfully opened but empty store, so wallet/PXE state would need to be recreated or resynchronized. The quarantined bytes remain available for forensic or manual recovery, although there is currently no public API or UI for that. If copying or verification fails, opening fails and the original pool is not intentionally removed. If the pool merely comes from an old version but has no duplicate logical mappings, nothing special happens, it opens normally. --------- Co-authored-by: Gregorio Juliana <gregojquiros@gmail.com>
#24689) ## Motivation The `#[note]` macro generated each `PropertySelector` from the field's position in the struct declaration, but selectors are applied to the note's packed representation. The two only agree when every field packs to one `Field`. For a note with a multi-slot field (a `Point`, an array, a nested struct), every filter on a later field silently constrained an unrelated packed slot — on the constrained read path, where these checks are what bind oracle-returned notes to the contract's criteria. A malicious PXE could satisfy a filter with a note that does not match it. No shipped contract is affected (all first-party filters target single-slot fields with single-slot predecessors); the bug was latent in the library. ## The change - Selector indices are the field's packed offset: the accumulated sum of preceding fields' `Packable::N`, mirroring `derive(Packable)`'s layout. - `PropertySelector<T>` carries the selected field's type. `select`/`sort` reject fields that pack to more than one `Field` at compile time (a one-slot criterion cannot express them), and `select`'s value is typed as the field's type. - Criterion values are compared as `value.pack()[0]` instead of `value.to_field()`, matching what the packed note slot actually contains. - `properties()` statically asserts the note's packed length equals the sum of its field packed lengths, so custom `Packable` layouts get a compile error directing to hand-written selectors instead of wrong ones. A same-length field reorder is not detectable; that residual gap is documented. - Breaking: hand-written `PropertySelector` literals need a type annotation, and every note field type must implement `Packable`. Migration notes included. All existing contracts compile to identical circuits; the PXE already applied indices to the packed layout, so no TS changes. ## Future changes The root cause is that two independent authorities describe the same layout: the note's `Packable` impl owns it, and the macro assumes it. Every assertion in this PR is a consistency check between the two, and one divergence (a custom pack that reorders fields at the same total length) cannot be checked at all and still fails silently. A potential fix (maybe there is a better one) is for the note macro to own the layout: `#[note]` derives `Packable` itself and generates the selectors from the same field list, making divergence impossible by construction, with an explicit custom-packing opt-out that generates neither and leaves both to the author. That is a larger breaking change to the macro surface and is left for a follow-up. Fixes F-800
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) 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 | - **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. 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. - [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)*
…4804) (#24808) ## Summary Backport of #24804 to `v5-next` via `backport-to-v5-next-staging`. Restores the mainnet `SLASH_GRACE_PERIOD_L2_SLOTS` default from `1200` to `8400` slots and updates the operator slashing docs to describe the 7-day grace period. ## Conflict resolution The automatic cherry-pick conflicted in: - `spartan/environments/network-defaults.yml` - `docs/docs-operate/operators/sequencer-management/slashing-configuration.md` Resolved by keeping the v5 branch's surrounding slashing/defaults context and applying only the intended grace-period value and docs wording from the source PR. ## Tests - `yq '.networks.mainnet.SLASH_GRACE_PERIOD_L2_SLOTS' spartan/environments/network-defaults.yml` - `slots=$(yq '.networks.mainnet.SLASH_GRACE_PERIOD_L2_SLOTS' spartan/environments/network-defaults.yml) && slot_duration=$(yq '.networks.mainnet.AZTEC_SLOT_DURATION' spartan/environments/network-defaults.yml) && test "$slots" = 8400 && test "$slot_duration" = 72 && test $((slots * slot_duration)) -eq 604800` - `rg -n 'SLASH_GRACE_PERIOD_L2_SLOTS[:=] ?1200|First 1,200|First 128 slots|1,200 slots' spartan/environments docs/docs-operate` (no matches) - `git diff --check origin/backport-to-v5-next-staging...HEAD` --- *Created by [claudebox](https://claudebox.work/v2/sessions/195fbf5dfecad0c3/jobs/1) · group: `slackbot` · [Slack thread](https://aztecprotocol.slack.com/archives/C0AGN2WT3CP/p1784549517302859?thread_ts=1784549517.302859&cid=C0AGN2WT3CP)*
This pr adds an optional prover-node config, `PROVER_NODE_PROOF_SUBMISSION_TARGET_ADDRESS`, that lets a prover send the `submitEpochRootProof` tx to a contract other than the rollup. Everything else is unchanged: all rollup state is still read from the real rollup, only the destination of the submit tx is redirected. When unset, it defaults to the rollup address, so existing provers are unaffected. Use case: A prover that wants to claim prover tips from oxide-styled withdrawal txs must register itself in the Pool contract as the first prover to submit a proof of a given length L. To do that, it deploys a wrapper contract that calls the Pool before (check proven length = L-T) and after (check proven length = L) calling `submitEpochRootProof` on the rollup, then points this config at the wrapper. Closes GK-752
This fixes a scoping bug where an account's ivsk would be used to produce an ECDH shared secret even if that account was not in scope. The base wallet class was adjusted to put these in scope when an explicit sender is selected for tagged messages.
Just a comment.
Replace the secp256r1-specific unique/positive table_index test with one that sweeps every basic table reachable through any MultiTable. The LogDeriv relation identifies a table solely by table_index, so this guards against any generator (not just secp256r1 fixed-base) storing a window or bit-slice position in place of the builder-assigned index.
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
fix(bb): assign unique secp256r1 lookup table indices
Reduce the mainnet SLASH_INACTIVITY_TARGET_PERCENTAGE default from 0.8 (80%) to 0.7 (70%) in spartan/environments/network-defaults.yml. Only the networks.mainnet preset is changed; devnet/testnet and the top-level slasher anchor (all 0.9) are untouched.
BEGIN_COMMIT_OVERRIDE fix(docs-examples): pin typescript to 5.x in execute runner (#24736) chore(spartan): restore 7 day mainnet slash grace period (#24804) chore(spartan): restore 7 day mainnet slash grace period (backport #24804) (#24808) feat: allow custom proof submission target address (#24270) END_COMMIT_OVERRIDE
…5-next (#24842) Brings public `v5-next` up to `private/v5-next` (`eb52040bd1`), porting the barretenberg secp256r1 fixed-base lookup-table soundness fix. ## Net change (6 files, all under `barretenberg/cpp/`) - Assign a unique `table_index` to each secp256r1 fixed-base lookup table, and add finalize-time guards that reject duplicate or zero table indices, with a new circuit-checker test (`Secp256r1FixedBaseTablesGetUniquePositiveIndices`, `FinalizationRejectsDuplicateTableIndices`, `FinalizationRejectsZeroTableIndex`). - Refresh the pinned Chonk IVC inputs hash to match the circuit change. ## Notes for reviewers - The commit set also includes the routine `chore: sync public-v5-next with upstream v5-next` merge nodes that sit between the two tips; those carry no net file change. The only net delta is the fix + the chonk hash bump. - Must merge via a **merge commit** (branch ruleset allows `merge` only). The public→private sync will reconcile `v5-next` afterward, so private stays a fast-forward of public.
## Summary - Documents the trust model of partial note completion on `PartialUintNote` and `PartialNFTNote`: - The validity commitment only proves that the contract created the partial note designating `completer`. - The storage slot and value/token id are trusted arguments, not bound by the commitment. - The completer is not authenticated by the check itself, so contracts must pass `msg_sender()` as `completer`. - Adds a WARNING that completion is not single-use: the designated completer can complete the same partial note any number of times, so contracts must make every completion independently paid for or authorized in the completing function (as the token and NFT contracts already do). - Fixes doc overclaims that said the validity commitment verifies the storage slot / state variable.
…#24844) ## Summary - AuthRegistry, MultiCallEntrypoint and PublicChecks hold no private state, but used the default `sync_state`, which performs pointless discovery RPC calls and embeds the HandshakeRegistry address in their bytecode. - Adds a shared `do_sync_state_no_op` handler to aztec-nr and wires it into those three contracts, plus SchnorrInitializerlessAccount, which previously carried its own local copy of the same no-op. - The pinned standard-contract artifacts are untouched, so shipped artifacts and addresses only change at the next intentional re-pin.
A contract with no notes might otherwise panic if e.g. it processed an offchain message related to one. I also made PXE skip the standard contracts that have no notes and events, both to avoid such a situation and because there's no need to do it.
BEGIN_COMMIT_OVERRIDE docs(aztec-nr): document partial note completion trust model (#24816) refactor(aztec-nr): shared no-op sync handler for stateless contracts (#24844) fix: dont panic on note msgs on contracts with no notes (#24852) docs(noir-contracts): document standard-contract re-pin consequences (#24890) fix: change init and single claim nullif to incl owner address, add testing utilities (#24892) END_COMMIT_OVERRIDE
Merged
alexghr
approved these changes
Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotes
v5-nextontov5for the v5.1.0 release.v5-nextintov5; the resulting tree is identical tov5-nextand.release-please-manifest.jsonis set to 5.1.0 (the only merge conflict was the manifest — v5 held 5.0.1, resolved to v5-next's 5.1.0).mergeonly).v5HEAD is taggedv5.1.0.Does not include #24840 (json-rpc result key), which is still on
merge-train/spartan-v5and not inv5-next.