Skip to content

feat(batch kernel): emit batch_expiration_block_num as the running-min over transactions#3019

Draft
mmagician wants to merge 32 commits into
mmagician-claude/batch-kernel-logicfrom
mmagician-claude/batch-kernel-expiration
Draft

feat(batch kernel): emit batch_expiration_block_num as the running-min over transactions#3019
mmagician wants to merge 32 commits into
mmagician-claude/batch-kernel-logicfrom
mmagician-claude/batch-kernel-expiration

Conversation

@mmagician

Copy link
Copy Markdown
Collaborator

Stacked on top of #2905. Adds the batch's batch_expiration_block_num output: the minimum expiration_block_num across all transactions in the batch.

What this does

  • During Layer 2 (per-tx header verification), the prologue pops each transaction's expiration_block_num from the advice stack and accumulates the running minimum into memory::BATCH_EXPIRATION_PTR (initialised to u32::MAX). The minimum is order-independent, so advice-stack ordering carries no correctness risk.
  • main.masm emits the accumulated minimum at output felt index 8: [INPUT_NOTES_COMMITMENT, BATCH_NOTE_TREE_ROOT, batch_expiration_block_num, pad(7)].
  • BatchKernel::build_advice_inputs pushes each transaction's expiration_block_num onto the advice stack.
  • BatchExecutor::execute cross-checks the kernel's emitted value against the expiration the ProposedBatch independently derives from its transactions, returning ProvenBatchError::BatchExpirationMismatch on disagreement.

BATCH_NOTE_TREE_ROOT remains a zero placeholder (BatchNoteTree work).

Caveats (tracked as TODOs)

  • The expiration is currently read from the unverified advice stack rather than derived from data committed-to in the verified transaction header.
  • Each expiration_block_num_i > reference_block_num is not yet asserted.

Tests

  • batch_kernel_emits_input_notes_commitment_and_expiration asserts the emitted expiration equals the proposed batch's independently-derived minimum (800 = min(1234, 800)).
  • batch_executor_then_prover_produces_proven_batch exercises the executor cross-check end-to-end.

claude and others added 26 commits May 12, 2026 08:18
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.
Co-authored-by: Marti <marcin.gorny.94@protonmail.com>
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.
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.
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.
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.
…h-kernel-skeleton

# Conflicts:
#	Cargo.lock
#	crates/miden-protocol/src/batch/mod.rs
#	crates/miden-testing/src/kernel_tests/batch/mod.rs
#	crates/miden-tx-batch-prover/Cargo.toml
#	crates/miden-tx-batch-prover/src/local_batch_prover.rs
…TMENT

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.
Prefer the associated constant `Felt::ZERO` over the bare `ZERO` import
in the batch output padding check.

Addresses a review comment on PR #2904.
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.
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.
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.
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.
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.
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.
Take `BatchId` instead of a raw `Word` so the input contract is expressed
through the domain type.
The type holds multiple outputs; rename it for consistency with
`TransactionOutputs`.
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.
Store the parsed `BatchOutputs` on `ExecutedBatch` and expose it via a
typed `batch_outputs()` accessor, replacing the raw `stack_outputs()`.
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-expiration branch from 5972411 to ef11540 Compare June 1, 2026 10:25
Add unit tests for the well-formed stack, non-zero padding rejection, and
oversized expiration block number rejection.
@mmagician mmagician changed the title feat: emit batch_expiration_block_num as the running-min over transactions feat: emit batch_expiration_block_num as the running-min over transactions Jun 1, 2026
@mmagician mmagician changed the title feat: emit batch_expiration_block_num as the running-min over transactions feat(batch kernel): emit batch_expiration_block_num as the running-min over transactions Jun 1, 2026
@mmagician mmagician added kernels Related to transaction, batch, or block kernels pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority labels Jun 1, 2026
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 7e97e87 to 7dbd6b7 Compare June 1, 2026 10:42
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-expiration branch from ef11540 to 56363ea Compare June 1, 2026 10:46
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 7dbd6b7 to 5bccee1 Compare June 1, 2026 11:25
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-expiration branch from 56363ea to fc480f2 Compare June 1, 2026 11:26
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 5bccee1 to 133f9bb Compare June 1, 2026 11:38
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-expiration branch from fc480f2 to ea42818 Compare June 1, 2026 11:43
Fill in the batch kernel to verify the batch's transaction list against
its BATCH_ID (Layer 1), verify each transaction header (Layer 2), and
recompute the batch INPUT_NOTES_COMMITMENT from the verified per-tx input
notes (Layer 3). Output-notes (BATCH_NOTE_TREE_ROOT) and the expiration
running-min stay as zero placeholders, wired up in follow-up PRs.
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 133f9bb to 59c2efb Compare June 1, 2026 13:51
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-expiration branch from ea42818 to af57214 Compare June 1, 2026 13:57
claude added 3 commits June 1, 2026 14:20
… injection

Add BatchExecutor::extend_advice_inputs (mirroring TransactionContextBuilder)
so the kernel's rejection paths can be exercised through the normal executor
with tampered advice, and drop the low-level run_kernel test helper. The three
negative tests now corrupt the Layer 1/2/3 advice-map entries via the executor.
Match the operand-stack (# =>) and advice-stack (# AS =>) comment style used
throughout the rest of the protocol assembly.
…tions

The batch kernel accumulates the minimum expiration_block_num across all
transactions (popped per-tx from the advice stack during Layer 2 header
verification) and emits it as the batch_expiration_block_num output.
BatchExecutor cross-checks the kernel's value against the expiration the
ProposedBatch independently derives, erroring with BatchExpirationMismatch
on disagreement.
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-expiration branch from af57214 to b46a277 Compare June 1, 2026 14:24
@mmagician mmagician force-pushed the mmagician-claude/batch-kernel-logic branch from 093ac8e to 622bee3 Compare June 3, 2026 12:32
greenhat added a commit to 0xMiden/compiler that referenced this pull request Jul 7, 2026
Port the Miden protocol batch kernel (0xMiden/protocol#2905, plus the expiration running-minimum of 0xMiden/protocol#3019) to Rust compiled with the Miden compiler, to exercise the compiler on a realistic kernel-sized program.

The fixture at tests/fixtures/batch-kernel mirrors the MASM kernel module-for-module: the prologue unhashes the layered advice data anchored at the public BATCH_ID, the note tracker determines intra-batch erasure and binds the host-provided sorted note lists to the verified per-transaction notes, and the epilogue enforces the tracking invariants and computes INPUT_NOTES_COMMITMENT. The smoke test plays the protocol's BatchKernel::prepare_inputs role: it derives batch ids, transaction ids and note commitments for mock transactions with the host hasher, feeds the layered advice map and the expiration advice stack, and checks the kernel outputs across four scenarios (a plain two-transaction batch, intra-batch note erasure, a tampered BATCH_ID pre-image, and a consume-before-create rejection).

Note-flag state is felt-typed and the sorted-list lookup uses a hand-rolled word comparison: integer discriminant matches currently lower to a br_table whose checked I32->U32 selector cast rejects legitimately wrapped selectors ("value does not fit in i32"), so the fixture stays in the felt domain where comparisons lower to opaque intrinsics.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kernels Related to transaction, batch, or block kernels pr-from-maintainers PRs that come from internal contributors or integration partners. They should be given priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants