miden_client/
lib.rs

1//! A no_std-compatible client library for interacting with the Miden network.
2//!
3//! This crate provides a lightweight client that handles connections to the Miden node, manages
4//! accounts and their state, and facilitates executing, proving, and submitting transactions.
5//!
6//! For a protocol-level overview and guides for getting started, please visit the official
7//! [Miden docs](https://0xMiden.github.io/miden-docs/).
8//!
9//! ## Overview
10//!
11//! The library is organized into several key modules:
12//!
13//! - **Accounts:** Provides types for managing accounts. Once accounts are tracked by the client,
14//!   their state is updated with every transaction and validated during each sync.
15//!
16//! - **Notes:** Contains types and utilities for working with notes in the Miden client.
17//!
18//! - **RPC:** Facilitates communication with Miden node, exposing RPC methods for syncing state,
19//!   fetching block headers, and submitting transactions.
20//!
21//! - **Store:** Defines and implements the persistence layer for accounts, transactions, notes, and
22//!   other entities.
23//!
24//! - **Sync:** Provides functionality to synchronize the local state with the current state on the
25//!   Miden network.
26//!
27//! - **Transactions:** Offers capabilities to build, execute, prove, and submit transactions.
28//!
29//! Additionally, the crate re-exports several utility modules:
30//!
31//! - **Assembly:** Types for working with Miden Assembly.
32//! - **Assets:** Types and utilities for working with assets.
33//! - **Auth:** Authentication-related types and functionalities.
34//! - **Blocks:** Types for handling block headers.
35//! - **Crypto:** Cryptographic types and utilities, including random number generators.
36//! - **Utils:** Miscellaneous utilities for serialization and common operations.
37//!
38//! The library is designed to work in both `no_std` and `std` environments and is
39//! configurable via Cargo features.
40//!
41//! ## Usage
42//!
43//! To use the Miden client library in your project, add it as a dependency in your `Cargo.toml`:
44//!
45//! ```toml
46//! [dependencies]
47//! miden-client = "0.10"
48//! ```
49//!
50//! ## Example
51//!
52//! Below is a brief example illustrating how to instantiate the client:
53//!
54//! ```rust
55//! use std::sync::Arc;
56//!
57//! use miden_client::crypto::RpoRandomCoin;
58//! use miden_client::keystore::FilesystemKeyStore;
59//! use miden_client::rpc::{Endpoint, TonicRpcClient};
60//! use miden_client::store::Store;
61//! use miden_client::store::sqlite_store::SqliteStore;
62//! use miden_client::{Client, ExecutionOptions, Felt};
63//! use miden_objects::crypto::rand::FeltRng;
64//! use miden_objects::{MAX_TX_EXECUTION_CYCLES, MIN_TX_EXECUTION_CYCLES};
65//! use rand::Rng;
66//! use rand::rngs::StdRng;
67//!
68//! # pub async fn create_test_client() -> Result<(), Box<dyn std::error::Error>> {
69//! // Create the SQLite store from the client configuration.
70//! let sqlite_store = SqliteStore::new("path/to/store".try_into()?).await?;
71//! let store = Arc::new(sqlite_store);
72//!
73//! // Generate a random seed for the RpoRandomCoin.
74//! let mut rng = rand::rng();
75//! let coin_seed: [u64; 4] = rng.random();
76//!
77//! // Initialize the random coin using the generated seed.
78//! let rng = RpoRandomCoin::new(coin_seed.map(Felt::new).into());
79//! let keystore = FilesystemKeyStore::new("path/to/keys/directory".try_into()?)?;
80//!
81//! // Determine the number of blocks to consider a transaction stale.
82//! // 20 is simply an example value.
83//! let tx_graceful_blocks = Some(20);
84//! // Determine the maximum number of blocks that the client can be behind from the network.
85//! // 256 is simply an example value.
86//! let max_block_number_delta = Some(256);
87//!
88//! // Instantiate the client using a Tonic RPC client
89//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
90//! let client: Client<FilesystemKeyStore<StdRng>> = Client::new(
91//!     Arc::new(TonicRpcClient::new(&endpoint, 10_000)),
92//!     Box::new(rng),
93//!     store,
94//!     Some(Arc::new(keystore)), // or None if no authenticator is needed
95//!     ExecutionOptions::new(
96//!         Some(MAX_TX_EXECUTION_CYCLES),
97//!         MIN_TX_EXECUTION_CYCLES,
98//!         false,
99//!         false, // Set to true for debug mode, if needed.
100//!     )
101//!     .unwrap(),
102//!     tx_graceful_blocks,
103//!     max_block_number_delta,
104//! )
105//! .await
106//! .unwrap();
107//!
108//! # Ok(())
109//! # }
110//! ```
111//!
112//! For additional usage details, configuration options, and examples, consult the documentation for
113//! each module.
114
115#![no_std]
116
117#[macro_use]
118extern crate alloc;
119use alloc::boxed::Box;
120
121#[cfg(feature = "std")]
122extern crate std;
123
124pub mod account;
125pub mod keystore;
126pub mod note;
127pub mod rpc;
128pub mod store;
129pub mod sync;
130pub mod transaction;
131pub mod utils;
132
133#[cfg(feature = "std")]
134pub mod builder;
135
136#[cfg(feature = "testing")]
137mod test_utils;
138
139#[cfg(test)]
140pub mod tests;
141
142mod errors;
143
144// RE-EXPORTS
145// ================================================================================================
146
147/// Provides types and utilities for working with Miden Assembly.
148pub mod assembly {
149    pub use miden_objects::assembly::{
150        Assembler,
151        DefaultSourceManager,
152        Library,
153        LibraryPath,
154        Module,
155        ModuleKind,
156    };
157}
158
159/// Provides types and utilities for working with assets within the Miden network.
160pub mod asset {
161    pub use miden_objects::AssetError;
162    pub use miden_objects::account::delta::{
163        AccountVaultDelta,
164        FungibleAssetDelta,
165        NonFungibleAssetDelta,
166        NonFungibleDeltaAction,
167    };
168    pub use miden_objects::asset::{
169        Asset,
170        AssetVault,
171        FungibleAsset,
172        NonFungibleAsset,
173        TokenSymbol,
174    };
175}
176
177/// Provides authentication-related types and functionalities for the Miden
178/// network.
179pub mod auth {
180    pub use miden_lib::AuthScheme;
181    pub use miden_objects::account::AuthSecretKey;
182    pub use miden_tx::auth::{BasicAuthenticator, SigningInputs, TransactionAuthenticator};
183}
184
185/// Provides types for working with blocks within the Miden network.
186pub mod block {
187    pub use miden_objects::block::BlockHeader;
188}
189
190/// Provides cryptographic types and utilities used within the Miden rollup
191/// network. It re-exports commonly used types and random number generators like `FeltRng` from
192/// the `miden_objects` crate.
193pub mod crypto {
194    pub use miden_objects::crypto::dsa::rpo_falcon512::SecretKey;
195    pub use miden_objects::crypto::hash::rpo::Rpo256;
196    pub use miden_objects::crypto::merkle::{
197        InOrderIndex,
198        LeafIndex,
199        MerklePath,
200        MerkleStore,
201        MerkleTree,
202        MmrDelta,
203        MmrPeaks,
204        MmrProof,
205        NodeIndex,
206        SmtLeaf,
207        SmtProof,
208    };
209    pub use miden_objects::crypto::rand::{FeltRng, RpoRandomCoin};
210}
211
212pub use errors::{AuthenticationError, ClientError, IdPrefixFetchError};
213pub use miden_objects::{EMPTY_WORD, Felt, ONE, StarkField, Word, ZERO};
214pub use miden_remote_prover_client::remote_prover::tx_prover::RemoteTransactionProver;
215pub use miden_tx::ExecutionOptions;
216
217/// Provides test utilities for working with accounts and account IDs
218/// within the Miden network. This module is only available when the `testing` feature is
219/// enabled.
220#[cfg(feature = "testing")]
221pub mod testing {
222    pub use miden_lib::testing::note::NoteBuilder;
223    pub use miden_objects::testing::*;
224    pub use miden_testing::*;
225
226    pub use crate::test_utils::*;
227}
228
229use alloc::sync::Arc;
230
231pub use miden_lib::utils::ScriptBuilder;
232use miden_objects::block::BlockNumber;
233use miden_objects::crypto::rand::FeltRng;
234use miden_tx::LocalTransactionProver;
235use miden_tx::auth::TransactionAuthenticator;
236use rand::RngCore;
237use rpc::NodeRpcClient;
238use store::Store;
239
240// MIDEN CLIENT
241// ================================================================================================
242
243/// A light client for connecting to the Miden network.
244///
245/// Miden client is responsible for managing a set of accounts. Specifically, the client:
246/// - Keeps track of the current and historical states of a set of accounts and related objects such
247///   as notes and transactions.
248/// - Connects to a Miden node to periodically sync with the current state of the network.
249/// - Executes, proves, and submits transactions to the network as directed by the user.
250pub struct Client<AUTH> {
251    /// The client's store, which provides a way to write and read entities to provide persistence.
252    store: Arc<dyn Store>,
253    /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
254    /// serial numbers, etc.
255    rng: ClientRng,
256    /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
257    /// Miden node.
258    rpc_api: Arc<dyn NodeRpcClient + Send>,
259    /// An instance of a [`LocalTransactionProver`] which will be the default prover for the
260    /// client.
261    tx_prover: Arc<LocalTransactionProver>,
262    /// An instance of a [`TransactionAuthenticator`] which will be used by the transaction
263    /// executor whenever a signature is requested from within the VM.
264    authenticator: Option<Arc<AUTH>>,
265    /// Options that control the transaction executor’s runtime behaviour (e.g. debug mode).
266    exec_options: ExecutionOptions,
267    /// The number of blocks that are considered old enough to discard pending transactions.
268    tx_graceful_blocks: Option<u32>,
269    /// Maximum number of blocks the client can be behind the network for transactions and account
270    /// proofs to be considered valid.
271    max_block_number_delta: Option<u32>,
272}
273
274/// Construction and access methods.
275impl<AUTH> Client<AUTH>
276where
277    AUTH: TransactionAuthenticator,
278{
279    // CONSTRUCTOR
280    // --------------------------------------------------------------------------------------------
281
282    /// Returns a new instance of [`Client`].
283    ///
284    /// ## Arguments
285    ///
286    /// - `api`: An instance of [`NodeRpcClient`] which provides a way for the client to connect to
287    ///   the Miden node.
288    /// - `rng`: An instance of [`FeltRng`] which provides randomness tools for generating new keys,
289    ///   serial numbers, etc. This can be any RNG that implements the [`FeltRng`] trait.
290    /// - `store`: An instance of [`Store`], which provides a way to write and read entities to
291    ///   provide persistence.
292    /// - `authenticator`: Defines the transaction authenticator that will be used by the
293    ///   transaction executor whenever a signature is requested from within the VM.
294    /// - `exec_options`: Options that control the transaction executor’s runtime behaviour (e.g.
295    ///   debug mode).
296    /// - `tx_graceful_blocks`: The number of blocks that are considered old enough to discard
297    ///   pending transactions.
298    /// - `max_block_number_delta`: Determines the maximum number of blocks that the client can be
299    ///   behind the network for transactions and account proofs to be considered valid.
300    ///
301    /// # Errors
302    ///
303    /// Returns an error if the client couldn't be instantiated.
304    pub async fn new(
305        rpc_api: Arc<dyn NodeRpcClient + Send>,
306        rng: Box<dyn FeltRng>,
307        store: Arc<dyn Store>,
308        authenticator: Option<Arc<AUTH>>,
309        exec_options: ExecutionOptions,
310        tx_graceful_blocks: Option<u32>,
311        max_block_number_delta: Option<u32>,
312    ) -> Result<Self, ClientError> {
313        let tx_prover = Arc::new(LocalTransactionProver::default());
314
315        if let Some((genesis, _)) = store.get_block_header_by_num(BlockNumber::GENESIS).await? {
316            // Set the genesis commitment in the RPC API client for future requests.
317            rpc_api.set_genesis_commitment(genesis.commitment()).await?;
318        }
319
320        Ok(Self {
321            store,
322            rng: ClientRng::new(rng),
323            rpc_api,
324            tx_prover,
325            authenticator,
326            exec_options,
327            tx_graceful_blocks,
328            max_block_number_delta,
329        })
330    }
331
332    /// Returns true if the client is in debug mode.
333    pub fn in_debug_mode(&self) -> bool {
334        self.exec_options.enable_debugging()
335    }
336
337    /// Returns an instance of the `ScriptBuilder`
338    pub fn script_builder(&self) -> ScriptBuilder {
339        ScriptBuilder::new(self.in_debug_mode())
340    }
341
342    /// Returns a reference to the client's random number generator. This can be used to generate
343    /// randomness for various purposes such as serial numbers, keys, etc.
344    pub fn rng(&mut self) -> &mut ClientRng {
345        &mut self.rng
346    }
347
348    // TEST HELPERS
349    // --------------------------------------------------------------------------------------------
350
351    #[cfg(any(test, feature = "testing"))]
352    pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient + Send> {
353        &mut self.rpc_api
354    }
355
356    #[cfg(any(test, feature = "testing"))]
357    pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
358        &mut self.store
359    }
360}
361
362// CLIENT RNG
363// ================================================================================================
364
365/// A wrapper around a [`FeltRng`] that implements the [`RngCore`] trait.
366/// This allows the user to pass their own generic RNG so that it's used by the client.
367pub struct ClientRng(Box<dyn FeltRng>);
368
369impl ClientRng {
370    pub fn new(rng: Box<dyn FeltRng>) -> Self {
371        Self(rng)
372    }
373
374    pub fn inner_mut(&mut self) -> &mut Box<dyn FeltRng> {
375        &mut self.0
376    }
377}
378
379impl RngCore for ClientRng {
380    fn next_u32(&mut self) -> u32 {
381        self.0.next_u32()
382    }
383
384    fn next_u64(&mut self) -> u64 {
385        self.0.next_u64()
386    }
387
388    fn fill_bytes(&mut self, dest: &mut [u8]) {
389        self.0.fill_bytes(dest);
390    }
391}
392
393impl FeltRng for ClientRng {
394    fn draw_element(&mut self) -> Felt {
395        self.0.draw_element()
396    }
397
398    fn draw_word(&mut self) -> Word {
399        self.0.draw_word()
400    }
401}
402
403/// Indicates whether the client is operating in debug mode.
404pub enum DebugMode {
405    Enabled,
406    Disabled,
407}
408
409impl From<DebugMode> for bool {
410    fn from(debug_mode: DebugMode) -> Self {
411        match debug_mode {
412            DebugMode::Enabled => true,
413            DebugMode::Disabled => false,
414        }
415    }
416}
417
418impl From<bool> for DebugMode {
419    fn from(debug_mode: bool) -> DebugMode {
420        if debug_mode {
421            DebugMode::Enabled
422        } else {
423            DebugMode::Disabled
424        }
425    }
426}