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:
55//!
56//! ```rust,ignore
57//! use std::sync::Arc;
58//!
59//! use miden_client::crypto::RpoRandomCoin;
60//! use miden_client::keystore::FilesystemKeyStore;
61//! use miden_client::note_transport::NOTE_TRANSPORT_DEFAULT_ENDPOINT;
62//! use miden_client::note_transport::grpc::GrpcNoteTransportClient;
63//! use miden_client::rpc::{Endpoint, GrpcClient};
64//! use miden_client::store::Store;
65//! use miden_client::{Client, ExecutionOptions, Felt};
66//! use miden_client_sqlite_store::SqliteStore;
67//! use miden_protocol::crypto::rand::FeltRng;
68//! use miden_protocol::{MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES};
69//! use rand::Rng;
70//!
71//! # pub async fn create_test_client() -> Result<(), Box<dyn std::error::Error>> {
72//! // Create the SQLite store from the client configuration.
73//! let sqlite_store = SqliteStore::new("path/to/store".try_into()?).await?;
74//! let store = Arc::new(sqlite_store);
75//!
76//! // Generate a random seed for the RpoRandomCoin.
77//! let mut rng = rand::rng();
78//! let coin_seed: [u64; 4] = rng.random();
79//!
80//! // Initialize the random coin using the generated seed.
81//! let rng = RpoRandomCoin::new(coin_seed.map(Felt::new).into());
82//! let keystore = FilesystemKeyStore::new("path/to/keys/directory".try_into()?)?;
83//!
84//! // Determine the number of blocks to consider a transaction stale.
85//! // 20 is simply an example value.
86//! let tx_graceful_blocks = Some(20);
87//! // Determine the maximum number of blocks that the client can be behind from the network.
88//! // 256 is simply an example value.
89//! let max_block_number_delta = Some(256);
90//!
91//! // Optionally, connect to the note transport network to exchange private notes.
92//! let note_transport_api =
93//!     GrpcNoteTransportClient::connect(NOTE_TRANSPORT_DEFAULT_ENDPOINT.to_string(), 10_000)
94//!         .await?;
95//!
96//! // Instantiate the client using a gRPC client
97//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
98//! let client: Client<FilesystemKeyStore> = Client::new(
99//!     Arc::new(GrpcClient::new(&endpoint, 10_000)),
100//!     Box::new(rng),
101//!     store,
102//!     Some(Arc::new(keystore)), // or None if no authenticator is needed
103//!     ExecutionOptions::new(
104//!         Some(MAX_TX_EXECUTION_CYCLES),
105//!         MIN_TX_EXECUTION_CYCLES,
106//!         false,
107//!         false, // Set to true for debug mode, if needed.
108//!     )
109//!     .unwrap(),
110//!     tx_graceful_blocks,
111//!     max_block_number_delta,
112//!     Some(Arc::new(note_transport_api)),
113//!     None, // or Some(Arc::new(prover)) for a custom prover
114//! )
115//! .await
116//! .unwrap();
117//!
118//! # Ok(())
119//! # }
120//! ```
121//!
122//! For additional usage details, configuration options, and examples, consult the documentation for
123//! each module.
124
125#![no_std]
126
127#[macro_use]
128extern crate alloc;
129use alloc::boxed::Box;
130
131#[cfg(feature = "std")]
132extern crate std;
133
134pub mod account;
135pub mod keystore;
136pub mod note;
137pub mod note_transport;
138pub mod rpc;
139pub mod settings;
140pub mod store;
141pub mod sync;
142pub mod transaction;
143pub mod utils;
144
145#[cfg(feature = "std")]
146pub mod builder;
147
148#[cfg(feature = "testing")]
149mod test_utils;
150
151pub mod errors;
152
153use miden_protocol::block::BlockNumber;
154pub use miden_protocol::utils::{Deserializable, Serializable, SliceReader};
155
156// RE-EXPORTS
157// ================================================================================================
158
159pub mod notes {
160    pub use miden_protocol::note::NoteFile;
161}
162
163/// Provides types and utilities for working with Miden Assembly.
164pub mod assembly {
165    pub use miden_protocol::MastForest;
166    pub use miden_protocol::assembly::debuginfo::SourceManagerSync;
167    pub use miden_protocol::assembly::diagnostics::Report;
168    pub use miden_protocol::assembly::diagnostics::reporting::PrintDiagnostic;
169    pub use miden_protocol::assembly::mast::MastNodeExt;
170    pub use miden_protocol::assembly::{
171        Assembler,
172        DefaultSourceManager,
173        Library,
174        Module,
175        ModuleKind,
176        Path,
177    };
178    pub use miden_standards::code_builder::CodeBuilder;
179}
180
181/// Provides types and utilities for working with assets within the Miden network.
182pub mod asset {
183    pub use miden_protocol::account::delta::{
184        AccountStorageDelta,
185        AccountVaultDelta,
186        FungibleAssetDelta,
187        NonFungibleAssetDelta,
188        NonFungibleDeltaAction,
189    };
190    pub use miden_protocol::asset::{
191        Asset,
192        AssetVault,
193        AssetWitness,
194        FungibleAsset,
195        NonFungibleAsset,
196        NonFungibleAssetDetails,
197        TokenSymbol,
198    };
199}
200
201/// Provides authentication-related types and functionalities for the Miden
202/// network.
203pub mod auth {
204    pub use miden_protocol::account::auth::{
205        AuthScheme as AuthSchemeId,
206        AuthSecretKey,
207        PublicKey,
208        PublicKeyCommitment,
209        Signature,
210    };
211    pub use miden_standards::AuthScheme;
212    pub use miden_standards::account::auth::{AuthEcdsaK256Keccak, AuthFalcon512Rpo, NoAuth};
213    pub use miden_tx::auth::{BasicAuthenticator, SigningInputs, TransactionAuthenticator};
214
215    pub const RPO_FALCON_SCHEME_ID: AuthSchemeId = AuthSchemeId::Falcon512Rpo;
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_rpo::{PublicKey, SecretKey, Signature};
230    }
231    pub use miden_protocol::crypto::hash::blake::{Blake3_160, Blake3Digest};
232    pub use miden_protocol::crypto::hash::rpo::Rpo256;
233    pub use miden_protocol::crypto::merkle::mmr::{
234        Forest,
235        InOrderIndex,
236        MmrDelta,
237        MmrPeaks,
238        MmrProof,
239        PartialMmr,
240    };
241    pub use miden_protocol::crypto::merkle::smt::{LeafIndex, SMT_DEPTH, SmtLeaf, SmtProof};
242    pub use miden_protocol::crypto::merkle::store::MerkleStore;
243    pub use miden_protocol::crypto::merkle::{MerklePath, MerkleTree, NodeIndex, SparseMerklePath};
244    pub use miden_protocol::crypto::rand::{FeltRng, RpoRandomCoin};
245}
246
247/// Provides types for working with addresses within the Miden network.
248pub mod address {
249    pub use miden_protocol::address::{
250        Address,
251        AddressId,
252        AddressInterface,
253        CustomNetworkId,
254        NetworkId,
255        RoutingParameters,
256    };
257}
258
259/// Provides types for working with the virtual machine within the Miden network.
260pub mod vm {
261    // TODO: Remove this re-export once miden-protocol exposes PackageKind/ProcedureExport.
262    pub use miden_mast_package::{PackageKind, ProcedureExport};
263    pub use miden_protocol::vm::{
264        AdviceInputs,
265        AdviceMap,
266        AttributeSet,
267        MastArtifact,
268        Package,
269        PackageExport,
270        PackageManifest,
271        Program,
272        QualifiedProcedureName,
273        Section,
274        SectionId,
275    };
276}
277
278pub use async_trait::async_trait;
279pub use errors::*;
280use miden_protocol::assembly::{DefaultSourceManager, SourceManagerSync};
281pub use miden_protocol::{
282    EMPTY_WORD,
283    Felt,
284    MAX_TX_EXECUTION_CYCLES,
285    MIN_TX_EXECUTION_CYCLES,
286    ONE,
287    PrettyPrint,
288    StarkField,
289    Word,
290    ZERO,
291};
292pub use miden_remote_prover_client::remote_prover::tx_prover::RemoteTransactionProver;
293pub use miden_tx::ExecutionOptions;
294
295/// Provides test utilities for working with accounts and account IDs
296/// within the Miden network. This module is only available when the `testing` feature is
297/// enabled.
298#[cfg(feature = "testing")]
299pub mod testing {
300    pub use miden_protocol::testing::account_id;
301    pub use miden_standards::testing::note::NoteBuilder;
302    pub use miden_standards::testing::*;
303    pub use miden_testing::*;
304
305    pub use crate::test_utils::*;
306}
307
308use alloc::sync::Arc;
309
310use miden_protocol::crypto::rand::FeltRng;
311use miden_tx::LocalTransactionProver;
312use miden_tx::auth::TransactionAuthenticator;
313use rand::RngCore;
314use rpc::NodeRpcClient;
315use store::Store;
316
317use crate::note_transport::{NoteTransportClient, init_note_transport_cursor};
318use crate::rpc::{ACCOUNT_ID_LIMIT, NOTE_TAG_LIMIT};
319use crate::transaction::TransactionProver;
320
321// MIDEN CLIENT
322// ================================================================================================
323
324/// A light client for connecting to the Miden network.
325///
326/// Miden client is responsible for managing a set of accounts. Specifically, the client:
327/// - Keeps track of the current and historical states of a set of accounts and related objects such
328///   as notes and transactions.
329/// - Connects to a Miden node to periodically sync with the current state of the network.
330/// - Executes, proves, and submits transactions to the network as directed by the user.
331pub struct Client<AUTH> {
332    /// The client's store, which provides a way to write and read entities to provide persistence.
333    store: Arc<dyn Store>,
334    /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
335    /// serial numbers, etc.
336    rng: ClientRng,
337    /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
338    /// Miden node.
339    rpc_api: Arc<dyn NodeRpcClient>,
340    /// An instance of a [`TransactionProver`] which will be the default prover for the
341    /// client.
342    tx_prover: Arc<dyn TransactionProver + Send + Sync>,
343    /// An instance of a [`TransactionAuthenticator`] which will be used by the transaction
344    /// executor whenever a signature is requested from within the VM.
345    authenticator: Option<Arc<AUTH>>,
346    /// Shared source manager used to retain MASM source information for assembled programs.
347    source_manager: Arc<dyn SourceManagerSync>,
348    /// Options that control the transaction executor’s runtime behaviour (e.g. debug mode).
349    exec_options: ExecutionOptions,
350    /// The number of blocks that are considered old enough to discard pending transactions.
351    tx_graceful_blocks: Option<u32>,
352    /// Maximum number of blocks the client can be behind the network for transactions and account
353    /// proofs to be considered valid.
354    max_block_number_delta: Option<u32>,
355    /// An instance of [`NoteTransportClient`] which provides a way for the client to connect to
356    /// the Miden Note Transport network.
357    note_transport_api: Option<Arc<dyn NoteTransportClient>>,
358}
359
360/// Construction and access methods.
361impl<AUTH> Client<AUTH>
362where
363    AUTH: TransactionAuthenticator,
364{
365    // CONSTRUCTOR
366    // --------------------------------------------------------------------------------------------
367
368    /// Returns a new instance of [`Client`].
369    ///
370    /// ## Arguments
371    ///
372    /// - `rpc_api`: An instance of [`NodeRpcClient`] which provides a way for the client to connect
373    ///   to the Miden node.
374    /// - `rng`: An instance of [`FeltRng`] which provides randomness tools for generating new keys,
375    ///   serial numbers, etc. This can be any RNG that implements [`ClientFeltRng`] (ie `FeltRng`
376    ///   + `Send` + `Sync`).
377    /// - `store`: An instance of [`Store`], which provides a way to write and read entities to
378    ///   provide persistence.
379    /// - `authenticator`: Defines the transaction authenticator that will be used by the
380    ///   transaction executor whenever a signature is requested from within the VM.
381    /// - `exec_options`: Options that control the transaction executor’s runtime behaviour (e.g.
382    ///   debug mode).
383    /// - `tx_graceful_blocks`: The number of blocks that are considered old enough to discard
384    ///   pending transactions.
385    /// - `max_block_number_delta`: Determines the maximum number of blocks that the client can be
386    ///   behind the network for transactions and account proofs to be considered valid.
387    /// - `note_transport_api`: An instance of [`NoteTransportClient`] which provides a way for the
388    ///   client to connect to the Miden Note Transport network.
389    /// - `tx_prover`: An optional instance of [`TransactionProver`] which will be used as the
390    ///   default prover for the client. If not provided, a default local prover will be created.
391    ///
392    /// # Errors
393    ///
394    /// Returns an error if the client couldn't be instantiated.
395    #[allow(clippy::too_many_arguments)]
396    pub async fn new(
397        rpc_api: Arc<dyn NodeRpcClient>,
398        rng: ClientRngBox,
399        store: Arc<dyn Store>,
400        authenticator: Option<Arc<AUTH>>,
401        exec_options: ExecutionOptions,
402        tx_graceful_blocks: Option<u32>,
403        max_block_number_delta: Option<u32>,
404        note_transport_api: Option<Arc<dyn NoteTransportClient>>,
405        tx_prover: Option<Arc<dyn TransactionProver + Send + Sync>>,
406    ) -> Result<Self, ClientError> {
407        let tx_prover: Arc<dyn TransactionProver + Send + Sync> =
408            tx_prover.unwrap_or_else(|| Arc::new(LocalTransactionProver::default()));
409
410        if let Some((genesis, _)) = store.get_block_header_by_num(BlockNumber::GENESIS).await? {
411            // Set the genesis commitment in the RPC API client for future requests.
412            rpc_api.set_genesis_commitment(genesis.commitment()).await?;
413        }
414
415        // Initialize the note transport cursor if the client uses it
416        if note_transport_api.is_some() {
417            init_note_transport_cursor(store.clone()).await?;
418        }
419
420        let source_manager: Arc<dyn SourceManagerSync> = Arc::new(DefaultSourceManager::default());
421
422        Ok(Self {
423            store,
424            rng: ClientRng::new(rng),
425            rpc_api,
426            tx_prover,
427            authenticator,
428            source_manager,
429            exec_options,
430            tx_graceful_blocks,
431            max_block_number_delta,
432            note_transport_api,
433        })
434    }
435
436    /// Returns true if the client is in debug mode.
437    pub fn in_debug_mode(&self) -> bool {
438        self.exec_options.enable_debugging()
439    }
440
441    /// Returns an instance of the `CodeBuilder`
442    pub fn code_builder(&self) -> assembly::CodeBuilder {
443        assembly::CodeBuilder::with_source_manager(self.source_manager.clone())
444    }
445
446    /// Returns a reference to the client's random number generator. This can be used to generate
447    /// randomness for various purposes such as serial numbers, keys, etc.
448    pub fn rng(&mut self) -> &mut ClientRng {
449        &mut self.rng
450    }
451
452    pub fn prover(&self) -> Arc<dyn TransactionProver + Send + Sync> {
453        self.tx_prover.clone()
454    }
455}
456
457impl<AUTH> Client<AUTH> {
458    // LIMITS
459    // --------------------------------------------------------------------------------------------
460
461    /// Checks if the note tag limit has been exceeded.
462    pub async fn check_note_tag_limit(&self) -> Result<(), ClientError> {
463        if self.store.get_unique_note_tags().await?.len() >= NOTE_TAG_LIMIT {
464            return Err(ClientError::NoteTagsLimitExceeded(NOTE_TAG_LIMIT));
465        }
466        Ok(())
467    }
468
469    /// Checks if the account limit has been exceeded.
470    pub async fn check_account_limit(&self) -> Result<(), ClientError> {
471        if self.store.get_account_ids().await?.len() >= ACCOUNT_ID_LIMIT {
472            return Err(ClientError::AccountsLimitExceeded(ACCOUNT_ID_LIMIT));
473        }
474        Ok(())
475    }
476
477    // TEST HELPERS
478    // --------------------------------------------------------------------------------------------
479
480    #[cfg(any(test, feature = "testing"))]
481    pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient> {
482        &mut self.rpc_api
483    }
484
485    #[cfg(any(test, feature = "testing"))]
486    pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
487        &mut self.store
488    }
489}
490
491// CLIENT RNG
492// ================================================================================================
493
494// NOTE: The idea of having `ClientRng` is to enforce `Send` and `Sync` over `FeltRng`.
495// This allows `Client`` to be `Send` and `Sync`. There may be users that would want to use clients
496// with !Send/!Sync RNGs. For this we have two options:
497//
498// - We can make client generic over R (adds verbosity but is more flexible and maybe even correct)
499// - We can optionally (e.g., based on features/target) change `ClientRng` definition to not enforce
500//   these bounds. (similar to TransactionAuthenticator)
501
502/// Marker trait for RNGs that can be shared across threads and used by the client.
503pub trait ClientFeltRng: FeltRng + Send + Sync {}
504impl<T> ClientFeltRng for T where T: FeltRng + Send + Sync {}
505
506/// Boxed RNG trait object used by the client.
507pub type ClientRngBox = Box<dyn ClientFeltRng>;
508
509/// A wrapper around a [`FeltRng`] that implements the [`RngCore`] trait.
510/// This allows the user to pass their own generic RNG so that it's used by the client.
511pub struct ClientRng(ClientRngBox);
512
513impl ClientRng {
514    pub fn new(rng: ClientRngBox) -> Self {
515        Self(rng)
516    }
517
518    pub fn inner_mut(&mut self) -> &mut ClientRngBox {
519        &mut self.0
520    }
521}
522
523impl RngCore for ClientRng {
524    fn next_u32(&mut self) -> u32 {
525        self.0.next_u32()
526    }
527
528    fn next_u64(&mut self) -> u64 {
529        self.0.next_u64()
530    }
531
532    fn fill_bytes(&mut self, dest: &mut [u8]) {
533        self.0.fill_bytes(dest);
534    }
535}
536
537impl FeltRng for ClientRng {
538    fn draw_element(&mut self) -> Felt {
539        self.0.draw_element()
540    }
541
542    fn draw_word(&mut self) -> Word {
543        self.0.draw_word()
544    }
545}
546
547/// Indicates whether the client is operating in debug mode.
548#[derive(Debug, Clone, Copy)]
549pub enum DebugMode {
550    Enabled,
551    Disabled,
552}
553
554impl From<DebugMode> for bool {
555    fn from(debug_mode: DebugMode) -> Self {
556        match debug_mode {
557            DebugMode::Enabled => true,
558            DebugMode::Disabled => false,
559        }
560    }
561}
562
563impl From<bool> for DebugMode {
564    fn from(debug_mode: bool) -> DebugMode {
565        if debug_mode {
566            DebugMode::Enabled
567        } else {
568            DebugMode::Disabled
569        }
570    }
571}
572
573#[cfg(test)]
574mod tests {
575    use super::Client;
576
577    fn assert_send_sync<T: Send + Sync>() {}
578
579    #[test]
580    fn client_is_send_sync() {
581        assert_send_sync::<Client<()>>();
582    }
583}