Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
2e1de17
Index account code references for history pruning
gabrielbosio Aug 5, 2026
843f459
Match a single note consumer with = instead of a list
gabrielbosio Aug 5, 2026
6be75f0
Query unspent note nullifiers by a positive state list
gabrielbosio Aug 5, 2026
3c31a47
Update note scripts in place instead of replacing them
gabrielbosio Aug 5, 2026
806ac64
Compare has_client_notes to 1 so the partial index applies
gabrielbosio Aug 5, 2026
bbbda78
Add changelog entries for SQL store query fixes
gabrielbosio Aug 5, 2026
b499d37
Link changelog entries to PR 2364
gabrielbosio Aug 5, 2026
5a1300a
Skip notes without a nullifier when listing unspent ones
gabrielbosio Aug 7, 2026
d3026c1
Move the SQL store fix entry to the Fixes section
gabrielbosio Aug 7, 2026
43206fc
Summarize the SQL store fix entry
gabrielbosio Aug 7, 2026
b88c328
Correct the account code claim in the SQL store fix entry
gabrielbosio Aug 7, 2026
ecb7b03
Rephrase comments on index usage
gabrielbosio Aug 10, 2026
2d0815c
Test that unspent state filters cover every note state
gabrielbosio Aug 10, 2026
d0211c6
Rephrase unspent state filters test comment
gabrielbosio Aug 10, 2026
e6cdb2e
Normalize dot notation in upsert note query comment
gabrielbosio Aug 10, 2026
5e9c532
Cover nullifier in the input notes state index
gabrielbosio Aug 10, 2026
ee829b2
Explain the input notes state index column order
gabrielbosio Aug 10, 2026
3710c44
Give the consumed external test note a nullifier
gabrielbosio Aug 10, 2026
f1bbef9
Split the semicolon in the consumption index comment
gabrielbosio Aug 11, 2026
8aa8582
Correct the column counts in the batch size comment
gabrielbosio Aug 11, 2026
fa90cd5
Drop the redundant unspent nullifier test
gabrielbosio Aug 11, 2026
1a165d8
Cover the batch note script upsert
gabrielbosio Aug 11, 2026
e681d88
Exclude invalid notes from the unspent nullifier query
gabrielbosio Aug 11, 2026
ac1d9e6
Page consumed input notes with a cursor instead of an offset
gabrielbosio Aug 11, 2026
37d20f9
chore: add pending TODOs
juan518munoz Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ jobs:
save-if: false
- name: Run miden-bench CLI tests
run: make test-miden-bench
- name: Run the SQL store scaling benchmark
run: make bench-store
- name: Fetch test node binaries
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* [BREAKING][param][rust] `NodeRpcClient` models encrypted submissions: `submit_proven_transaction` now takes `SealedTransactionInputs` instead of `TransactionInputs`, `submit_proven_batch` now takes `Vec<SealedTransactionInputs>` (one per transaction, each sealed against its own transaction ID), and implementations must provide the new `get_transaction_encryption_key` method ([#2341](https://github.com/0xMiden/rust-sdk/pull/2341)).
* [BREAKING][type][rust] Added the `NoteFilter::ScriptRoots` variant, so exhaustive matches on `NoteFilter` in `Store` implementations must handle it ([#2335](https://github.com/0xMiden/rust-sdk/pull/2335)).
* [BREAKING][behavior][store] The SQLite base schema now declares an index on `input_notes(script_root)`. This changes the schema fingerprint, so opening a database created before this change fails with `SchemaHashMismatch` and existing stores must be recreated ([#2335](https://github.com/0xMiden/rust-sdk/pull/2335)).
* [BREAKING][behavior][store] The SQLite base schema now indexes `code_commitment` on `latest_account_headers`, `historical_account_headers` and `foreign_account_code`, the `input_notes` consumption index now leads with `consumer_account_id`, and the `input_notes` state index now carries `nullifier`. This changes the schema fingerprint, so opening a database created before this change fails with `SchemaHashMismatch` and existing stores must be recreated ([#2364](https://github.com/0xMiden/rust-sdk/pull/2364)).
* [BREAKING][param][rust] `Store::get_input_note_by_offset` is replaced by `Store::get_input_note_after`, which takes an `Option<InputNoteCursor>` identifying the last note read instead of an ordinal offset. Build the cursor for the next call with `InputNoteCursor::from_record`. `Store` implementations must be updated; `InputNoteReader` is unaffected ([#2364](https://github.com/0xMiden/rust-sdk/pull/2364)).

### Enhancements

Expand All @@ -21,9 +23,15 @@
* [FEATURE][rust] `Client::get_consumable_notes(Some(account_id))` now screens only that account instead of screening every tracked account and discarding the rest, so its cost no longer grows with the number of tracked accounts. Added `NoteScreener::get_batch_consumability_for_account` to screen notes against a single account ([#2338](https://github.com/0xMiden/rust-sdk/pull/2338)).
* [FEATURE][rust] Added the `miden_client::rpc::encryption` module backing encrypted submissions: `TransactionEncryptionKey`, `AttestedTransactionEncryptionKey` (whose `verify` is the only path to a usable key), `ValidatorAttestation`, `NextTransactionEncryptionKey`, `SealedTransactionInputs` and `seal_transaction_inputs`, along with re-exports of the validator DSA key types reachable from this API ([#2341](https://github.com/0xMiden/rust-sdk/pull/2341)).
* [FEATURE][rust,store] Added `NoteFilter::ScriptRoots` to query input notes by their note script root directly at the store level, without loading and screening unrelated notes. The filter doesn't apply to output notes: querying output notes with it returns an empty list ([#2335](https://github.com/0xMiden/rust-sdk/pull/2335)).
* [FEATURE][store] Added the `miden-bench store` subcommand, which measures how the `SQLite` store methods scale with the number of notes and accounts and reports the growth between the smallest and the largest size. It seeds its own throwaway databases and needs no node, and `make bench-store` runs the same sweep CI does ([#2364](https://github.com/0xMiden/rust-sdk/pull/2364)).
* [rust] Added `PartialBlockchainUpdates::block_headers_to_store`, which narrows the staged headers to the ones a sync must persist: those marked as relevant, genesis, and the block at the sync height. `block_headers` still yields all staged headers ([#2297](https://github.com/0xMiden/rust-sdk/pull/2297)).
* [rust] State sync now authenticates every relevant note block but only persists block headers and MMR authentication nodes for blocks containing notes that remain unspent or that a `NoteObserver` explicitly marks as relevant ([#2297](https://github.com/0xMiden/rust-sdk/pull/2297)).

### Fixes

* [FIX][rust] `InputNoteReader::next` now fails with `ClientError::MissingNoteConsumptionPosition` when the store yields a note that carries no consumption position. The walk cannot advance past such a note, and it previously restarted from the first note on every subsequent call ([#2364](https://github.com/0xMiden/rust-sdk/pull/2364)).
* [FIX][store] Input notes listed with `NoteFilter::Consumed` now break ties on the details commitment instead of the note ID, so notes consumed by the same transaction come back in a stable order. A note only carries an ID once its metadata is known, which left the previous tie-break undefined for the rest ([#2364](https://github.com/0xMiden/rust-sdk/pull/2364)).

## 0.16.0-alpha.1 (2026-07-17)

### Breaking Changes
Expand Down
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ WARNINGS=RUSTDOCFLAGS="-D warnings"

TEST_MIDEN_NOTE_TRANSPORT_URL?=http://127.0.0.1:57292

# Sizes the SQL store scaling benchmark sweeps over. Kept small enough to run on every PR, and
# overridable for a deeper local run.
STORE_BENCH_ARGS?=--notes 1000,10000 --accounts 100,1000 --iterations 5

# --- Linting -------------------------------------------------------------------------------------

.PHONY: clippy
Expand Down Expand Up @@ -84,6 +88,12 @@ test-miden-bench: ## Run miden-bench CLI tests
test-docs: ## Run documentation tests
cargo test --doc $(FEATURES_CLIENT)

# --- Benchmarking --------------------------------------------------------------------------------

.PHONY: bench-store
bench-store: ## Run the SQL store scaling benchmark (no node needed)
cargo run --package miden-client-bench --release --locked -- store $(STORE_BENCH_ARGS)

# --- Integration testing -------------------------------------------------------------------------

.PHONY: start-node
Expand Down
41 changes: 40 additions & 1 deletion bin/miden-bench/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# miden-bench

Benchmarking tool for the Miden client library. This binary measures performance of transactions to establish baselines and identify optimization opportunities.
Benchmarking tool for the Miden client library. This binary measures performance of transactions and of the `SQLite` store to establish baselines and identify optimization opportunities.

## Installation

Expand Down Expand Up @@ -66,6 +66,39 @@ The number of storage maps is auto-detected from the account.
miden-bench --network localhost transaction --account-id 0x...
```

### `store`

Benchmarks the `SQLite` store as the database grows.

```bash
miden-bench store --notes 1000,10000 --accounts 100,1000 --iterations 5
```

Two tables come out of a run, one per sweep. Each row is a store method, each column a size, and the last column the growth from the first size to the last. That growth is the number to read: a method served by an index stays near `1.00x` while the database grows, and one that falls back to a scan grows with it.

The note sweep seeds three quarters of the notes as consumed by a single account, spread over blocks and transaction orders, and the rest as unspent notes carrying a nullifier. It measures:

- `get_input_notes` for the `Unspent`, `Consumed`, `List`, `Nullifiers` and `ScriptRoots` filters
- `get_unspent_input_note_nullifiers` and `get_tracked_block_headers`
- `get_input_note_after` seeded with a cursor near the end of the account's history
- a full `InputNoteReader` walk, reported as a total and per note
- `upsert_input_notes` and `apply_state_sync` for a fixed batch of new notes

The account sweep seeds wallets that share one account code, and measures `SqliteStore::new` (which rebuilds the SMT forest on open), `get_account_headers`, `get_account_header` and `prune_account_history`.

Reads run before writes within a size, so every read measures exactly the seeded database.

```bash
# A deeper sweep. Seeding is linear in the sizes, so the run time is too.
miden-bench store --notes 10000,100000 --accounts 1000,10000
```

`make bench-store` runs the same sweep CI does. Override `STORE_BENCH_ARGS` to change the sizes:

```bash
make bench-store STORE_BENCH_ARGS="--notes 5000,50000 --accounts 500,5000"
```

### `import`

Imports an account into the local store. Two mutually exclusive modes:
Expand Down Expand Up @@ -196,6 +229,12 @@ miden-bench deploy --maps 3
- `-r, --reads <N>` - Maximum storage reads per transaction. When total entries exceed this limit, reads are split across multiple transactions per benchmark iteration. Each iteration's time is the sum across all transactions. When omitted, all entries are read in a single transaction.
- `-i, --iterations <N>` - Number of benchmark iterations (default: 5)

#### Store

- `--notes <N[,N...]>` - Note counts to sweep over (default: `1000,10000`)
- `--accounts <M[,M...]>` - Account counts to sweep over (default: `100,1000`)
- `-i, --iterations <N>` - Number of benchmark iterations per measurement (default: 5)

#### Import

Exactly one of the following must be provided:
Expand Down
1 change: 1 addition & 0 deletions bin/miden-bench/src/benchmarks/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
pub mod store;
pub mod transaction;
Loading