Skip to content

store: move SyncNotes loop into the database layer#2027

Open
bigeez wants to merge 3 commits into0xMiden:nextfrom
bigeez:bigeez/move-sync-notes-loop-to-db
Open

store: move SyncNotes loop into the database layer#2027
bigeez wants to merge 3 commits into0xMiden:nextfrom
bigeez:bigeez/move-sync-notes-loop-to-db

Conversation

@bigeez
Copy link
Copy Markdown

@bigeez bigeez commented May 1, 2026

Closes #1871

Summary

Replaces the N async round-trip loop in State::sync_notes with a single get_note_sync_multi call that performs note-sync pagination inside one database transaction.

Before: sync_notes drove a loop calling get_note_sync on each iteration. Each call opened a new async transact on tokio's blocking thread pool, ran a two-stage SQL query to find the next matching block and fetch that block's notes, then returned a single block. For a response spanning N blocks this meant N blocking task dispatches.

After: State::sync_notes makes one async DB call. Inside that transaction, get_note_sync_multi repeatedly fetches the next matching block, appends it while it fits within the response payload budget, and stops before returning blocks that would exceed the cap. This preserves response pagination/backpressure while avoiding repeated async DB transactions.

Also removes the unused account_ids parameter from the note sync query path. It was always passed as &[] but threaded through the entire call chain.

Changes

  • queries::select_notes_since_block_by_tag returns notes from the next matching block in the range, ordered by block/batch/note index
  • queries::get_note_sync_multi loops within one transaction and returns Vec<NoteSyncUpdate> while respecting MAX_RESPONSE_PAYLOAD_BYTES
  • Db::get_note_sync_multi passes the response payload cap into the transaction-level helper
  • State::sync_notes keeps the MMR-proof assembly and final payload guard
  • Tests updated for multi-block behavior, no-match semantics, and payload-cap behavior

Test plan

  • cargo test -p miden-node-store note_sync (blocked locally by miden-core-lib: project 'miden-core' is missing its manifest path)
  • note_sync_across_multiple_blocks verifies all 3 blocks are returned through one helper call
  • note_sync_multi_respects_payload_limit verifies returned blocks stop at the payload budget
  • note_sync_no_matching_tags asserts empty Vec instead of None

bigeez added 2 commits May 1, 2026 12:15
Replace the N-round-trip loop in `State::sync_notes` with a single
`get_note_sync_multi` call that returns all matching blocks in one
database transaction.

Previously each call to `get_note_sync` used a subquery to find the
minimum matching block number, returned only that block's notes, and
required the caller to loop and advance `current_from` on every
iteration. For a response spanning N blocks this meant N async
`transact` calls through tokio's blocking thread pool.

The new `select_notes_since_block_by_tag` query drops the inner
`WHERE block_num = (SELECT MIN(...))` constraint and returns all
matching notes ordered by block number. `get_note_sync_multi` then
groups them by block via a `BTreeMap` (preserving ascending order)
and fetches each block header within the same transaction. The
application layer in `sync_notes` now iterates already-fetched data
to enforce the payload cap, instead of driving repeated DB round trips.

Also removes the unused `account_ids` parameter from the note sync
query path — it was always passed as an empty slice.

Closes 0xMiden#1871
- Add missing `BTreeMap` import in notes.rs (fixes build)
- Split import group in sync_state.rs onto separate lines (fixes nightly rustfmt)
- Add changelog entry for 0xMiden#2027
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.

Move SyncNotes loop to the db

1 participant