Skip to content

feat(discovery-core): add batch iviews methods and outgoing channel support - #457

Merged
m-kus merged 1 commit into
mainfrom
pr-split/03-iviews-extensions
Feb 11, 2026
Merged

m-kus merged 1 commit into
mainfrom
pr-split/03-iviews-extensions

Conversation

@m-kus

@m-kus m-kus commented Feb 9, 2026 •

Copy link
Copy Markdown

TL;DR

Added support for batch operations and outgoing channel information to the privacy pool implementation.

What changed?

  • Added a new EncOutgoingChannelInfo struct to represent encrypted outgoing channel information
  • Implemented a new method get_outgoing_channel_info to retrieve outgoing channel data
  • Added batch operations to efficiently retrieve multiple items in a single call:
    • get_channel_info_batch: Retrieves multiple channel infos in one call
    • get_notes_batch: Retrieves multiple note values in one call
    • get_public_keys_batch: Retrieves multiple public keys in one call
    • get_note_and_nullifier_batch: Retrieves both note amounts and nullifier existence in one call
  • Added validation to ensure the correct number of slots are returned from storage operations
  • Added a new SlotCountMismatch error type to handle cases where the wrong number of slots are returned

This change is Reviewable

m-kus commented Feb 9, 2026 •

Copy link
Copy Markdown
Author

@Yoni-Starkware Yoni-Starkware left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Yoni-Starkware reviewed 1 file and all commit messages, and made 1 comment.
Reviewable status: 1 of 3 files reviewed, 1 unresolved discussion (waiting on @m-kus).


crates/discovery-core/src/storage_backend.rs line 43 at r1 (raw file):

    ///
    /// The returned `Vec` must have the same length as `slots`.
    async fn read_slots(&self, slots: Vec<Felt>) -> Result<Vec<Felt>, StorageError>;

Consider this

Suggestion:

}

/// Low-level storage access for reading raw storage slots.
#[async_trait]
pub trait RawStorageAccess: Send + Sync {
    /// Reads a single storage slot.
    async fn read_slot(&self, slot: Felt) -> Result<Felt, StorageError>;

    /// Reads multiple storage slots.
    async fn read_slots<const N: usize>(&self, slots: [Felt; N]) -> Result<[Felt; N], StorageError>;

@Yoni-Starkware Yoni-Starkware left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Yoni-Starkware made 2 comments.
Reviewable status: 1 of 3 files reviewed, 3 unresolved discussions (waiting on @m-kus).


crates/discovery-core/src/privacy_pool/views.rs line 86 at r1 (raw file):

        nullifiers: &[Felt],
    ) -> Result<(Vec<Felt>, Vec<bool>), StorageError>;
}

WDYT about setting a default impl in this trait for all non-batch funcs to call their batch variant with count=1?

Code quote:

    /// Batch-reads channel info for `count` consecutive channels starting at `start_index`.
    ///
    /// Returns a `Vec<EncChannelInfo>` of length `count`, fetched in a single `read_slots` call.
    async fn get_channel_info_batch(
        &self,
        recipient_addr: Felt,
        start_index: u64,
        count: usize,
    ) -> Result<Vec<EncChannelInfo>, StorageError>;

    /// Batch-reads packed note values for the given note IDs.
    ///
    /// Returns a `Vec<Felt>` matching the input length. Zero = note doesn't exist.
    async fn get_notes_batch(&self, note_ids: &[Felt]) -> Result<Vec<Felt>, StorageError>;

    /// Batch-reads public keys for the given addresses.
    ///
    /// Returns a `Vec<Felt>` matching the input length. Zero = unregistered.
    async fn get_public_keys_batch(&self, addrs: &[Felt]) -> Result<Vec<Felt>, StorageError>;

    /// Batch-reads packed note amounts and nullifier existence.
    ///
    /// Returns `(packed_amounts, nullifier_exists)`.
    /// Both vectors match the lengths of their respective inputs.
    async fn get_note_and_nullifier_batch(
        &self,
        note_ids: &[Felt],
        nullifiers: &[Felt],
    ) -> Result<(Vec<Felt>, Vec<bool>), StorageError>;
}

crates/discovery-core/src/privacy_pool/views.rs line 169 at r1 (raw file):

        let slots = storage_slots::outgoing_channels(outgoing_channel_id);
        let values = self
            .read_slots(vec![slots.salt, slots.enc_recipient_addr])

A bit weird that you unpack the slots struct here. That's another place to fix if the format changes.
Consider returning an array, or doing this unpacking through some into/to_vec method of this struct.

Code quote:

        let slots = storage_slots::outgoing_channels(outgoing_channel_id);
        let values = self
            .read_slots(vec![slots.salt, slots.enc_recipient_addr])

@m-kus
m-kus force-pushed the pr-split/02-hash-primitives branch from 2fc4a74 to b444378 Compare February 11, 2026 13:05
@m-kus
m-kus force-pushed the pr-split/03-iviews-extensions branch from 2a6b820 to 52e1fa9 Compare February 11, 2026 13:05
@m-kus
m-kus changed the base branch from pr-split/02-hash-primitives to graphite-base/457 February 11, 2026 14:34
@m-kus
m-kus force-pushed the pr-split/03-iviews-extensions branch from 52e1fa9 to 64df6c3 Compare February 11, 2026 15:03
@m-kus
m-kus force-pushed the graphite-base/457 branch from b444378 to ec15ebd Compare February 11, 2026 15:03
@m-kus
m-kus changed the base branch from graphite-base/457 to pr-split/02-hash-primitives February 11, 2026 15:03

@m-kus m-kus left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-kus made 2 comments and resolved 1 discussion.
Reviewable status: 1 of 4 files reviewed, 2 unresolved discussions (waiting on @Yoni-Starkware).


crates/discovery-core/src/storage_backend.rs line 43 at r1 (raw file):

Previously, Yoni-Starkware (Yoni) wrote…

Consider this

batch size is dynamic, we don't know it in advance


crates/discovery-core/src/privacy_pool/views.rs line 86 at r1 (raw file):

Previously, Yoni-Starkware (Yoni) wrote…

WDYT about setting a default impl in this trait for all non-batch funcs to call their batch variant with count=1?

Done.

@Yoni-Starkware Yoni-Starkware left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Yoni-Starkware reviewed 2 files and all commit messages, made 2 comments, and resolved 2 discussions.
Reviewable status: 3 of 4 files reviewed, 1 unresolved discussion (waiting on @m-kus).


crates/discovery-core/src/storage_backend.rs line 43 at r1 (raw file):

Previously, m-kus (Michael Zaikin) wrote…

batch size is dynamic, we don't know it in advance

:(


crates/discovery-core/src/privacy_pool/views.rs line 178 at r2 (raw file):

    #[tracing::instrument(name = "get_note", level = "debug", skip(self))]
    async fn get_note(&self, note_id: Felt) -> Result<Felt, StorageError> {

Delete the non-batch impls

Code quote:

   async fn get_note(&self, note_id: Felt) -> Result<Felt, StorageError> {

@Yoni-Starkware Yoni-Starkware left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@Yoni-Starkware made 3 comments.
Reviewable status: 3 of 4 files reviewed, 2 unresolved discussions (waiting on @m-kus).


crates/discovery-core/src/privacy_pool/views.rs line 178 at r2 (raw file):

Previously, Yoni-Starkware (Yoni) wrote…

Delete the non-batch impls

.


crates/discovery-core/src/privacy_pool/views.rs line 290 at r2 (raw file):

        let values = self.read_slots(slots).await?;
        check_slots_len(&values, nullifiers.len())?;
        Ok(values.iter().map(|v| *v != Felt::ZERO).collect())

read_slots guarantees the output length. No need to check again if you don't need to load into a struct

Suggestion:

    async fn get_notes_batch(&self, note_ids: &[Felt]) -> Result<Vec<Felt>, StorageError> {
        let slots: Vec<_> = note_ids
            .iter()
            .map(|&nid| storage_slots::notes(nid))
            .collect();
        let values = self.read_slots(slots).await?;
        Ok(values)
    }

    #[tracing::instrument(
        name = "get_public_keys_batch",
        level = "debug",
        skip(self, addrs),
        fields(count = addrs.len())
    )]
    async fn get_public_keys_batch(&self, addrs: &[Felt]) -> Result<Vec<Felt>, StorageError> {
        let slots: Vec<_> = addrs
            .iter()
            .map(|&addr| storage_slots::public_key(addr))
            .collect();
        let values = self.read_slots(slots).await?;
        Ok(values)
    }

    #[tracing::instrument(
        name = "nullifier_exists_batch",
        level = "debug",
        skip(self, nullifiers),
        fields(count = nullifiers.len())
    )]
    async fn nullifier_exists_batch(&self, nullifiers: &[Felt]) -> Result<Vec<bool>, StorageError> {
        let slots: Vec<_> = nullifiers
            .iter()
            .map(|&nul| storage_slots::nullifiers(nul))
            .collect();
        let values = self.read_slots(slots).await?;
        Ok(values.iter().map(|v| *v != Felt::ZERO).collect())

@Yoni-Starkware Yoni-Starkware left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Yoni-Starkware reviewed 1 file.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on @m-kus).

@m-kus
m-kus changed the base branch from pr-split/02-hash-primitives to graphite-base/457 February 11, 2026 18:36
@m-kus
m-kus force-pushed the graphite-base/457 branch from f2a60f2 to 269dbcc Compare February 11, 2026 18:55
@m-kus
m-kus force-pushed the pr-split/03-iviews-extensions branch from 4ddeb8f to 3a3512a Compare February 11, 2026 18:55
@m-kus
m-kus changed the base branch from graphite-base/457 to main February 11, 2026 18:55

@m-kus m-kus left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m-kus resolved 2 discussions.
Reviewable status: 2 of 4 files reviewed, all discussions resolved (waiting on @Yoni-Starkware).

@m-kus
m-kus force-pushed the pr-split/03-iviews-extensions branch from 3a3512a to 3e9392f Compare February 11, 2026 18:56
@m-kus
m-kus merged commit 6c1f8aa into main Feb 11, 2026
5 of 6 checks passed
@m-kus
m-kus deleted the pr-split/03-iviews-extensions branch February 11, 2026 18:59
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.

2 participants