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//! - **Assets:** Types and utilities for working with assets.
32//! - **Auth:** Authentication-related types and functionalities.
33//! - **Blocks:** Types for handling block headers.
34//! - **Crypto:** Cryptographic types and utilities, including random number generators.
35//! - **Utils:** Miscellaneous utilities for serialization and common operations.
36//!
37//! The library is designed to work in both `no_std` and `std` environments and is
38//! configurable via Cargo features.
39//!
40//! ## Usage
41//!
42//! To use the Miden client library in your project, add it as a dependency in your `Cargo.toml`:
43//!
44//! ```toml
45//! [dependencies]
46//! miden-client = "0.9"
47//! ```
48//!
49//! ## Example
50//!
51//! Below is a brief example illustrating how to instantiate the client:
52//!
53//! ```rust
54//! use std::sync::Arc;
55//!
56//! use miden_client::{
57//!     Client, Felt,
58//!     crypto::RpoRandomCoin,
59//!     keystore::FilesystemKeyStore,
60//!     rpc::{Endpoint, TonicRpcClient},
61//!     store::{Store, sqlite_store::SqliteStore},
62//! };
63//! use miden_objects::crypto::rand::FeltRng;
64//! use rand::{Rng, rngs::StdRng};
65//!
66//! # pub async fn create_test_client() -> Result<(), Box<dyn std::error::Error>> {
67//! // Create the SQLite store from the client configuration.
68//! let sqlite_store = SqliteStore::new("path/to/store".try_into()?).await?;
69//! let store = Arc::new(sqlite_store);
70//!
71//! // Generate a random seed for the RpoRandomCoin.
72//! let mut rng = rand::rng();
73//! let coin_seed: [u64; 4] = rng.random();
74//!
75//! // Initialize the random coin using the generated seed.
76//! let rng = RpoRandomCoin::new(coin_seed.map(Felt::new));
77//! let keystore = FilesystemKeyStore::new("path/to/keys/directory".try_into()?)?;
78//!
79//! // Determine the number of blocks to consider a transaction stale.
80//! // 20 is simply an example value.
81//! let tx_graceful_blocks = Some(20);
82//! // Determine the maximum number of blocks that the client can be behind from the network.
83//! // 256 is simply an example value.
84//! let max_block_number_delta = Some(256);
85//!
86//! // Instantiate the client using a Tonic RPC client
87//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
88//! let client: Client = Client::new(
89//!     Arc::new(TonicRpcClient::new(&endpoint, 10_000)),
90//!     Box::new(rng),
91//!     store,
92//!     Arc::new(keystore),
93//!     false, // Set to true for debug mode, if needed.
94//!     tx_graceful_blocks,
95//!     max_block_number_delta,
96//! );
97//!
98//! # Ok(())
99//! # }
100//! ```
101//!
102//! For additional usage details, configuration options, and examples, consult the documentation for
103//! each module.
104
105#![no_std]
106
107#[macro_use]
108extern crate alloc;
109use alloc::boxed::Box;
110
111#[cfg(feature = "std")]
112extern crate std;
113
114pub mod account;
115pub mod keystore;
116pub mod note;
117pub mod rpc;
118pub mod store;
119pub mod sync;
120pub mod transaction;
121
122#[cfg(feature = "std")]
123pub mod builder;
124
125#[cfg(feature = "testing")]
126mod test_utils;
127
128#[cfg(test)]
129pub mod tests;
130
131mod errors;
132
133// RE-EXPORTS
134// ================================================================================================
135
136/// Provides types and utilities for working with assets within the Miden network.
137pub mod asset {
138    pub use miden_objects::{
139        account::delta::{
140            AccountVaultDelta, FungibleAssetDelta, NonFungibleAssetDelta, NonFungibleDeltaAction,
141        },
142        asset::{Asset, AssetVault, FungibleAsset, NonFungibleAsset, TokenSymbol},
143    };
144}
145
146/// Provides authentication-related types and functionalities for the Miden
147/// network.
148pub mod auth {
149    pub use miden_lib::AuthScheme;
150    pub use miden_objects::account::AuthSecretKey;
151    pub use miden_tx::auth::{BasicAuthenticator, TransactionAuthenticator};
152}
153
154/// Provides types for working with blocks within the Miden network.
155pub mod block {
156    pub use miden_objects::block::BlockHeader;
157}
158
159/// Provides cryptographic types and utilities used within the Miden rollup
160/// network. It re-exports commonly used types and random number generators like `FeltRng` from
161/// the `miden_objects` crate.
162pub mod crypto {
163    pub use miden_objects::{
164        Digest,
165        crypto::{
166            dsa::rpo_falcon512::SecretKey,
167            merkle::{
168                InOrderIndex, LeafIndex, MerklePath, MmrDelta, MmrPeaks, MmrProof, SmtLeaf,
169                SmtProof,
170            },
171            rand::{FeltRng, RpoRandomCoin},
172        },
173    };
174}
175
176pub use errors::{AuthenticationError, ClientError, IdPrefixFetchError};
177pub use miden_objects::{Felt, ONE, StarkField, Word, ZERO};
178pub use miden_proving_service_client::proving_service::tx_prover::RemoteTransactionProver;
179
180/// Provides various utilities that are commonly used throughout the Miden
181/// client library.
182pub mod utils {
183    pub use miden_tx::utils::{
184        ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
185        bytes_to_hex_string,
186        sync::{LazyLock, RwLock, RwLockReadGuard, RwLockWriteGuard},
187    };
188}
189
190/// Provides test utilities for working with accounts and account IDs
191/// within the Miden network. This module is only available when the `testing` feature is
192/// enabled.
193#[cfg(feature = "testing")]
194pub mod testing {
195    pub use miden_objects::testing::*;
196
197    pub use crate::test_utils::*;
198}
199
200use alloc::sync::Arc;
201
202use miden_objects::crypto::rand::FeltRng;
203use miden_tx::{
204    LocalTransactionProver, TransactionExecutor, TransactionMastStore,
205    auth::TransactionAuthenticator,
206};
207use rand::RngCore;
208use rpc::NodeRpcClient;
209use store::{Store, data_store::ClientDataStore};
210use tracing::info;
211
212// MIDEN CLIENT
213// ================================================================================================
214
215/// A light client for connecting to the Miden network.
216///
217/// Miden client is responsible for managing a set of accounts. Specifically, the client:
218/// - Keeps track of the current and historical states of a set of accounts and related objects such
219///   as notes and transactions.
220/// - Connects to a Miden node to periodically sync with the current state of the network.
221/// - Executes, proves, and submits transactions to the network as directed by the user.
222pub struct Client {
223    /// The client's store, which provides a way to write and read entities to provide persistence.
224    store: Arc<dyn Store>,
225    /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
226    /// serial numbers, etc.
227    rng: ClientRng,
228    /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
229    /// Miden node.
230    rpc_api: Arc<dyn NodeRpcClient + Send>,
231    /// An instance of a [`LocalTransactionProver`] which will be the default prover for the
232    /// client.
233    tx_prover: Arc<LocalTransactionProver>,
234    /// An instance of a [`TransactionExecutor`] that will be used to execute transactions.
235    tx_executor: TransactionExecutor,
236    /// A MAST store, used to provide code inputs to the VM.
237    mast_store: Arc<TransactionMastStore>,
238    /// Flag to enable the debug mode for scripts compilation and execution.
239    in_debug_mode: bool,
240    /// The number of blocks that are considered old enough to discard pending transactions.
241    tx_graceful_blocks: Option<u32>,
242    /// Maximum number of blocks the client can be behind the network for transactions and account
243    /// proofs to be considered valid.
244    max_block_number_delta: Option<u32>,
245}
246
247/// Construction and access methods.
248impl Client {
249    // CONSTRUCTOR
250    // --------------------------------------------------------------------------------------------
251
252    /// Returns a new instance of [`Client`].
253    ///
254    /// ## Arguments
255    ///
256    /// - `api`: An instance of [`NodeRpcClient`] which provides a way for the client to connect to
257    ///   the Miden node.
258    /// - `store`: An instance of [`Store`], which provides a way to write and read entities to
259    ///   provide persistence.
260    /// - `executor_store`: An instance of [`Store`] that provides a way for [`TransactionExecutor`]
261    ///   to retrieve relevant inputs at the moment of transaction execution. It should be the same
262    ///   store as the one for `store`, but it doesn't have to be the **same instance**.
263    /// - `authenticator`: Defines the transaction authenticator that will be used by the
264    ///   transaction executor whenever a signature is requested from within the VM.
265    /// - `in_debug_mode`: Instantiates the transaction executor (and in turn, its compiler) in
266    ///   debug mode, which will enable debug logs for scripts compiled with this mode for easier
267    ///   MASM debugging.
268    /// - `tx_graceful_blocks`: The number of blocks that are considered old enough to discard
269    ///   pending transactions.
270    /// - `max_block_number_delta`: Determines the maximum number of blocks that the client can be
271    ///   behind the network for transactions and account proofs to be considered valid.
272    ///
273    /// # Errors
274    ///
275    /// Returns an error if the client couldn't be instantiated.
276    pub fn new(
277        rpc_api: Arc<dyn NodeRpcClient + Send>,
278        rng: Box<dyn FeltRng>,
279        store: Arc<dyn Store>,
280        authenticator: Arc<dyn TransactionAuthenticator>,
281        in_debug_mode: bool,
282        tx_graceful_blocks: Option<u32>,
283        max_block_number_delta: Option<u32>,
284    ) -> Self {
285        let client_data_store = Arc::new(ClientDataStore::new(store.clone()));
286        let mast_store = client_data_store.mast_store();
287
288        let authenticator = Some(authenticator);
289        let mut tx_executor = TransactionExecutor::new(client_data_store, authenticator);
290        let tx_prover = Arc::new(LocalTransactionProver::default());
291
292        if in_debug_mode {
293            info!("Creating the Client in debug mode.");
294            tx_executor = tx_executor.with_debug_mode();
295        }
296
297        Self {
298            store,
299            rng: ClientRng::new(rng),
300            rpc_api,
301            tx_prover,
302            tx_executor,
303            in_debug_mode,
304            tx_graceful_blocks,
305            max_block_number_delta,
306            mast_store,
307        }
308    }
309
310    /// Returns true if the client is in debug mode.
311    pub fn is_in_debug_mode(&self) -> bool {
312        self.in_debug_mode
313    }
314
315    /// Returns a reference to the client's random number generator. This can be used to generate
316    /// randomness for various purposes such as serial numbers, keys, etc.
317    pub fn rng(&mut self) -> &mut ClientRng {
318        &mut self.rng
319    }
320
321    // TEST HELPERS
322    // --------------------------------------------------------------------------------------------
323
324    #[cfg(any(test, feature = "testing"))]
325    pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient + Send> {
326        &mut self.rpc_api
327    }
328
329    #[cfg(any(test, feature = "testing"))]
330    pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
331        &mut self.store
332    }
333}
334
335// CLIENT RNG
336// ================================================================================================
337
338/// A wrapper around a [`FeltRng`] that implements the [`RngCore`] trait.
339/// This allows the user to pass their own generic RNG so that it's used by the client.
340pub struct ClientRng(Box<dyn FeltRng>);
341
342impl ClientRng {
343    pub fn new(rng: Box<dyn FeltRng>) -> Self {
344        Self(rng)
345    }
346
347    pub fn inner_mut(&mut self) -> &mut Box<dyn FeltRng> {
348        &mut self.0
349    }
350}
351
352impl RngCore for ClientRng {
353    fn next_u32(&mut self) -> u32 {
354        self.0.next_u32()
355    }
356
357    fn next_u64(&mut self) -> u64 {
358        self.0.next_u64()
359    }
360
361    fn fill_bytes(&mut self, dest: &mut [u8]) {
362        self.0.fill_bytes(dest);
363    }
364}
365
366impl FeltRng for ClientRng {
367    fn draw_element(&mut self) -> Felt {
368        self.0.draw_element()
369    }
370
371    fn draw_word(&mut self) -> Word {
372        self.0.draw_word()
373    }
374}