Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove nullifiers from SyncState endpoint #708

1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- [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).
- [BREAKING] Changed sync state endpoint to stream the response (#685).

### Enhancements
Expand Down
6 changes: 1 addition & 5 deletions crates/proto/src/generated/requests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,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 @@ -63,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 @@ -58,9 +58,6 @@ pub struct SyncStateResponse {
/// List of all notes together with the Merkle paths from `response.block_header.note_root`.
#[prost(message, repeated, tag = "5")]
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 = "6")]
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,18 +353,18 @@ 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 a stream where multiple update responses will be pushed in order.
/// Client is expected to read the updates from the stream and apply them, and then it will be
/// fully synchronized with the chain.
///
/// Each update response also contains 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 @@ -512,18 +512,18 @@ pub mod api_server {
+ std::marker::Send
+ 'static;
/// 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 a stream where multiple update responses will be pushed in order.
/// Client is expected to read the updates from the stream and apply them, and then it will be
/// fully synchronized with the chain.
///
/// Each update response also contains 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
6 changes: 1 addition & 5 deletions crates/rpc-proto/proto/requests.proto
Original file line number Diff line number Diff line change
Expand Up @@ -43,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 @@ -59,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 @@ -63,9 +63,6 @@ message SyncStateResponse {

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

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

// 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,18 +49,18 @@ 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 a stream where multiple update responses will be pushed in order.
// Client is expected to read the updates from the stream and apply them, and then it will be
// fully synchronized with the chain.
//
// Each update response also contains 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 (stream responses.SyncStateResponse) {}
}
17 changes: 8 additions & 9 deletions crates/rpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,17 @@ 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.
This request returns a stream where multiple update responses will be pushed in order. Client is expected to read
the updates from the stream and apply them, and then it will be 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
used to update the state of Chain MMR. This includes both chain MMR peaks and chain MMR nodes.
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 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.

---

Expand Down
6 changes: 1 addition & 5 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 @@ -328,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
57 changes: 0 additions & 57 deletions crates/store/src/db/sql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,54 +617,6 @@ 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)
}

/// Returns nullifiers filtered by prefix and block creation height.
///
/// Each value of the `nullifier_prefixes` is only the `prefix_len` most significant bits
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
Loading