Skip to main content

miden_client/rpc/
mod.rs

1//! Provides an interface for the client to communicate with a Miden node using
2//! Remote Procedure Calls (RPC).
3//!
4//! This module defines the [`NodeRpcClient`] trait which abstracts calls to the RPC protocol used
5//! to:
6//!
7//! - Submit proven transactions.
8//! - Submit proven batches.
9//! - Retrieve block headers (optionally with MMR proofs).
10//! - Sync state updates (including notes, nullifiers, and account updates).
11//! - Fetch details for specific notes and accounts.
12//!
13//! The client implementation adapts to the target environment automatically:
14//! - Native targets use `tonic` transport with TLS.
15//! - `wasm32` targets use `tonic-web-wasm-client` transport.
16//!
17//! ## Example
18//!
19//! ```no_run
20//! # use miden_client::rpc::{Endpoint, NodeRpcClient, GrpcClient};
21//! # use miden_protocol::block::BlockNumber;
22//! # #[tokio::main]
23//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
24//! // Create a gRPC client instance (assumes default endpoint configuration).
25//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
26//! let mut rpc_client = GrpcClient::new(&endpoint, 1000);
27//!
28//! // Fetch the latest block header (by passing None).
29//! let (block_header, mmr_proof) = rpc_client.get_block_header_by_number(None, true).await?;
30//!
31//! println!("Latest block number: {}", block_header.block_num());
32//! if let Some(proof) = mmr_proof {
33//!     println!("MMR proof received accordingly");
34//! }
35//!
36//! #    Ok(())
37//! # }
38//! ```
39//! The client also makes use of this component in order to communicate with the node.
40//!
41//! For further details and examples, see the documentation for the individual methods in the
42//! [`NodeRpcClient`] trait.
43
44use alloc::boxed::Box;
45use alloc::collections::{BTreeMap, BTreeSet};
46use alloc::string::String;
47use alloc::vec::Vec;
48use core::fmt;
49
50use domain::account::{
51    AccountDetails,
52    AccountProof,
53    GetAccountRequest,
54    StorageMapEntries,
55    StorageMapEntry,
56    StorageMapFetch,
57    VaultFetch,
58};
59use domain::note::{FetchedNote, NoteSyncBlock, SyncedNoteDetails};
60use domain::nullifier::NullifierUpdate;
61use domain::sync::{ChainMmrInfo, SyncTarget};
62use miden_protocol::Word;
63use miden_protocol::account::{Account, AccountId};
64use miden_protocol::address::NetworkId;
65use miden_protocol::batch::{ProposedBatch, ProvenBatch};
66use miden_protocol::block::{BlockHeader, BlockNumber, ProvenBlock};
67use miden_protocol::crypto::merkle::mmr::MmrProof;
68use miden_protocol::note::{NoteId, NoteMetadata, NoteScript, NoteTag, NoteType, Nullifier};
69use miden_protocol::transaction::{ProvenTransaction, TransactionInputs};
70
71use crate::rpc::domain::storage_map::StorageMapInfo;
72
73/// Contains domain types related to RPC requests and responses, as well as utility functions
74/// for dealing with them.
75pub mod domain;
76
77mod errors;
78pub use errors::*;
79
80mod endpoint;
81pub(crate) use domain::limits::RPC_LIMITS_STORE_SETTING;
82pub use domain::limits::RpcLimits;
83pub use domain::status::{NetworkNoteStatus, NetworkNoteStatusInfo, RpcStatusInfo};
84pub use endpoint::Endpoint;
85
86#[cfg(not(feature = "testing"))]
87mod generated;
88#[cfg(feature = "testing")]
89pub mod generated;
90
91#[cfg(feature = "tonic")]
92mod tonic_client;
93#[cfg(feature = "tonic")]
94pub use tonic_client::GrpcClient;
95
96use crate::rpc::domain::account_vault::AccountVaultInfo;
97use crate::rpc::domain::transaction::TransactionRecord;
98use crate::store::InputNoteRecord;
99use crate::store::input_note_states::UnverifiedNoteState;
100
101/// Represents the state that we want to retrieve from the network
102#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
103pub enum AccountStateAt {
104    /// Gets the latest state, for the current chain tip
105    #[default]
106    ChainTip,
107    /// Gets the state at a specific block number
108    Block(BlockNumber),
109}
110
111/// Returns `true` if the note's metadata advertises at least one attachment.
112///
113/// Sync records carry attachment scheme markers (not the attachment content), so a present scheme
114/// in any header slot indicates the note has attachments whose content must be fetched separately.
115fn metadata_has_attachments(metadata: &NoteMetadata) -> bool {
116    metadata.attachment_headers().iter().any(|header| header.scheme().is_some())
117}
118
119// NODE RPC CLIENT TRAIT
120// ================================================================================================
121
122/// Defines the interface for communicating with the Miden node.
123///
124/// The implementers are responsible for connecting to the Miden node, handling endpoint
125/// requests/responses, and translating responses into domain objects relevant for each of the
126/// endpoints.
127#[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)]
128#[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))]
129pub trait NodeRpcClient: Send + Sync {
130    /// Sets the genesis commitment for the client and reconnects to the node providing the
131    /// genesis commitment in the request headers. If the genesis commitment is already set,
132    /// this method does nothing.
133    async fn set_genesis_commitment(&self, commitment: Word) -> Result<(), RpcError>;
134
135    /// Returns the genesis commitment if it has been set, without fetching from the node.
136    fn has_genesis_commitment(&self) -> Option<Word>;
137
138    /// Given a Proven Transaction, send it to the node for it to be included in a future block
139    /// using the `/SubmitProvenTransaction` RPC endpoint.
140    ///
141    /// Returns the node's chain tip at submission (not the block the transaction is committed in).
142    async fn submit_proven_transaction(
143        &self,
144        proven_transaction: ProvenTransaction,
145        transaction_inputs: TransactionInputs,
146    ) -> Result<BlockNumber, RpcError>;
147
148    /// Given a Proven Batch together with the corresponding [`ProposedBatch`] and the list of
149    /// [`TransactionInputs`] (one per transaction, matching the ordering of the batch), sends
150    /// the batch to the node for inclusion in a future block using the `/SubmitProvenBatch`
151    /// RPC endpoint. All transactions in the batch must build on the current mempool state
152    /// following normal transaction submission rules.
153    ///
154    /// Returns the node's chain tip at submission (not the block the batch is committed in).
155    async fn submit_proven_batch(
156        &self,
157        proven_batch: ProvenBatch,
158        proposed_batch: ProposedBatch,
159        transaction_inputs: Vec<TransactionInputs>,
160    ) -> Result<BlockNumber, RpcError>;
161
162    /// Given a block number, fetches the block header corresponding to that height from the node
163    /// using the `/GetBlockHeaderByNumber` endpoint.
164    /// If `include_mmr_proof` is set to true and the function returns an `Ok`, the second value
165    /// of the return tuple should always be Some(MmrProof).
166    ///
167    /// When `None` is provided, returns info regarding the latest block.
168    async fn get_block_header_by_number(
169        &self,
170        block_num: Option<BlockNumber>,
171        include_mmr_proof: bool,
172    ) -> Result<(BlockHeader, Option<MmrProof>), RpcError>;
173
174    /// Given a block number, fetches the block corresponding to that height from the node using
175    /// the `/GetBlockByNumber` RPC endpoint.
176    ///
177    /// If `include_proof` is set to true, the block proof will be included in the response.
178    async fn get_block_by_number(
179        &self,
180        block_num: BlockNumber,
181        include_proof: bool,
182    ) -> Result<ProvenBlock, RpcError>;
183
184    /// Fetches note-related data for a list of [`NoteId`] using the `/GetNotesById`
185    /// RPC endpoint.
186    ///
187    /// For [`miden_protocol::note::NoteType::Private`] notes, the response includes only the
188    /// [`miden_protocol::note::NoteMetadata`].
189    ///
190    /// For [`miden_protocol::note::NoteType::Public`] notes, the response includes all note details
191    /// (recipient, assets, script, etc.).
192    ///
193    /// In both cases, a [`miden_protocol::note::NoteInclusionProof`] is returned so the caller can
194    /// verify that each note is part of the block's note tree.
195    async fn get_notes_by_id(&self, note_ids: &[NoteId]) -> Result<Vec<FetchedNote>, RpcError>;
196
197    /// Fetches the MMR delta for a given block range using the `/SyncChainMmr` RPC endpoint.
198    ///
199    /// - `current_block_height` is the last block number already present in the caller's MMR.
200    /// - `upper_bound` determines the upper bound of the sync range. Can be a specific block number
201    ///   (`BlockNumber`), or a chain tip finality level: `CommittedChainTip` syncs up to the latest
202    ///   committed block (the chain tip), while `ProvenChainTip` syncs up to the latest proven
203    ///   block which may be behind the committed tip.
204    async fn sync_chain_mmr(
205        &self,
206        current_block_height: BlockNumber,
207        upper_bound: SyncTarget,
208    ) -> Result<ChainMmrInfo, RpcError>;
209
210    /// Fetches the full state of a public account from the node using the `/GetAccount` endpoint,
211    /// and then resolves oversized vault and storage map entries via the `SyncVault` and
212    /// `SyncStorageMap` endpoints when needed.
213    ///
214    /// - `account_id` is the ID of the wanted account.
215    ///
216    /// Returns `Ok(None)` for accounts without public state.
217    async fn get_account_details(
218        &self,
219        account_id: AccountId,
220    ) -> Result<Option<Account>, RpcError> {
221        // Accounts without public state have no full state to fetch; only a commitment is on-chain.
222        if !account_id.is_public() {
223            return Ok(None);
224        }
225
226        // A single request fetches the full public state: every storage map's entries plus the
227        // vault, with the storage layout discovered server-side.
228        let (block_number, mut proof) = self
229            .get_account(
230                account_id,
231                GetAccountRequest::new()
232                    .with_storage(StorageMapFetch::All)
233                    .with_vault(VaultFetch::Always),
234            )
235            .await?;
236
237        if let Some(details) = proof.details_mut() {
238            self.resolve_oversize_vault(account_id, block_number, details).await?;
239            self.resolve_oversize_storage_maps(account_id, block_number, details).await?;
240        }
241
242        let details = proof.into_details().ok_or(RpcError::ExpectedDataMissing(
243            "public account returned without details".into(),
244        ))?;
245
246        Ok(Some(Account::try_from(&details)?))
247    }
248
249    /// Fetches notes related to the specified tags using the `/SyncNotes` RPC endpoint,
250    /// paginating over the full block range and returning, in block-number order, every block in
251    /// that range that contains at least one note matching the requested tags.
252    ///
253    /// - `block_from`: The starting block number for the range (inclusive).
254    /// - `block_to`: The ending block number for the range (inclusive).
255    /// - `note_tags` is the set of tags used to filter the notes the client is interested in.
256    ///
257    /// Notes with attachments will have header-only metadata after this call; use
258    /// [`NodeRpcClient::sync_notes_with_details`] to also resolve their full metadata and
259    /// fetch public note bodies in a single follow-up call.
260    async fn sync_notes(
261        &self,
262        block_from: BlockNumber,
263        block_to: BlockNumber,
264        note_tags: &BTreeSet<NoteTag>,
265    ) -> Result<Vec<NoteSyncBlock>, RpcError>;
266
267    /// Calls [`NodeRpcClient::sync_notes`] for the requested range, then makes a single
268    /// [`NodeRpcClient::get_notes_by_id`] call to fetch full note bodies (scripts, assets,
269    /// recipient) for public notes and attachment content for private notes that carry
270    /// attachments.
271    ///
272    /// All public notes in the range are fetched (not just the ones the client tracks) to
273    /// avoid revealing which specific notes the client is interested in. Private notes are only
274    /// fetched when their synced metadata indicates non-empty attachments, since the sync record
275    /// carries attachment scheme markers but not the attachment content, which is needed to
276    /// reconstruct the note's ID.
277    ///
278    /// Returns the resolved note blocks paired with a map of the fetched content (public note
279    /// bodies and private-note attachments), keyed by note ID.
280    async fn sync_notes_with_details(
281        &self,
282        block_from: BlockNumber,
283        block_to: BlockNumber,
284        note_tags: &BTreeSet<NoteTag>,
285    ) -> Result<(Vec<NoteSyncBlock>, BTreeMap<NoteId, SyncedNoteDetails>), RpcError> {
286        let blocks = self.sync_notes(block_from, block_to, note_tags).await?;
287
288        let note_ids: Vec<NoteId> = blocks
289            .iter()
290            .flat_map(|b| b.notes.values())
291            .filter(|n| n.note_type() == NoteType::Public || metadata_has_attachments(n.metadata()))
292            .map(|n| *n.note_id())
293            .collect();
294
295        let mut synced_notes: BTreeMap<NoteId, SyncedNoteDetails> = BTreeMap::new();
296
297        if !note_ids.is_empty() {
298            let fetched = self.get_notes_by_id(&note_ids).await?;
299
300            for fetched_note in fetched {
301                match fetched_note {
302                    FetchedNote::Public(note, _) => {
303                        synced_notes.insert(note.id(), SyncedNoteDetails::Public(note));
304                    },
305                    FetchedNote::Private(note_id, _, attachments, _) => {
306                        let attachments = (!attachments.is_empty()).then_some(attachments);
307                        synced_notes.insert(note_id, SyncedNoteDetails::Private(attachments));
308                    },
309                }
310            }
311        }
312
313        Ok((blocks, synced_notes))
314    }
315
316    /// Fetches the nullifiers corresponding to a list of prefixes using the
317    /// `/SyncNullifiers` RPC endpoint.
318    ///
319    /// - `prefix` is a list of nullifiers prefixes to search for.
320    /// - `block_from`: The starting block number for the range (inclusive).
321    /// - `block_to`: The ending block number for the range (inclusive).
322    async fn sync_nullifiers(
323        &self,
324        prefix: &[u16],
325        block_from: BlockNumber,
326        block_to: BlockNumber,
327    ) -> Result<Vec<NullifierUpdate>, RpcError>;
328
329    /// Fetches the account from the node, using the `/GetAccount` endpoint.
330    ///
331    /// The response carries an
332    /// [`AccountWitness`](miden_protocol::block::account_tree::AccountWitness) and the target
333    /// block. Public accounts additionally get [`AccountDetails`]; for private accounts the
334    /// other `request` fields are ignored.
335    ///
336    /// For a fully oversize-resolved account, use [`NodeRpcClient::get_account_details`].
337    ///
338    /// Errors if the account isn't found.
339    async fn get_account(
340        &self,
341        account_id: AccountId,
342        request: GetAccountRequest,
343    ) -> Result<(BlockNumber, AccountProof), RpcError>;
344
345    /// Fills in the asset list when the vault came back flagged `too_many_assets`, by
346    /// querying [`NodeRpcClient::sync_account_vault`] over `[GENESIS, block_to]`. No-op when
347    /// the flag isn't set.
348    async fn resolve_oversize_vault(
349        &self,
350        account_id: AccountId,
351        block_to: BlockNumber,
352        details: &mut AccountDetails,
353    ) -> Result<(), RpcError> {
354        if !details.vault_details.too_many_assets {
355            return Ok(());
356        }
357        let vault_info =
358            self.sync_account_vault(BlockNumber::GENESIS, block_to, account_id).await?;
359        let mut updates = vault_info.updates;
360        // The node returns the full history of vault entries, so a given key may appear in more
361        // than one block. Sort by block so the BTreeMap keeps the latest value per key.
362        updates.sort_by_key(|u| u.block_num);
363        details.vault_details.assets = updates
364            .into_iter()
365            .map(|u| (u.vault_key, u.asset))
366            .collect::<BTreeMap<_, _>>()
367            .into_values()
368            .flatten()
369            .collect();
370        details.vault_details.too_many_assets = false;
371        Ok(())
372    }
373
374    /// Fills in the entries of any storage map flagged `too_many_entries`, by querying
375    /// [`NodeRpcClient::sync_storage_maps`] over `[GENESIS, block_to]`. No-op when no map
376    /// has the flag set.
377    async fn resolve_oversize_storage_maps(
378        &self,
379        account_id: AccountId,
380        block_to: BlockNumber,
381        details: &mut AccountDetails,
382    ) -> Result<(), RpcError> {
383        if !details.storage_details.map_details.iter().any(|m| m.too_many_entries) {
384            return Ok(());
385        }
386        let info = self.sync_storage_maps(BlockNumber::GENESIS, block_to, account_id).await?;
387        for map_details in &mut details.storage_details.map_details {
388            if !map_details.too_many_entries {
389                continue;
390            }
391            // The node returns the full history of map entries, so a given key may appear in
392            // more than one block. Sort by block so the BTreeMap keeps the latest value per key.
393            let mut sorted: Vec<_> =
394                info.updates.iter().filter(|u| u.slot_name == map_details.slot_name).collect();
395            sorted.sort_by_key(|u| u.block_num);
396            let entries: Vec<StorageMapEntry> = sorted
397                .into_iter()
398                .map(|u| (u.key, u.value))
399                .collect::<BTreeMap<_, _>>()
400                .into_iter()
401                .map(|(key, value)| StorageMapEntry { key, value })
402                .collect();
403            map_details.too_many_entries = false;
404            map_details.entries = StorageMapEntries::AllEntries(entries);
405        }
406        Ok(())
407    }
408
409    /// Fetches the commit height where the nullifier was consumed. If the nullifier isn't found,
410    /// then `None` is returned.
411    /// The `block_num` parameter is the block number to start the search from (inclusive).
412    ///
413    /// The default implementation of this method makes two RPC requests: one to
414    /// [`NodeRpcClient::get_block_header_by_number`] to resolve the chain tip, and one to
415    /// [`NodeRpcClient::sync_nullifiers`] to search up to that tip.
416    async fn get_nullifier_commit_heights(
417        &self,
418        requested_nullifiers: BTreeSet<Nullifier>,
419        block_from: BlockNumber,
420    ) -> Result<BTreeMap<Nullifier, Option<BlockNumber>>, RpcError> {
421        let prefixes: Vec<u16> =
422            requested_nullifiers.iter().map(crate::note::Nullifier::prefix).collect();
423        let (chain_tip, _) = self.get_block_header_by_number(None, false).await?;
424        let retrieved_nullifiers =
425            self.sync_nullifiers(&prefixes, block_from, chain_tip.block_num()).await?;
426
427        let mut nullifiers_height = BTreeMap::new();
428        for nullifier in requested_nullifiers {
429            if let Some(update) =
430                retrieved_nullifiers.iter().find(|update| update.nullifier == nullifier)
431            {
432                nullifiers_height.insert(nullifier, Some(update.block_num));
433            } else {
434                nullifiers_height.insert(nullifier, None);
435            }
436        }
437
438        Ok(nullifiers_height)
439    }
440
441    /// Fetches public note-related data for a list of [`NoteId`] and builds [`InputNoteRecord`]s
442    /// with it. If a note is not found or it's private, it is ignored and will not be included
443    /// in the returned list.
444    ///
445    /// The default implementation of this method uses [`NodeRpcClient::get_notes_by_id`].
446    async fn get_public_note_records(
447        &self,
448        note_ids: &[NoteId],
449        current_timestamp: Option<u64>,
450    ) -> Result<Vec<InputNoteRecord>, RpcError> {
451        if note_ids.is_empty() {
452            return Ok(vec![]);
453        }
454
455        let mut public_notes = Vec::with_capacity(note_ids.len());
456        let note_details = self.get_notes_by_id(note_ids).await?;
457
458        for detail in note_details {
459            if let FetchedNote::Public(note, inclusion_proof) = detail {
460                let state = UnverifiedNoteState {
461                    metadata: *note.metadata(),
462                    inclusion_proof,
463                }
464                .into();
465                let attachments = note.attachments().clone();
466                let note = InputNoteRecord::new(note.into(), attachments, current_timestamp, state);
467
468                public_notes.push(note);
469            }
470        }
471
472        Ok(public_notes)
473    }
474
475    /// Given a block number, fetches the block header corresponding to that height from the node
476    /// along with the MMR proof.
477    ///
478    /// The default implementation of this method uses
479    /// [`NodeRpcClient::get_block_header_by_number`].
480    async fn get_block_header_with_proof(
481        &self,
482        block_num: BlockNumber,
483    ) -> Result<(BlockHeader, MmrProof), RpcError> {
484        let (header, proof) = self.get_block_header_by_number(Some(block_num), true).await?;
485        Ok((header, proof.ok_or(RpcError::ExpectedDataMissing(String::from("MmrProof")))?))
486    }
487
488    /// Fetches the note with the specified ID.
489    ///
490    /// The default implementation of this method uses [`NodeRpcClient::get_notes_by_id`].
491    ///
492    /// Errors:
493    /// - [`RpcError::NoteNotFound`] if the note with the specified ID is not found.
494    async fn get_note_by_id(&self, note_id: NoteId) -> Result<FetchedNote, RpcError> {
495        let notes = self.get_notes_by_id(&[note_id]).await?;
496        notes.into_iter().next().ok_or(RpcError::NoteNotFound(note_id))
497    }
498
499    /// Fetches the note script with the specified root, returning `None` if the node has no script
500    /// registered for that root.
501    ///
502    /// Implementations must verify that a returned script's root matches the requested `root` and
503    /// return [`RpcError::InvalidResponse`] otherwise; callers may rely on this invariant.
504    ///
505    /// Errors:
506    /// - [`RpcError::InvalidResponse`] if the node returns a script whose root does not match the
507    ///   requested `root`.
508    async fn get_note_script_by_root(&self, root: Word) -> Result<Option<NoteScript>, RpcError>;
509
510    /// Fetches storage map updates for specified account and storage slots within a block range,
511    /// using the `/SyncStorageMaps` RPC endpoint.
512    ///
513    /// - `block_from`: The starting block number for the range (inclusive).
514    /// - `block_to`: The ending block number for the range (inclusive). The node rejects values
515    ///   greater than the chain tip.
516    /// - `account_id`: The account ID for which to fetch storage map updates.
517    async fn sync_storage_maps(
518        &self,
519        block_from: BlockNumber,
520        block_to: BlockNumber,
521        account_id: AccountId,
522    ) -> Result<StorageMapInfo, RpcError>;
523
524    /// Fetches account vault updates for specified account within a block range,
525    /// using the `/SyncAccountVault` RPC endpoint.
526    ///
527    /// - `block_from`: The starting block number for the range (inclusive).
528    /// - `block_to`: The ending block number for the range (inclusive). The node rejects values
529    ///   greater than the chain tip.
530    /// - `account_id`: The account ID for which to fetch storage map updates.
531    async fn sync_account_vault(
532        &self,
533        block_from: BlockNumber,
534        block_to: BlockNumber,
535        account_id: AccountId,
536    ) -> Result<AccountVaultInfo, RpcError>;
537
538    /// Fetches transaction records for specific accounts within a block range using the
539    /// `/SyncTransactions` RPC endpoint.
540    ///
541    /// - `block_from`: The starting block number for the range (inclusive).
542    /// - `block_to`: The ending block number for the range (inclusive).
543    /// - `account_ids`: The account IDs for which to fetch transactions.
544    async fn sync_transactions(
545        &self,
546        block_from: BlockNumber,
547        block_to: BlockNumber,
548        account_ids: Vec<AccountId>,
549    ) -> Result<Vec<TransactionRecord>, RpcError>;
550
551    /// Fetches the network ID of the node.
552    /// Errors:
553    /// - [`RpcError::ExpectedDataMissing`] if the note with the specified root is not found.
554    async fn get_network_id(&self) -> Result<NetworkId, RpcError>;
555
556    /// Fetches the RPC limits configured on the node.
557    ///
558    /// Implementations may cache the result internally to avoid repeated network calls.
559    async fn get_rpc_limits(&self) -> Result<RpcLimits, RpcError>;
560
561    /// Returns the RPC limits if they have been set, without fetching from the node.
562    fn has_rpc_limits(&self) -> Option<RpcLimits>;
563
564    /// Sets the RPC limits internally to be used by the client.
565    async fn set_rpc_limits(&self, limits: RpcLimits);
566
567    /// Fetches the RPC status without requiring Accept header validation.
568    ///
569    /// This is useful for diagnostics when version negotiation fails, as it allows
570    /// retrieving node information even when there's a version mismatch.
571    async fn get_status_unversioned(&self) -> Result<RpcStatusInfo, RpcError>;
572
573    /// Fetches the status of a specific network note ID.
574    ///
575    /// This is useful for debugging when a network note fails.
576    async fn get_network_note_status(
577        &self,
578        note_id: NoteId,
579    ) -> Result<NetworkNoteStatusInfo, RpcError>;
580}
581
582// RPC API ENDPOINT
583// ================================================================================================
584//
585/// RPC methods for the Miden protocol.
586#[derive(Debug, Clone, Copy)]
587pub enum RpcEndpoint {
588    Status,
589    SyncNullifiers,
590    GetAccount,
591    GetBlockByNumber,
592    GetBlockHeaderByNumber,
593    GetNotesById,
594    SyncChainMmr,
595    SubmitProvenTx,
596    SubmitProvenBatch,
597    SyncNotes,
598    GetNoteScriptByRoot,
599    SyncStorageMaps,
600    SyncAccountVault,
601    SyncTransactions,
602    GetLimits,
603    GetNetworkNoteStatus,
604}
605
606impl RpcEndpoint {
607    /// Returns the endpoint name as used in the RPC service definition.
608    pub fn proto_name(&self) -> &'static str {
609        match self {
610            RpcEndpoint::Status => "Status",
611            RpcEndpoint::SyncNullifiers => "SyncNullifiers",
612            RpcEndpoint::GetAccount => "GetAccount",
613            RpcEndpoint::GetBlockByNumber => "GetBlockByNumber",
614            RpcEndpoint::GetBlockHeaderByNumber => "GetBlockHeaderByNumber",
615            RpcEndpoint::GetNotesById => "GetNotesById",
616            RpcEndpoint::SyncChainMmr => "SyncChainMmr",
617            RpcEndpoint::SubmitProvenTx => "SubmitProvenTransaction",
618            RpcEndpoint::SubmitProvenBatch => "SubmitProvenBatch",
619            RpcEndpoint::SyncNotes => "SyncNotes",
620            RpcEndpoint::GetNoteScriptByRoot => "GetNoteScriptByRoot",
621            RpcEndpoint::SyncStorageMaps => "SyncStorageMaps",
622            RpcEndpoint::SyncAccountVault => "SyncAccountVault",
623            RpcEndpoint::SyncTransactions => "SyncTransactions",
624            RpcEndpoint::GetLimits => "GetLimits",
625            RpcEndpoint::GetNetworkNoteStatus => "GetNetworkNoteStatus",
626        }
627    }
628}
629
630impl fmt::Display for RpcEndpoint {
631    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
632        match self {
633            RpcEndpoint::Status => write!(f, "status"),
634            RpcEndpoint::SyncNullifiers => {
635                write!(f, "sync_nullifiers")
636            },
637            RpcEndpoint::GetAccount => write!(f, "get_account"),
638            RpcEndpoint::GetBlockByNumber => write!(f, "get_block_by_number"),
639            RpcEndpoint::GetBlockHeaderByNumber => {
640                write!(f, "get_block_header_by_number")
641            },
642            RpcEndpoint::GetNotesById => write!(f, "get_notes_by_id"),
643            RpcEndpoint::SyncChainMmr => write!(f, "sync_chain_mmr"),
644            RpcEndpoint::SubmitProvenTx => write!(f, "submit_proven_transaction"),
645            RpcEndpoint::SubmitProvenBatch => write!(f, "submit_proven_batch"),
646            RpcEndpoint::SyncNotes => write!(f, "sync_notes"),
647            RpcEndpoint::GetNoteScriptByRoot => write!(f, "get_note_script_by_root"),
648            RpcEndpoint::SyncStorageMaps => write!(f, "sync_storage_maps"),
649            RpcEndpoint::SyncAccountVault => write!(f, "sync_account_vault"),
650            RpcEndpoint::SyncTransactions => write!(f, "sync_transactions"),
651            RpcEndpoint::GetLimits => write!(f, "get_limits"),
652            RpcEndpoint::GetNetworkNoteStatus => write!(f, "get_network_note_status"),
653        }
654    }
655}