Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
- Remove the cyclic database optimization ([#1497](https://github.com/0xMiden/miden-node/pull/1497)).
- Fix race condition at DB shutdown in tests ([#1503](https://github.com/0xMiden/miden-node/pull/1503)).
- [BREAKING] Updated to new miden-base protocol: removed `aux` and `execution_hint` from `NoteMetadata`, removed `NoteExecutionMode`, and `NoteMetadata::new()` is now infallible ([#1526](https://github.com/0xMiden/miden-node/pull/1526)).
- [BREAKING] Network note queries now use full account ID instead of 30-bit prefix ([#1572](https://github.com/0xMiden/miden-node/pull/1572)).

### Fixes

Expand Down
2 changes: 1 addition & 1 deletion crates/ntx-builder/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl StoreClient {
let req = proto::store::UnconsumedNetworkNotesRequest {
page_token,
page_size: PAGE_SIZE,
network_account_id_prefix: network_account_id.prefix(),
account_id: Some(network_account_id.inner().into()),
block_num,
};
let resp = store_client.get_unconsumed_network_notes(req).await?.into_inner();
Expand Down
8 changes: 4 additions & 4 deletions crates/proto/src/generated/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ pub struct MaybeAccountDetails {
/// Returns a paginated list of unconsumed network notes for an account.
///
/// Notes created or consumed after the specified block are excluded from the result.
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
pub struct UnconsumedNetworkNotesRequest {
/// This should be null on the first call, and set to the response token until the response token
/// is null, at which point all data has been fetched.
Expand All @@ -179,9 +179,9 @@ pub struct UnconsumedNetworkNotesRequest {
/// Number of notes to retrieve per page.
#[prost(uint64, tag = "2")]
pub page_size: u64,
/// The network account ID prefix to filter notes by.
#[prost(uint32, tag = "3")]
pub network_account_id_prefix: u32,
/// The full account ID to filter notes by.
#[prost(message, optional, tag = "3")]
pub account_id: ::core::option::Option<super::account::AccountId>,
/// The block number to filter the returned notes by.
///
/// Notes that are created or consumed after this block are excluded from the result.
Expand Down
3 changes: 2 additions & 1 deletion crates/store/src/db/migrations/2025062000000_setup/up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ CREATE TABLE notes (
sender BLOB NOT NULL,
tag INTEGER NOT NULL,
network_note_type INTEGER NOT NULL, -- 0-not a network note, 1-single account target network note
target_account_id BLOB, -- Full target account ID for single-target network notes
attachment BLOB NOT NULL, -- Serialized note attachment data
inclusion_path BLOB NOT NULL, -- Serialized sparse Merkle path of the note in the block's note tree
consumed_at INTEGER, -- Block number when the note was consumed
Expand All @@ -74,7 +75,7 @@ CREATE INDEX idx_notes_note_commitment ON notes(note_commitment);
CREATE INDEX idx_notes_sender ON notes(sender, committed_at);
CREATE INDEX idx_notes_tag ON notes(tag, committed_at);
CREATE INDEX idx_notes_nullifier ON notes(nullifier);
CREATE INDEX idx_unconsumed_network_notes ON notes(network_note_type, consumed_at);
CREATE INDEX idx_notes_target_account ON notes(target_account_id, committed_at) WHERE target_account_id IS NOT NULL;
-- Index for joining with block_headers on committed_at
CREATE INDEX idx_notes_committed_at ON notes(committed_at);
-- Index for joining with note_scripts
Expand Down
12 changes: 3 additions & 9 deletions crates/store/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,19 +652,13 @@ impl Db {
/// Pagination is used to limit the number of notes returned.
pub(crate) async fn select_unconsumed_network_notes(
&self,
network_account_prefix: u32,
account_id: AccountId,
block_num: BlockNumber,
page: Page,
) -> Result<(Vec<NoteRecord>, Page)> {
// Single-target network notes have their tags derived from the target account ID.
// The 30-bit account ID prefix is used as the note tag, allowing us to query notes
// for a given network account.
self.transact("unconsumed network notes for account", move |conn| {
models::queries::select_unconsumed_network_notes_by_tag(
conn,
network_account_prefix,
block_num,
page,
models::queries::select_unconsumed_network_notes_by_account_id(
conn, account_id, block_num, page,
)
})
.await
Expand Down
21 changes: 12 additions & 9 deletions crates/store/src/db/models/queries/notes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ pub(crate) fn select_note_script_by_root(
/// FROM notes
/// LEFT JOIN note_scripts ON notes.script_root = note_scripts.script_root
/// WHERE
/// network_note_type = 1 AND tag = ?1 AND
/// network_note_type = 1 AND target_account_id = ?1 AND
/// committed_at <= ?2 AND
/// (consumed_at IS NULL OR consumed_at > ?2) AND notes.rowid >= ?3
/// ORDER BY notes.rowid ASC
Expand All @@ -449,9 +449,9 @@ pub(crate) fn select_note_script_by_root(
clippy::too_many_lines,
reason = "Lines will be reduced when schema is updated to simplify logic"
)]
pub(crate) fn select_unconsumed_network_notes_by_tag(
pub(crate) fn select_unconsumed_network_notes_by_account_id(
conn: &mut SqliteConnection,
tag: u32,
account_id: AccountId,
block_num: BlockNumber,
mut page: Page,
) -> Result<(Vec<NoteRecord>, Page), DatabaseError> {
Expand Down Expand Up @@ -494,7 +494,7 @@ pub(crate) fn select_unconsumed_network_notes_by_tag(
),
)
.filter(schema::notes::network_note_type.eq(i32::from(NetworkNoteType::SingleTarget)))
.filter(schema::notes::tag.eq(tag as i32))
.filter(schema::notes::target_account_id.eq(Some(account_id.to_bytes())))
.filter(schema::notes::committed_at.le(block_num.to_raw_sql()))
.filter(
schema::notes::consumed_at
Expand Down Expand Up @@ -861,22 +861,24 @@ pub struct NoteInsertRow {
pub sender: Vec<u8>, // AccountId
pub tag: i32,

pub network_note_type: i32,
pub target_account_id: Option<Vec<u8>>,
pub attachment: Vec<u8>,
pub inclusion_path: Vec<u8>,
pub consumed_at: Option<i64>,
pub nullifier: Option<Vec<u8>>,
pub assets: Option<Vec<u8>>,
pub inputs: Option<Vec<u8>>,
pub serial_num: Option<Vec<u8>>,
pub nullifier: Option<Vec<u8>>,
pub script_root: Option<Vec<u8>>,
pub network_note_type: i32,
pub inclusion_path: Vec<u8>,
pub serial_num: Option<Vec<u8>>,
}

impl From<(NoteRecord, Option<Nullifier>)> for NoteInsertRow {
fn from((note, nullifier): (NoteRecord, Option<Nullifier>)) -> Self {
let attachment = note.metadata.attachment();

let network_note_type = if NetworkAccountTarget::try_from(attachment).is_ok() {
let target_account_id = NetworkAccountTarget::try_from(attachment).ok();
let network_note_type = if target_account_id.is_some() {
NetworkNoteType::SingleTarget
} else {
NetworkNoteType::None
Expand All @@ -894,6 +896,7 @@ impl From<(NoteRecord, Option<Nullifier>)> for NoteInsertRow {
sender: note.metadata.sender().to_bytes(),
tag: note.metadata.tag().to_raw_sql(),
network_note_type: network_note_type.into(),
target_account_id: target_account_id.map(|t| t.target_id().to_bytes()),
attachment: attachment_bytes,
inclusion_path: note.inclusion_path.to_bytes(),
consumed_at: None::<i64>, // New notes are always unconsumed.
Expand Down
1 change: 1 addition & 0 deletions crates/store/src/db/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ diesel::table! {
sender -> Binary,
tag -> Integer,
network_note_type -> Integer,
target_account_id -> Nullable<Binary>,
attachment -> Binary,
inclusion_path -> Binary,
consumed_at -> Nullable<BigInt>,
Expand Down
12 changes: 6 additions & 6 deletions crates/store/src/db/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,9 +393,9 @@ fn sql_unconsumed_network_notes() {

// Both notes are unconsumed, query should return both notes on both blocks.
(0..2).for_each(|i: u32| {
let (result, _) = queries::select_unconsumed_network_notes_by_tag(
let (result, _) = queries::select_unconsumed_network_notes_by_account_id(
&mut conn,
NoteTag::with_account_target(account_note.0).into(),
account_note.0,
i.into(),
Page {
token: None,
Expand All @@ -410,9 +410,9 @@ fn sql_unconsumed_network_notes() {
queries::insert_nullifiers_for_block(&mut conn, &[notes[1].1.unwrap()], 1.into()).unwrap();

// Query against first block should return both notes.
let (result, _) = queries::select_unconsumed_network_notes_by_tag(
let (result, _) = queries::select_unconsumed_network_notes_by_account_id(
&mut conn,
NoteTag::with_account_target(account_note.0).into(),
account_note.0,
0.into(),
Page {
token: None,
Expand All @@ -423,9 +423,9 @@ fn sql_unconsumed_network_notes() {
assert_eq!(result.len(), 2);

// Query against second block should return only first note.
let (result, _) = queries::select_unconsumed_network_notes_by_tag(
let (result, _) = queries::select_unconsumed_network_notes_by_account_id(
&mut conn,
NoteTag::with_account_target(account_note.0).into(),
account_note.0,
1.into(),
Page {
token: None,
Expand Down
7 changes: 2 additions & 5 deletions crates/store/src/server/ntx_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,7 @@ impl ntx_builder_server::NtxBuilder for StoreApi {
) -> Result<Response<proto::store::UnconsumedNetworkNotes>, Status> {
let request = request.into_inner();
let block_num = BlockNumber::from(request.block_num);
let network_account_prefix =
validate_network_account_prefix(request.network_account_id_prefix).map_err(|err| {
invalid_argument(err.as_report_context("invalid network_account_id_prefix"))
})?;
let account_id = read_account_id::<Status>(request.account_id)?;

let state = self.state.clone();

Expand All @@ -112,7 +109,7 @@ impl ntx_builder_server::NtxBuilder for StoreApi {
// TODO: no need to get the whole NoteRecord here, a NetworkNote wrapper should be created
// instead
let (notes, next_page) = state
.get_unconsumed_network_notes_for_account(network_account_prefix, block_num, page)
.get_unconsumed_network_notes_for_account(account_id, block_num, page)
.await
.map_err(internal_error)?;

Expand Down
6 changes: 2 additions & 4 deletions crates/store/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1228,13 +1228,11 @@ impl State {
/// along with the next pagination token.
pub async fn get_unconsumed_network_notes_for_account(
&self,
network_account_prefix: u32,
account_id: AccountId,
block_num: BlockNumber,
page: Page,
) -> Result<(Vec<NoteRecord>, Page), DatabaseError> {
self.db
.select_unconsumed_network_notes(network_account_prefix, block_num, page)
.await
self.db.select_unconsumed_network_notes(account_id, block_num, page).await
}

/// Returns the script for a note by its root.
Expand Down
4 changes: 2 additions & 2 deletions proto/proto/internal/store.proto
Original file line number Diff line number Diff line change
Expand Up @@ -308,8 +308,8 @@ message UnconsumedNetworkNotesRequest {
// Number of notes to retrieve per page.
uint64 page_size = 2;

// The network account ID prefix to filter notes by.
uint32 network_account_id_prefix = 3;
// The full account ID to filter notes by.
account.AccountId account_id = 3;

// The block number to filter the returned notes by.
//
Expand Down