Skip to main content

miden_client/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3//! A no_std-compatible client library for interacting with the Miden network.
4//!
5//! This crate provides a lightweight client that handles connections to the Miden node, manages
6//! accounts and their state, and facilitates executing, proving, and submitting transactions.
7//!
8//! For a protocol-level overview and guides for getting started, please visit the official
9//! [Miden docs](https://0xMiden.github.io/miden-docs/).
10//!
11//! ## Overview
12//!
13//! The library is organized into several key modules:
14//!
15//! - **Accounts:** Provides types for managing accounts. Once accounts are tracked by the client,
16//!   their state is updated with every transaction and validated during each sync.
17//!
18//! - **Notes:** Contains types and utilities for working with notes in the Miden client.
19//!
20//! - **RPC:** Facilitates communication with Miden node, exposing RPC methods for syncing state,
21//!   fetching block headers, and submitting transactions.
22//!
23//! - **Store:** Defines and implements the persistence layer for accounts, transactions, notes, and
24//!   other entities.
25//!
26//! - **Sync:** Provides functionality to synchronize the local state with the current state on the
27//!   Miden network.
28//!
29//! - **Transactions:** Offers capabilities to build, execute, prove, and submit transactions.
30//!
31//! Additionally, the crate re-exports several utility modules:
32//!
33//! - **Assembly:** Types for working with Miden Assembly.
34//! - **Assets:** Types and utilities for working with assets.
35//! - **Auth:** Authentication-related types and functionalities.
36//! - **Blocks:** Types for handling block headers.
37//! - **Crypto:** Cryptographic types and utilities, including random number generators.
38//! - **Utils:** Miscellaneous utilities for serialization and common operations.
39//!
40//! The library is designed to work in both `no_std` and `std` environments and is
41//! configurable via Cargo features.
42//!
43//! ## Usage
44//!
45//! To use the Miden client library in your project, add it as a dependency in your `Cargo.toml`:
46//!
47//! ```toml
48//! [dependencies]
49//! miden-client = "0.10"
50//! ```
51//!
52//! ## Example
53//!
54//! Below is a brief example illustrating how to instantiate the client using `ClientBuilder`:
55//!
56//! ```rust,ignore
57//! use std::sync::Arc;
58//!
59//! use miden_client::DebugMode;
60//! use miden_client::builder::ClientBuilder;
61//! use miden_client::keystore::FilesystemKeyStore;
62//! use miden_client::rpc::{Endpoint, GrpcClient};
63//! use miden_client_sqlite_store::SqliteStore;
64//!
65//! # pub async fn create_test_client() -> Result<(), Box<dyn std::error::Error>> {
66//! // Create the SQLite store.
67//! let sqlite_store = SqliteStore::new("path/to/store".try_into()?).await?;
68//! let store = Arc::new(sqlite_store);
69//!
70//! // Create the keystore for transaction signing.
71//! let keystore = FilesystemKeyStore::new("path/to/keys/directory".try_into()?)?;
72//!
73//! // Create the RPC client.
74//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
75//!
76//! // Instantiate the client using the builder.
77//! let client = ClientBuilder::new()
78//!     .rpc(Arc::new(GrpcClient::new(&endpoint, 10_000)))
79//!     .store(store)
80//!     .authenticator(Arc::new(keystore))
81//!     .in_debug_mode(DebugMode::Disabled)
82//!     .build()
83//!     .await?;
84//!
85//! # Ok(())
86//! # }
87//! ```
88//!
89//! For network-specific defaults, use the convenience constructors:
90//!
91//! ```ignore
92//! // For testnet (includes remote prover and note transport)
93//! let client = ClientBuilder::for_testnet()
94//!     .store(store)
95//!     .authenticator(Arc::new(keystore))
96//!     .build()
97//!     .await?;
98//!
99//! // For local development
100//! let client = ClientBuilder::for_localhost()
101//!     .store(store)
102//!     .authenticator(Arc::new(keystore))
103//!     .build()
104//!     .await?;
105//! ```
106//!
107//! For additional usage details, configuration options, and examples, consult the documentation for
108//! each module.
109
110#![no_std]
111
112#[macro_use]
113extern crate alloc;
114use alloc::boxed::Box;
115
116#[cfg(feature = "std")]
117extern crate std;
118
119pub mod account;
120pub mod grpc_support;
121pub mod keystore;
122pub mod note;
123pub mod note_transport;
124pub mod rpc;
125pub mod settings;
126pub mod store;
127pub mod sync;
128pub mod transaction;
129pub mod utils;
130
131pub mod builder;
132
133#[cfg(feature = "testing")]
134mod test_utils;
135
136pub mod errors;
137
138pub use miden_protocol::utils::serde::{Deserializable, Serializable, SliceReader};
139
140// RE-EXPORTS
141// ================================================================================================
142
143pub mod notes {
144    pub use miden_protocol::note::NoteFile;
145}
146
147/// Provides types and utilities for working with Miden Assembly.
148pub mod assembly {
149    pub use miden_protocol::MastForest;
150    pub use miden_protocol::assembly::debuginfo::SourceManagerSync;
151    pub use miden_protocol::assembly::diagnostics::Report;
152    pub use miden_protocol::assembly::diagnostics::reporting::PrintDiagnostic;
153    pub use miden_protocol::assembly::mast::MastNodeExt;
154    pub use miden_protocol::assembly::{
155        Assembler,
156        DefaultSourceManager,
157        Library,
158        Module,
159        ModuleKind,
160        Path,
161    };
162    pub use miden_standards::code_builder::CodeBuilder;
163}
164
165/// Provides types and utilities for working with assets within the Miden network.
166pub mod asset {
167    pub use miden_protocol::account::delta::{
168        AccountStorageDelta,
169        AccountVaultDelta,
170        FungibleAssetDelta,
171        NonFungibleAssetDelta,
172        NonFungibleDeltaAction,
173    };
174    pub use miden_protocol::account::{
175        AccountStorageHeader,
176        StorageMapWitness,
177        StorageSlotContent,
178        StorageSlotHeader,
179    };
180    pub use miden_protocol::asset::{
181        Asset,
182        AssetVault,
183        AssetVaultKey,
184        AssetWitness,
185        FungibleAsset,
186        NonFungibleAsset,
187        NonFungibleAssetDetails,
188        PartialVault,
189        TokenSymbol,
190    };
191}
192
193/// Provides authentication-related types and functionalities for the Miden
194/// network.
195pub mod auth {
196    pub use miden_protocol::account::auth::{
197        AuthScheme as AuthSchemeId,
198        AuthSecretKey,
199        PublicKey,
200        PublicKeyCommitment,
201        Signature,
202    };
203    pub use miden_standards::account::auth::{
204        AuthMultisig,
205        AuthMultisigConfig,
206        AuthSingleSig,
207        AuthSingleSigAcl,
208        AuthSingleSigAclConfig,
209        NoAuth,
210    };
211    pub use miden_tx::auth::{BasicAuthenticator, SigningInputs, TransactionAuthenticator};
212
213    pub use crate::account::component::AuthScheme;
214
215    pub const RPO_FALCON_SCHEME_ID: AuthSchemeId = AuthSchemeId::Falcon512Poseidon2;
216    pub const ECDSA_K256_KECCAK_SCHEME_ID: AuthSchemeId = AuthSchemeId::EcdsaK256Keccak;
217}
218
219/// Provides types for working with blocks within the Miden network.
220pub mod block {
221    pub use miden_protocol::block::{BlockHeader, BlockNumber};
222}
223
224/// Provides cryptographic types and utilities used within the Miden rollup
225/// network. It re-exports commonly used types and random number generators like `FeltRng` from
226/// the `miden_standards` crate.
227pub mod crypto {
228    pub mod rpo_falcon512 {
229        pub use miden_protocol::crypto::dsa::falcon512_poseidon2::{
230            PublicKey,
231            SecretKey,
232            Signature,
233        };
234    }
235    pub use miden_protocol::crypto::hash::blake::Blake3Digest;
236    pub use miden_protocol::crypto::hash::poseidon2::Poseidon2;
237    pub use miden_protocol::crypto::hash::rpo::Rpo256;
238    pub use miden_protocol::crypto::merkle::mmr::{
239        Forest,
240        InOrderIndex,
241        MmrDelta,
242        MmrPeaks,
243        MmrProof,
244        PartialMmr,
245    };
246    pub use miden_protocol::crypto::merkle::smt::{
247        LeafIndex,
248        SMT_DEPTH,
249        Smt,
250        SmtForest,
251        SmtLeaf,
252        SmtProof,
253    };
254    pub use miden_protocol::crypto::merkle::store::MerkleStore;
255    pub use miden_protocol::crypto::merkle::{
256        EmptySubtreeRoots,
257        MerkleError,
258        MerklePath,
259        MerkleTree,
260        NodeIndex,
261        SparseMerklePath,
262    };
263    pub use miden_protocol::crypto::rand::{FeltRng, RandomCoin};
264}
265
266/// Provides types for working with addresses within the Miden network.
267pub mod address {
268    pub use miden_protocol::address::{
269        Address,
270        AddressId,
271        AddressInterface,
272        CustomNetworkId,
273        NetworkId,
274        RoutingParameters,
275    };
276}
277
278/// Provides types for working with the virtual machine within the Miden network.
279pub mod vm {
280    pub use miden_protocol::vm::{
281        AdviceInputs,
282        AdviceMap,
283        AttributeSet,
284        Package,
285        PackageExport,
286        PackageManifest,
287        ProcedureExport,
288        Program,
289        QualifiedProcedureName,
290        Section,
291        SectionId,
292        TargetType,
293    };
294}
295
296pub use async_trait::async_trait;
297pub use errors::*;
298use miden_protocol::assembly::SourceManagerSync;
299pub use miden_protocol::{
300    EMPTY_WORD,
301    Felt,
302    MAX_TX_EXECUTION_CYCLES,
303    MIN_TX_EXECUTION_CYCLES,
304    ONE,
305    PrettyPrint,
306    Word,
307    ZERO,
308};
309pub use miden_remote_prover_client::RemoteTransactionProver;
310pub use miden_tx::ExecutionOptions;
311
312/// Provides test utilities for working with accounts and account IDs
313/// within the Miden network. This module is only available when the `testing` feature is
314/// enabled.
315#[cfg(feature = "testing")]
316pub mod testing {
317    pub use miden_protocol::testing::account_id;
318    pub use miden_standards::testing::note::NoteBuilder;
319    pub use miden_standards::testing::*;
320    pub use miden_testing::*;
321
322    pub use crate::test_utils::*;
323}
324
325use alloc::sync::Arc;
326
327use miden_protocol::crypto::rand::FeltRng;
328use miden_tx::auth::TransactionAuthenticator;
329use rand::RngCore;
330use rpc::NodeRpcClient;
331use store::Store;
332
333use crate::note_transport::NoteTransportClient;
334use crate::transaction::TransactionProver;
335
336// MIDEN CLIENT
337// ================================================================================================
338
339/// A light client for connecting to the Miden network.
340///
341/// Miden client is responsible for managing a set of accounts. Specifically, the client:
342/// - Keeps track of the current and historical states of a set of accounts and related objects such
343///   as notes and transactions.
344/// - Connects to a Miden node to periodically sync with the current state of the network.
345/// - Executes, proves, and submits transactions to the network as directed by the user.
346pub struct Client<AUTH> {
347    /// The client's store, which provides a way to write and read entities to provide persistence.
348    store: Arc<dyn Store>,
349    /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
350    /// serial numbers, etc.
351    rng: ClientRng,
352    /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
353    /// Miden node.
354    rpc_api: Arc<dyn NodeRpcClient>,
355    /// An instance of a [`TransactionProver`] which will be the default prover for the
356    /// client.
357    tx_prover: Arc<dyn TransactionProver + Send + Sync>,
358    /// An instance of a [`TransactionAuthenticator`] which will be used by the transaction
359    /// executor whenever a signature is requested from within the VM.
360    authenticator: Option<Arc<AUTH>>,
361    /// Shared source manager used to retain MASM source information for assembled programs.
362    source_manager: Arc<dyn SourceManagerSync>,
363    /// Options that control the transaction executor's runtime behaviour (e.g. debug mode).
364    exec_options: ExecutionOptions,
365    /// Number of blocks after which pending transactions are considered stale and discarded.
366    tx_discard_delta: Option<u32>,
367    /// Maximum number of blocks the client can be behind the network for transactions and account
368    /// proofs to be considered valid.
369    max_block_number_delta: Option<u32>,
370    /// An instance of [`NoteTransportClient`] which provides a way for the client to connect to
371    /// the Miden Note Transport network.
372    note_transport_api: Option<Arc<dyn NoteTransportClient>>,
373}
374
375/// Constructors.
376impl<AUTH> Client<AUTH>
377where
378    AUTH: builder::BuilderAuthenticator,
379{
380    /// Returns a new [`ClientBuilder`](builder::ClientBuilder) for constructing a client.
381    ///
382    /// This is a convenience method equivalent to calling `ClientBuilder::new()`.
383    ///
384    /// # Example
385    ///
386    /// ```ignore
387    /// let client = Client::builder()
388    ///     .rpc(rpc_client)
389    ///     .store(store)
390    ///     .authenticator(Arc::new(keystore))
391    ///     .build()
392    ///     .await?;
393    /// ```
394    pub fn builder() -> builder::ClientBuilder<AUTH> {
395        builder::ClientBuilder::new()
396    }
397}
398
399/// Access methods.
400impl<AUTH> Client<AUTH>
401where
402    AUTH: TransactionAuthenticator,
403{
404    /// Returns true if the client is in debug mode.
405    pub fn in_debug_mode(&self) -> bool {
406        self.exec_options.enable_debugging()
407    }
408
409    /// Returns an instance of the `CodeBuilder`
410    pub fn code_builder(&self) -> assembly::CodeBuilder {
411        assembly::CodeBuilder::with_source_manager(self.source_manager.clone())
412    }
413
414    /// Returns an instance of [`note::NoteScreener`] configured for this client.
415    pub fn note_screener(&self) -> note::NoteScreener {
416        note::NoteScreener::new(self.store.clone(), self.rpc_api.clone())
417    }
418
419    /// Returns a reference to the client's random number generator. This can be used to generate
420    /// randomness for various purposes such as serial numbers, keys, etc.
421    pub fn rng(&mut self) -> &mut ClientRng {
422        &mut self.rng
423    }
424
425    pub fn prover(&self) -> Arc<dyn TransactionProver + Send + Sync> {
426        self.tx_prover.clone()
427    }
428
429    pub fn authenticator(&self) -> Option<&Arc<AUTH>> {
430        self.authenticator.as_ref()
431    }
432}
433
434impl<AUTH> Client<AUTH> {
435    /// Returns the identifier of the underlying store (e.g. `IndexedDB` database name, `SQLite`
436    /// file path).
437    pub fn store_identifier(&self) -> &str {
438        self.store.identifier()
439    }
440
441    // LIMITS
442    // --------------------------------------------------------------------------------------------
443
444    /// Checks if the note tag limit has been exceeded.
445    pub async fn check_note_tag_limit(&self) -> Result<(), ClientError> {
446        let limits = self.rpc_api.get_rpc_limits().await?;
447        if self.store.get_unique_note_tags().await?.len() >= limits.note_tags_limit as usize {
448            return Err(ClientError::NoteTagsLimitExceeded(limits.note_tags_limit));
449        }
450        Ok(())
451    }
452
453    /// Checks if the account limit has been exceeded.
454    pub async fn check_account_limit(&self) -> Result<(), ClientError> {
455        let limits = self.rpc_api.get_rpc_limits().await?;
456        if self.store.get_account_ids().await?.len() >= limits.account_ids_limit as usize {
457            return Err(ClientError::AccountsLimitExceeded(limits.account_ids_limit));
458        }
459        Ok(())
460    }
461
462    // TEST HELPERS
463    // --------------------------------------------------------------------------------------------
464
465    #[cfg(any(test, feature = "testing"))]
466    pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient> {
467        &mut self.rpc_api
468    }
469
470    #[cfg(any(test, feature = "testing"))]
471    pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
472        &mut self.store
473    }
474}
475
476// CLIENT RNG
477// ================================================================================================
478
479// NOTE: The idea of having `ClientRng` is to enforce `Send` and `Sync` over `FeltRng`.
480// This allows `Client`` to be `Send` and `Sync`. There may be users that would want to use clients
481// with !Send/!Sync RNGs. For this we have two options:
482//
483// - We can make client generic over R (adds verbosity but is more flexible and maybe even correct)
484// - We can optionally (e.g., based on features/target) change `ClientRng` definition to not enforce
485//   these bounds. (similar to TransactionAuthenticator)
486
487/// Marker trait for RNGs that can be shared across threads and used by the client.
488pub trait ClientFeltRng: FeltRng + Send + Sync {}
489impl<T> ClientFeltRng for T where T: FeltRng + Send + Sync {}
490
491/// Boxed RNG trait object used by the client.
492pub type ClientRngBox = Box<dyn ClientFeltRng>;
493
494/// A wrapper around a [`FeltRng`] that implements the [`RngCore`] trait.
495/// This allows the user to pass their own generic RNG so that it's used by the client.
496pub struct ClientRng(ClientRngBox);
497
498impl ClientRng {
499    pub fn new(rng: ClientRngBox) -> Self {
500        Self(rng)
501    }
502
503    pub fn inner_mut(&mut self) -> &mut ClientRngBox {
504        &mut self.0
505    }
506}
507
508impl RngCore for ClientRng {
509    fn next_u32(&mut self) -> u32 {
510        self.0.next_u32()
511    }
512
513    fn next_u64(&mut self) -> u64 {
514        self.0.next_u64()
515    }
516
517    fn fill_bytes(&mut self, dest: &mut [u8]) {
518        self.0.fill_bytes(dest);
519    }
520}
521
522impl FeltRng for ClientRng {
523    fn draw_element(&mut self) -> Felt {
524        self.0.draw_element()
525    }
526
527    fn draw_word(&mut self) -> Word {
528        self.0.draw_word()
529    }
530}
531
532/// Indicates whether the client is operating in debug mode.
533#[derive(Debug, Clone, Copy)]
534pub enum DebugMode {
535    Enabled,
536    Disabled,
537}
538
539impl From<DebugMode> for bool {
540    fn from(debug_mode: DebugMode) -> Self {
541        match debug_mode {
542            DebugMode::Enabled => true,
543            DebugMode::Disabled => false,
544        }
545    }
546}
547
548impl From<bool> for DebugMode {
549    fn from(debug_mode: bool) -> DebugMode {
550        if debug_mode {
551            DebugMode::Enabled
552        } else {
553            DebugMode::Disabled
554        }
555    }
556}
557
558#[cfg(test)]
559mod tests {
560    use super::Client;
561
562    fn assert_send_sync<T: Send + Sync>() {}
563
564    #[test]
565    fn client_is_send_sync() {
566        assert_send_sync::<Client<()>>();
567    }
568}