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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

- [BREAKING] Updated minimum Rust version to 1.84.
- [BREAKING] `Endpoint` configuration simplified to a single string (#654).
- [BREAKING] `CheckNullifiersByPrefix` now takes a starting block number (#707).
- [BREAKING] Removed nullifiers from `SyncState` endpoint (#708).

### Enhancements

Expand Down
9 changes: 4 additions & 5 deletions crates/proto/src/generated/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ pub struct CheckNullifiersByPrefixRequest {
/// to `prefix_len`.
#[prost(uint32, repeated, tag = "2")]
pub nullifiers: ::prost::alloc::vec::Vec<u32>,
/// Block number from which the nullifiers are requested (inclusive).
#[prost(fixed32, tag = "3")]
pub block_num: u32,
}
/// Returns a nullifier proof for each of the requested nullifiers.
#[derive(Clone, PartialEq, ::prost::Message)]
Expand All @@ -42,7 +45,7 @@ pub struct GetBlockHeaderByNumberRequest {
///
/// Specifies state updates the client is interested in. The server will return the first block which
/// contains a note matching `note_tags` or the chain tip. And the corresponding updates to
/// `nullifiers` and `account_ids` for that block range.
/// `account_ids` for that block range.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SyncStateRequest {
/// Last block known by the client. The response will contain data starting from the next block,
Expand All @@ -60,10 +63,6 @@ pub struct SyncStateRequest {
/// Specifies the tags which the client is interested in.
#[prost(fixed32, repeated, tag = "3")]
pub note_tags: ::prost::alloc::vec::Vec<u32>,
/// Determines the nullifiers the client is interested in by specifying the 16high bits of the
/// target nullifier.
#[prost(uint32, repeated, tag = "4")]
pub nullifiers: ::prost::alloc::vec::Vec<u32>,
}
/// Note synchronization request.
///
Expand Down
3 changes: 0 additions & 3 deletions crates/proto/src/generated/responses.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,6 @@ pub struct SyncStateResponse {
/// List of all notes together with the Merkle paths from `response.block_header.note_root`.
#[prost(message, repeated, tag = "7")]
pub notes: ::prost::alloc::vec::Vec<super::note::NoteSyncRecord>,
/// List of nullifiers created between `request.block_num + 1` and `response.block_header.block_num`.
#[prost(message, repeated, tag = "8")]
pub nullifiers: ::prost::alloc::vec::Vec<NullifierUpdate>,
}
/// Represents the result of syncing notes request.
#[derive(Clone, PartialEq, ::prost::Message)]
Expand Down
16 changes: 8 additions & 8 deletions crates/proto/src/generated/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,19 +353,19 @@ pub mod api_client {
self.inner.unary(req, path, codec).await
}
/// Returns info which can be used by the client to sync up to the latest state of the chain
/// for the objects (accounts, notes, nullifiers) the client is interested in.
/// for the objects (accounts and notes) the client is interested in.
///
/// This request returns the next block containing requested data. It also returns `chain_tip`
/// which is the latest block number in the chain. Client is expected to repeat these requests
/// in a loop until `response.block_header.block_num == response.chain_tip`, at which point
/// the client is fully synchronized with the chain.
///
/// Each request also returns info about new notes, nullifiers etc. created. It also returns
/// Each update response also contains info about new notes, accounts etc. created. It also returns
/// Chain MMR delta that can be used to update the state of Chain MMR. This includes both chain
/// MMR peaks and chain MMR nodes.
///
/// For preserving some degree of privacy, note tags and nullifiers filters contain only high
/// part of hashes. Thus, returned data contains excessive notes and nullifiers, client can make
/// For preserving some degree of privacy, note tags contain only high
/// part of hashes. Thus, returned data contains excessive notes, client can make
/// additional filtering of that data on its side.
pub async fn sync_state(
&mut self,
Expand Down Expand Up @@ -502,19 +502,19 @@ pub mod api_server {
tonic::Status,
>;
/// Returns info which can be used by the client to sync up to the latest state of the chain
/// for the objects (accounts, notes, nullifiers) the client is interested in.
/// for the objects (accounts and notes) the client is interested in.
///
/// This request returns the next block containing requested data. It also returns `chain_tip`
/// which is the latest block number in the chain. Client is expected to repeat these requests
/// in a loop until `response.block_header.block_num == response.chain_tip`, at which point
/// the client is fully synchronized with the chain.
///
/// Each request also returns info about new notes, nullifiers etc. created. It also returns
/// Each update response also contains info about new notes, accounts etc. created. It also returns
/// Chain MMR delta that can be used to update the state of Chain MMR. This includes both chain
/// MMR peaks and chain MMR nodes.
///
/// For preserving some degree of privacy, note tags and nullifiers filters contain only high
/// part of hashes. Thus, returned data contains excessive notes and nullifiers, client can make
/// For preserving some degree of privacy, note tags contain only high
/// part of hashes. Thus, returned data contains excessive notes, client can make
/// additional filtering of that data on its side.
async fn sync_state(
&self,
Expand Down
8 changes: 3 additions & 5 deletions crates/rpc-proto/proto/requests.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ message CheckNullifiersByPrefixRequest {
// List of nullifiers to check. Each nullifier is specified by its prefix with length equal
// to `prefix_len`.
repeated uint32 nullifiers = 2;
// Block number from which the nullifiers are requested (inclusive).
fixed32 block_num = 3;
}

// Returns a nullifier proof for each of the requested nullifiers.
Expand All @@ -41,7 +43,7 @@ message GetBlockHeaderByNumberRequest {
//
// Specifies state updates the client is interested in. The server will return the first block which
// contains a note matching `note_tags` or the chain tip. And the corresponding updates to
// `nullifiers` and `account_ids` for that block range.
// `account_ids` for that block range.
message SyncStateRequest {
// Last block known by the client. The response will contain data starting from the next block,
// until the first block which contains a note of matching the requested tag, or the chain tip
Expand All @@ -57,10 +59,6 @@ message SyncStateRequest {

// Specifies the tags which the client is interested in.
repeated fixed32 note_tags = 3;

// Determines the nullifiers the client is interested in by specifying the 16high bits of the
// target nullifier.
repeated uint32 nullifiers = 4;
}

// Note synchronization request.
Expand Down
3 changes: 0 additions & 3 deletions crates/rpc-proto/proto/responses.proto
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ message SyncStateResponse {

// List of all notes together with the Merkle paths from `response.block_header.note_root`.
repeated note.NoteSyncRecord notes = 7;

// List of nullifiers created between `request.block_num + 1` and `response.block_header.block_num`.
repeated NullifierUpdate nullifiers = 8;
}

// Represents the result of syncing notes request.
Expand Down
8 changes: 4 additions & 4 deletions crates/rpc-proto/proto/rpc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ service Api {
rpc SyncNotes(requests.SyncNoteRequest) returns (responses.SyncNoteResponse) {}

// Returns info which can be used by the client to sync up to the latest state of the chain
// for the objects (accounts, notes, nullifiers) the client is interested in.
// for the objects (accounts and notes) the client is interested in.
//
// This request returns the next block containing requested data. It also returns `chain_tip`
// which is the latest block number in the chain. Client is expected to repeat these requests
// in a loop until `response.block_header.block_num == response.chain_tip`, at which point
// the client is fully synchronized with the chain.
//
// Each request also returns info about new notes, nullifiers etc. created. It also returns
// Each update response also contains info about new notes, accounts etc. created. It also returns
// Chain MMR delta that can be used to update the state of Chain MMR. This includes both chain
// MMR peaks and chain MMR nodes.
//
// For preserving some degree of privacy, note tags and nullifiers filters contain only high
// part of hashes. Thus, returned data contains excessive notes and nullifiers, client can make
// For preserving some degree of privacy, note tags contain only high
// part of hashes. Thus, returned data contains excessive notes, client can make
// additional filtering of that data on its side.
rpc SyncState(requests.SyncStateRequest) returns (responses.SyncStateResponse) {}
}
14 changes: 7 additions & 7 deletions crates/rpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ Returns a nullifier proof for each of the requested nullifiers.

### CheckNullifiersByPrefix

Returns a list of nullifiers that match the specified prefixes and are recorded in the node.
Returns a list of nullifiers recorded in the node that match the specified prefixes and were created at or after
the given block height.

Only 16-bit prefixes are supported at this time.

Expand Down Expand Up @@ -102,19 +103,18 @@ the chain.

### SyncState

Returns info which can be used by the client to sync up to the latest state of the chain for the objects (accounts,
notes, nullifiers) the client is interested in.
Returns info which can be used by the client to sync up to the latest state of the chain for the objects (accounts and
notes) the client is interested in.

This request returns the next block containing requested data. It also returns `chain_tip` which is the latest block
number in the chain. Client is expected to repeat these requests in a loop until
`response.block_header.block_num == response.chain_tip`, at which point the client is fully synchronized with the chain.

Each request also returns info about new notes, nullifiers etc. created. It also returns Chain MMR delta that can be
Each request also returns info about new notes, accounts, etc. created. It also returns Chain MMR delta that can be
used to update the state of Chain MMR. This includes both chain MMR peaks and chain MMR nodes.

For preserving some degree of privacy, note tags and nullifiers filters contain only high part of hashes. Thus, returned
data contains excessive notes and nullifiers, client can make additional filtering of that data on its side.

For preserving some degree of privacy, note tags contain only high part of hashes. Thus, returned data contains excessive
notes, client can make additional filtering of that data on its side.
---

## License
Expand Down
9 changes: 3 additions & 6 deletions crates/store/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ pub struct StateSyncUpdate {
pub block_header: BlockHeader,
pub account_updates: Vec<AccountSummary>,
pub transactions: Vec<TransactionSummary>,
pub nullifiers: Vec<NullifierInfo>,
}

#[derive(Debug, PartialEq)]
Expand Down Expand Up @@ -215,12 +214,13 @@ impl Db {
&self,
prefix_len: u32,
nullifier_prefixes: Vec<u32>,
block_num: BlockNumber,
) -> Result<Vec<NullifierInfo>> {
self.pool
.get()
.await?
.interact(move |conn| {
sql::select_nullifiers_by_prefix(conn, prefix_len, &nullifier_prefixes)
sql::select_nullifiers_by_prefix(conn, prefix_len, &nullifier_prefixes, block_num)
})
.await
.map_err(|err| {
Expand Down Expand Up @@ -327,15 +327,12 @@ impl Db {
block_num: BlockNumber,
account_ids: Vec<AccountId>,
note_tags: Vec<u32>,
nullifier_prefixes: Vec<u32>,
) -> Result<StateSyncUpdate, StateSyncError> {
self.pool
.get()
.await
.map_err(DatabaseError::MissingDbConnection)?
.interact(move |conn| {
sql::get_state_sync(conn, block_num, &account_ids, &note_tags, &nullifier_prefixes)
})
.interact(move |conn| sql::get_state_sync(conn, block_num, &account_ids, &note_tags))
.await
.map_err(|err| {
DatabaseError::InteractError(format!("Get state sync task failed: {err}"))
Expand Down
67 changes: 5 additions & 62 deletions crates/store/src/db/sql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,56 +617,7 @@ pub fn select_all_nullifiers(conn: &mut Connection) -> Result<Vec<(Nullifier, Bl
Ok(result)
}

/// Select nullifiers created between `(block_start, block_end]` that also match the
/// `nullifier_prefixes` filter using the given [Connection].
///
/// Each value of the `nullifier_prefixes` is only the 16 most significant bits of the nullifier of
/// interest to the client. This hides the details of the specific nullifier being requested.
///
/// # Returns
///
/// A vector of [`NullifierInfo`] with the nullifiers and the block height at which they were
/// created, or an error.
pub fn select_nullifiers_by_block_range(
conn: &mut Connection,
block_start: BlockNumber,
block_end: BlockNumber,
nullifier_prefixes: &[u32],
) -> Result<Vec<NullifierInfo>> {
let nullifier_prefixes: Vec<Value> =
nullifier_prefixes.iter().copied().map(Into::into).collect();

let mut stmt = conn.prepare_cached(
"
SELECT
nullifier,
block_num
FROM
nullifiers
WHERE
block_num > ?1 AND
block_num <= ?2 AND
nullifier_prefix IN rarray(?3)
ORDER BY
block_num ASC
",
)?;

let mut rows =
stmt.query(params![block_start.as_u32(), block_end.as_u32(), Rc::new(nullifier_prefixes)])?;

let mut result = Vec::new();
while let Some(row) = rows.next()? {
let nullifier_data = row.get_ref(0)?.as_blob()?;
let nullifier = Nullifier::read_from_bytes(nullifier_data)?;
let block_num: u32 = row.get(1)?;
result.push(NullifierInfo { nullifier, block_num: block_num.into() });
}
Ok(result)
}

/// Select nullifiers created that match the `nullifier_prefixes` filter using the given
/// [Connection].
/// Returns nullifiers filtered by prefix and block creation height.
///
/// Each value of the `nullifier_prefixes` is only the `prefix_len` most significant bits
/// of the nullifier of interest to the client. This hides the details of the specific
Expand All @@ -680,6 +631,7 @@ pub fn select_nullifiers_by_prefix(
conn: &mut Connection,
prefix_len: u32,
nullifier_prefixes: &[u32],
block_num: BlockNumber,
) -> Result<Vec<NullifierInfo>> {
assert_eq!(prefix_len, 16, "Only 16-bit prefixes are supported");

Expand All @@ -694,13 +646,13 @@ pub fn select_nullifiers_by_prefix(
FROM
nullifiers
WHERE
nullifier_prefix IN rarray(?1)
nullifier_prefix IN rarray(?1) AND
block_num >= ?2
ORDER BY
block_num ASC
",
)?;

let mut rows = stmt.query(params![Rc::new(nullifier_prefixes)])?;
let mut rows = stmt.query(params![Rc::new(nullifier_prefixes), block_num.as_u32()])?;

let mut result = Vec::new();
while let Some(row) = rows.next()? {
Expand Down Expand Up @@ -1195,7 +1147,6 @@ pub fn get_state_sync(
block_num: BlockNumber,
account_ids: &[AccountId],
note_tag_prefixes: &[u32],
nullifier_prefixes: &[u32],
) -> Result<StateSyncUpdate, StateSyncError> {
let notes = select_notes_since_block_by_tag_and_sender(
conn,
Expand All @@ -1218,19 +1169,11 @@ pub fn get_state_sync(
account_ids,
)?;

let nullifiers = select_nullifiers_by_block_range(
conn,
block_num,
block_header.block_num(),
nullifier_prefixes,
)?;

Ok(StateSyncUpdate {
notes,
block_header,
account_updates,
transactions,
nullifiers,
})
}

Expand Down
Loading