Skip to content

Tracking PR for v0.16.0 release#2976

Draft
bobbinth wants to merge 23 commits into
mainfrom
next
Draft

Tracking PR for v0.16.0 release#2976
bobbinth wants to merge 23 commits into
mainfrom
next

Conversation

@bobbinth
Copy link
Copy Markdown
Contributor

This is a tracking PR for v0.16.0 release.

bobbinth and others added 23 commits May 22, 2026 14:15
* feat: implement Clone for TransactionContextBuilder

* chore: add unwrap_unauthorized_err
* feat(agglayer): reject duplicate GER insertions

Adds a duplicate-detection guard to `bridge_config::update_ger`: after
calling `set_map_item`, the OLD_VALUE returned is compared against
EMPTY_WORD; if it is not empty the GER was already registered and the
transaction panics with ERR_GER_ALREADY_REGISTERED.

Note on Solidity divergence: the Solidity GlobalExitRootManager treats
duplicate GER insertions as idempotent no-ops. Miden intentionally
rejects them because a permanently-unconsumable network note is a worse
failure mode than an explicit transaction revert. This divergence is
documented in SPEC.md.

Docs updated on `update_ger`, the `update_ger.masm` note script, and
SPEC.md (Panics row + Section 2.3 prose). A new integration test
(`update_ger_rejects_duplicate`) verifies that a second UPDATE_GER note
carrying the same GER value is rejected with the expected error code.

Closes #2708

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore: add CHANGELOG entry for #2983

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* review: combine padw+assert_eqw and use assert_transaction_executor_error!

- bridge_config.masm: collapse the `padw` / `assert_eqw` pair onto a single
  line as suggested in review.
- tests: replace the manual `is_err()` + `error_msg.contains(...)` block
  with the standard `assert_transaction_executor_error!` macro.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* review: use word::eqz + assert instead of padw + assert_eqw

Slightly cheaper than the `padw`-then-`assert_eqw` pair: `word::eqz`
consumes the 4-felt `OLD_VALUE` and pushes a single 0/1 flag, then a
plain `assert.err=...` verifies it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The MASM doc-comment and formatting conventions previously captured in
masm_doc_comment_fmt.md are now covered by the .claude/skills/masm-*
skill files plus the MASM formatting tool. Maintaining a separate
hand-written guide is redundant and prone to drift, so remove it.

Closes #2021

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
The protocol does not prevent adding multiple attachments with the same
scheme to a note (e.g. two NetworkAccountTarget attachments). Document
that doing so is discouraged as it brings no additional benefit and only
increases public on-chain data and fees, and clarify in the rustdoc that
the first matching attachment is treated as the canonical one.

Closes #2873

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* refactor: include leaves number in BURN note ID computation

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

---------

Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Marti <marcin.gorny.94@protonmail.com>
* Extend execution-error assertion macros with patter and any arms

* Fix formating

* Apply PR review feedback
…k level (#2993)

* feat: reject consuming and creating same note in a tx

* feat: erase notes on the fly

* chore: remove unused `NoteCommitmentMismatch` error variants

* chore: add changelog

* chore: rename input/output note tracker functions

* feat: reintroduce `NoteTracker` for readability

* chore: improve clarity of comments

* chore: format changelog

* chore: add second cross-tx circular dep test
* feat: rename storage delta to patch

* chore: add changelog
* refactor(protocol): relocate TransactionVerifier into miden-protocol

Move TransactionVerifier and TransactionVerifierError from miden-tx to
miden-protocol (transaction module + errors) with no behavior change.
This lets ProposedBatch (in miden-protocol) verify transaction proofs in
a follow-up without a miden-protocol -> miden-tx dependency cycle.

TransactionVerifier is a thin wrapper over types already in
miden-protocol (TransactionKernel, CoreLibrary, miden-verifier), so the
move adds no new dependencies: miden-tx no longer needs miden-verifier,
and miden-tx-batch-prover no longer needs miden-tx. No re-export is kept
from miden-tx (a breaking change to its public surface); in-repo
importers now use miden_protocol::transaction::TransactionVerifier.

* refactor(protocol): verify transaction proofs in ProposedBatch::new

Move per-transaction proof verification from LocalBatchProver into
ProposedBatch construction. ProposedBatch::new now takes a
proof_security_level and verifies each transaction's ExecutionProof (via
the relocated TransactionVerifier) after the structural batch validation,
which is factored into a private new_batch_inner.

A testing-gated new_unverified skips verification for batches built from
mock/dummy-proof transactions. Deserialization reconstructs via
new_batch_inner (no re-verification; documented), so serialized batches
do not require valid proofs to be read back. LocalBatchProver loses its
verify loop and proof_security_level, collapsing to a single prove.

ProposedBatchError gains a typed TransactionVerificationFailed variant;
the now-unused ProvenBatchError::TransactionVerificationFailed is removed.
MockChain and the batch structural tests build via new_unverified.

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…ss (#2999)

The code-reviewer and security-reviewer agents treat every finding as
blocking, with no notion of deliberately-staged work. A skeleton or
placeholder that is explicitly documented as incomplete, warns against
misuse, and is not wired into a path that relies on the missing behavior
was being flagged as a blocking Critical/Important/Warning, forcing a
bypass of the pre-push gate.

Add a "documented, intentional incompleteness" rule to both agents:
downgrade such a limitation to a Nit/Note (which the pre-push hook does
not block on) when it is documented, warned about, and self-contained;
keep the high severity when the documentation is missing or misleading,
or when the incomplete code is actually reachable from a trust boundary.

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…2988) (#3005)

* feat(protocol): add active_note::is_public / is_private (#2988)

Cherry-pick the reusable protocol-level building blocks from #2988,
which was merged to the agglayer branch as an agglayer-specific
B2AGG bridge-out hardening:

  - active_note::is_public
  - active_note::is_private

Both procs read the active note's metadata and decode its note
type via the existing note::metadata_into_note_type primitive
(from #2738), then compare against NOTE_TYPE_PUBLIC /
NOTE_TYPE_PRIVATE from miden::protocol::util::note. A parameterized
kernel test covers the Public and Private cases.

The agglayer-only files from #2988 (bridge_out.masm, B2AGG.masm,
tests/agglayer/bridge_out.rs) and the constant-value flip the PR
applied on agglayer's NoteType encoding are intentionally not
brought along: next already encodes Private=0, Public=1, and the
existing metadata_into_note_type is tailored to next's metadata
bit layout.

Co-Authored-By: Claude (Opus) <noreply@anthropic.com>

* fix(agglayer): enforce NoteType::Public for B2AGG bridge-out notes (#2988)

Cherry-pick the bridge-side half of #2988 to next. The B2AGG note
type lives in NoteMetadata, not in the recipient commitment, so an
attacker could submit a note with an identical recipient,
attachment, and asset but NoteType::Private. consensus would accept
it, the leaf would be folded into the on-chain Local Exit Tree, but
aggkit could never recover the pre-image off-chain — the LET mirror
would permanently desync and the bridge-out path would brick.

Add an active_note::is_public assert at the top of bridge_out,
extend the bridge_out and b2agg.masm doc comments, and parameterize
the existing destination-network-is-Miden test into
test_bridge_out_rejects_invalid_b2agg_note covering the
recipient-identical private-note case too.

Co-Authored-By: Claude (Opus) <noreply@anthropic.com>

* Apply suggestions from code review

Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>

* chore: fmt files

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Marti <marti@miden.team>
Co-authored-by: Philipp Gackstatter <PhilippGackstatter@users.noreply.github.com>
…2755)

* Patch crypto with Clones

* Split reader writer impls

* Fix impl read write matching

* Split NullifierTreeBackend reader writer

* Replace write with reader traits

* Lint

* update crypto after revert

* Back to v0.14

* Back to v0.15

* Fix trait bound readers

* Update crypto dep

* Changelog

* Update crypto branch

* Update deps

* Update deps

* Update deps

* Update deps

* Add reader()

* Update deps

* Bump crypto v0.24

* Changelog

* Update changelog

* Move id prefix to smt fn to account id key

* Move account tree impls

* Move nullifier tree impls

* Add AccountTree::with_storage_from_entries

* Changelog

* fix docs

---------

Co-authored-by: Marti <marti@miden.team>
…ng (#3015)

* docs(overview): clarify transaction definition and execution vs proving

* docs(overview): refine transaction definition per review

Address Philipp's review note: a transaction is not always the state
transition of an account. Reframe so account mutation is one of two
possible effects (mutating storage/vault, or creating/consuming notes),
and note that the account need not be mutated at all.

* docs: add changelog entry for #3015
…g tooling (#2997)

* fix(hooks): base pre-push review on the integration branch

The pre-push reviewer derived its diff base from the branch's own
upstream tracking ref (@{u}). For a branch that merged next in, the
merge-base against its pre-merge remote tip swept the entire merged
history into the reviewed diff, so the code-reviewer and
security-reviewer ended up checking all of next instead of just the
branch's own change.

Resolve the review base from the remote default branch (origin/HEAD,
i.e. origin/next) instead. merge-base(HEAD, origin/next) is then the
branch's divergence point, so the reviewed diff is exactly this
branch's contribution, even after merging next in. Adds unit tests
for _diff_base.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update .claude/hooks/pre_push_review.py

* chore(hooks): drop the _diff_base unit test

Not needed for this change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(reviewers): diff the integration branch / PR, not the local checkout

Apply the same diff-base correction this PR makes to pre_push_review.py
across the agents it spawns and the changelog agent:

- code-reviewer / security-reviewer diffed `@{upstream}...HEAD`, which (like
  the hook before this PR) drags the whole merged history into the review once
  the integration branch is merged in. Point them at the remote default branch
  (`origin/HEAD`) instead.
- changelog-manager classified a local `git diff origin/next...HEAD`, which
  analyzes whatever branch the cwd is on rather than the PR being created.
  Classify `gh pr diff <N>` instead, so it always sees the PR's own diff (this
  also fixes creating a PR for one branch from a worktree on another).

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
… review (#3024)

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* feat: add skeleton batch kernel + ProvenBatch proof field

Establishes the public input/output contract for the batch kernel (#1122)
plus the Rust plumbing that surrounds it, without any verification logic.

- main.masm drops TRANSACTIONS_COMMITMENT + BLOCK_HASH and exits; the VM's
  depth >= 16 invariant leaves the all-zero 16-felt output region in place.
- BatchKernel struct exposes prepare_inputs / build_input_stack /
  build_output_stack / parse_output_stack; build_advice_inputs returns the
  default empty AdviceInputs since the skeleton ignores advice data.
- ProvenBatch carries a proof: ExecutionProof field through
  new_unchecked and serde.
- LocalBatchProver::prove now runs the kernel via miden_prover::prove and
  attaches the proof to the returned ProvenBatch. The kernel's public
  outputs are not yet cross-checked against the proposed batch; that lands
  with the verification logic.
- prove_dummy retained for tests that don't want proof generation.

Smoke test exercises the full plumbing: builds a realistic two-transaction
ProposedBatch, runs the kernel via FastProcessor, asserts the parsed
outputs are empty / zero.

TODO list in main.masm enumerates the checks the verification PR will
introduce.

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* chore(protocol): drop premature BATCH error category

The batch kernel is compiled separately and its MASM errors are not
extracted by generate_error_constants (which only scans the transaction
kernel dir), so the BATCH entry in TX_KERNEL_ERROR_CATEGORIES is inert.
Batch error handling will be added properly alongside the verification
logic.

* refactor(protocol): order build_input_stack params to match stack layout

Pass transactions_commitment before block_hash so the parameter order
matches the documented input stack [TRANSACTIONS_COMMITMENT, BLOCK_HASH].
Also drop the now-stale reference to the main.masm TODO from the
BatchKernel doc comment.

* refactor(batch-prover): remove unused proof_security_level accessor

The getter had no callers.

* refactor(protocol): simplify batch output padding check

Replace the two separate pad-word checks with a single scan over every
cell after batch_expiration_block_num, dropping the EXPIRATION_PAD_WORD_*
and TRAILING_PAD_WORD_FELT_IDX constants.

* test(batch): reuse shared chain setup helpers

Expose TestSetup and setup_chain from the proposed_batch test module and
reuse them in the batch kernel smoke test instead of re-implementing the
identical TestSetup/setup/generate_account fixtures.

* docs: trim verbose batch kernel CHANGELOG entry

* refactor(protocol): name batch kernel inputs BATCH_ID and BLOCK_COMMITMENT

Rename the batch kernel's public inputs from TRANSACTIONS_COMMITMENT to
BATCH_ID (consistent with the `BatchId` type the value comes from) and
from BLOCK_HASH to BLOCK_COMMITMENT (we no longer use "hash"). Trim the
over-detailed BATCH_ID doc comment down to just referencing `BatchId`.

Addresses review comments on PR #2904.

* refactor(protocol): use Felt::ZERO associated constant

Prefer the associated constant `Felt::ZERO` over the bare `ZERO` import
in the batch output padding check.

Addresses a review comment on PR #2904.

* refactor(protocol): type batch kernel errors instead of stringifying

Stringifying the kernel error via `to_string` discarded the source error
chain. Wrap the real source instead: `BatchKernelExecutionFailed` now
carries `#[source] ExecutionError`, and a dedicated
`BatchKernelOutputInvalid(#[source] BatchOutputError)` variant covers
output-stack parsing failures. The batch prover maps these directly.

Addresses a review comment on PR #2904.

* test(batch): rename batch_kernel module to test_batch_kernel

Adopt the `test_*` naming used by `kernel_tests/tx/test_*.rs` so the
`kernel_tests::batch::batch_kernel` path is no longer redundant and
future per-feature batch kernel test modules slot in consistently.

Addresses a review comment on PR #2904.

* chore: shorten comment

* chore: fmt

* refactor(batch-prover): split batch execution and proving

Separate batch kernel execution from proof generation, mirroring the
transaction flow's ExecutedTransaction:

  ProposedBatch -> BatchExecutor::execute -> ExecutedBatch
  ExecutedBatch -> LocalBatchProver::prove -> ProvenBatch

`BatchExecutor::execute` runs the batch kernel (via the synchronous trace
APIs, `execute_trace_inputs_sync`), validates the output stack shape, and
returns an `ExecutedBatch` holding the trace inputs. `LocalBatchProver`
now consumes an `ExecutedBatch` and only builds the trace + proof (via
`prove_from_trace_sync`), so the flow is fully synchronous. Transaction
proofs are already verified in `ProposedBatch::new`, so the executor does
not re-verify them.

This lets tests exercise raw batch execution without re-proving. The
batch kernel smoke test now goes through `BatchExecutor`, removing the
inline FastProcessor setup, and a new test covers the execute -> prove
path.

Addresses review comment T19 on PR #2904.

* Update crates/miden-tx-batch-prover/src/batch_executor.rs

* refactor(protocol): return a BatchOutput from parse_output_stack

Introduce a `BatchOutput` type (mirroring `TransactionOutputs`) that
encapsulates the batch kernel's parsed outputs — input/output note
commitments and the batch expiration block number — instead of returning
a raw `(Word, Word, BlockNumber)` tuple. The output-stack layout indices
move onto `BatchOutput` as associated constants.

Addresses review comment T15 on PR #2904.

* refactor(protocol): put BLOCK_COMMITMENT on top of the batch input stack

Order the batch kernel's public inputs as [BLOCK_COMMITMENT, BATCH_ID]
to stay consistent with the transaction kernel's input layout.

Addresses a review comment on PR #2904.

* refactor(protocol): name the batch output BATCH_NOTE_TREE_ROOT

Rename the batch kernel's second output from OUTPUT_NOTES_COMMITMENT to
BATCH_NOTE_TREE_ROOT (and the `BatchOutput` field/accessor/layout const
accordingly). The end-goal output is the root of the batch's note tree,
which lets the block kernel aggregate per-batch note trees instead of a
flat output-notes commitment; renaming now fixes the contract name even
though the value is still wired up in a follow-up.

Addresses a review comment on PR #2904.

* refactor(batch): strong-type build_input_stack batch_id param

Take `BatchId` instead of a raw `Word` so the input contract is expressed
through the domain type.

* refactor(batch): rename BatchOutput to BatchOutputs

The type holds multiple outputs; rename it for consistency with
`TransactionOutputs`.

* refactor(batch): move output parsing onto BatchOutputs and return errors

Replace `BatchKernel::parse_output_stack` with `BatchOutputs::parse`, and
return `BatchOutputError::OutputStackInvalid` instead of panicking when a
required output word or element is missing from the stack.

* refactor(batch): expose typed BatchOutputs from ExecutedBatch

Store the parsed `BatchOutputs` on `ExecutedBatch` and expose it via a
typed `batch_outputs()` accessor, replacing the raw `stack_outputs()`.

* test(batch): cover BatchOutputs::parse error branches

Add unit tests for the well-formed stack, non-zero padding rejection, and
oversized expiration block number rejection.

* Apply suggestion from @mmagician

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
…3032)

Adds a regression test that pushes a marker word before calling
active_note::get_metadata and asserts the metadata word is added directly
on top of it. This catches the regression where an empty NOTE_ATTACHMENT
word leaked onto the stack alongside the metadata.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…d` traits (#3009)

* refactor: unify account/nullifier SMT backends into shared SmtBackend traits

Replaces the near-identical AccountTreeBackend/NullifierTreeBackend trait
pairs with a single Word-valued SmtBackendReader + SmtBackend pair, impl'd
once for Smt and once for LargeSmt. The NullifierBlock value wrapping moves
from the backend into NullifierTree's own accessors, leaving the backend
layer value-agnostic. Removes both per-tree backend.rs modules.

* test: add reader() coverage; fix changelog and backend docs

Addresses pre-push review findings on the SMT backend unification:
- correct the CHANGELOG entry to name the shared SmtBackend/SmtBackendReader
  traits instead of the removed per-tree reader traits
- disambiguate the writer-impl section headers in smt_backend.rs
- document that with_storage_from_entries panics (not errors) on storage
  failures, matching large_smt_error_to_merkle_error behavior
- add reader() tests asserting the read-only view shares root and entries

* refactor: unify duplicate-entry error handling across account backends

Removes the redundant AccountTreeError::DuplicateEntries variant and maps
the LargeSmt-backed with_storage_from_entries duplicate case through the same
prefix-extracting helper as the Smt-backed with_entries, so both constructors
surface DuplicateStateCommitments { prefix }. Adds a duplicate-entry test,
documents the read-only reader() invariant, and aligns the leaves()/entries()
lifetime style.

* docs: reference PR #3009 in changelog entry

* test: drop tautological reader_matches_source_tree tests

These only asserted that a freshly created reader view equals its source,
which exercises no meaningful logic. The duplicate-entry test (real error
path) is kept.

* Apply suggestions from code review

Co-authored-by: Marti <marcin.gorny.94@protonmail.com>

* docs: fix unresolved intra-doc links in SmtBackendReader

Use inline `[`leaves`](Self::leaves)` / `[`entries`](Self::entries)` links
instead of reference-style links, which rustdoc failed to resolve under
`-D warnings`.

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat(batch-prover): verify batch kernel execution proofs

Add `BatchVerifier`, the verification counterpart to `LocalBatchProver`.
It reconstructs the batch kernel's public input stack from a
`ProvenBatch` (`BatchId` + reference block commitment) and verifies the
attached `ExecutionProof` against the batch kernel program via
`miden_verifier::verify`.

The skeleton kernel emits the all-zero output region, so verification
checks the proof against that empty-output contract; binding the batch's
real commitments lands with the kernel verification logic. The verifier
is documented as not yet usable at a trust boundary.

Tests build a real batch proof via `BatchExecutor` + `LocalBatchProver`
and cover the positive path (verify + insufficient-security-level
rejection) and the negative path (dummy proof rejected).

* refactor(batch-prover): align BatchVerifier with new input order

Adapt the verifier to the base-branch changes merged in: feed the kernel
public inputs as [BLOCK_COMMITMENT, BATCH_ID] (matching the reordered
build_input_stack signature) and update the docs/comments to reference the
batch note tree root output.

* test(batch-prover): assert against the proof's actual security level

Use proven.proof_security_level() in the accept test: requiring exactly
that level succeeds and requiring one more bit fails, instead of the
arbitrary 0 / u32::MAX bounds.

* refactor(protocol): replace build_output_stack with BatchOutput::into_stack_outputs

Encoding a BatchOutput into the kernel's output stack belongs on BatchOutput
itself, mirroring BatchKernel::parse_output_stack (the inverse) and reusing the
layout constants it already owns. The verifier now constructs a typed all-zero
BatchOutput and converts it, which reads more clearly than passing three loose
words to a free function.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9e91ae3)

* fix(batch-prover): pass BatchId to build_input_stack after rebase

next changed BatchKernel::build_input_stack to take a BatchId instead of a
Word; the rebased BatchVerifier still passed batch.id().as_word(), which broke
the build. Pass batch.id() directly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* init

* changelog

* collapse constructors into custom

* add bon builder

* lint

* remove panic add error

* apply suggestions

* add AccountComponent::has_procedure

---------

Co-authored-by: Bobbin Threadbare <43513081+bobbinth@users.noreply.github.com>
* feat: Add `AccountPatch` and `AccountVaultPatch`

* feat: track vault updates for both delta and patch

* chore: return initial asset value from asset_vault proc

* chore: track initial and final asset values

* chore: add changelog

* fix: broken doc link

* chore: unify separate maps in vault tracker into one

* chore: new_nonce -> final_nonce, old_nonce -> initial_nonce

* chore: move AccountStoragePatch to patch module

* chore: remove buggy `assets` iterator

* chore: leave note for why headers are appended

* chore: vault_patch -> vault

* chore: simplify `is_empty` impl

* chore: clarify asset value / empty word in patch docs

* chore: `AccountDeltaTracker` -> `AccountUpdateTracker`

* feat: domain-separate delta and patch commitment headers

Add distinct domain separators to the headers of `AccountDelta` and
`AccountPatch` commitments so the two contexts can never collide,
even when their bodies are identical. The asset, value-slot, and
map-slot domains are renumbered to 3/4/5 to leave 1/2 reserved for
the delta/patch headers, and the shared constants are centralized in
a new `commitment_domain` module.

* fix: docs on with_assets

* fix: lower case domain_delta

* fix: invert vault patch normalization to drop unchanged entries

* chore: name add_asset/remove_asset output FINAL_ASSET_VALUE

---------

Co-authored-by: Claude (Opus) <noreply@anthropic.com>
* add active_account::has_storage_slot

* changelog

* fix comment
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants