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//! [Polygon Miden docs](https://0xpolygonmiden.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.8"
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//! // Instantiate the client using a Tonic RPC client
80//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
81//! let client: Client = Client::new(
82//! Arc::new(TonicRpcClient::new(&endpoint, 10_000)),
83//! Box::new(rng),
84//! store,
85//! Arc::new(keystore),
86//! false, // Set to true for debug mode, if needed.
87//! );
88//!
89//! # Ok(())
90//! # }
91//! ```
92//!
93//! For additional usage details, configuration options, and examples, consult the documentation for
94//! each module.
95
96#![no_std]
97
98#[macro_use]
99extern crate alloc;
100use alloc::boxed::Box;
101
102#[cfg(feature = "std")]
103extern crate std;
104
105pub mod account;
106pub mod keystore;
107pub mod note;
108pub mod rpc;
109pub mod store;
110pub mod sync;
111pub mod transaction;
112
113#[cfg(feature = "std")]
114pub mod builder;
115
116#[cfg(test)]
117pub mod mock;
118
119#[cfg(test)]
120pub mod tests;
121
122mod errors;
123
124// RE-EXPORTS
125// ================================================================================================
126
127/// Provides types and utilities for working with assets within the Miden network.
128pub mod asset {
129 pub use miden_objects::{
130 account::delta::{
131 AccountVaultDelta, FungibleAssetDelta, NonFungibleAssetDelta, NonFungibleDeltaAction,
132 },
133 asset::{Asset, AssetVault, FungibleAsset, NonFungibleAsset, TokenSymbol},
134 };
135}
136
137/// Provides authentication-related types and functionalities for the Miden
138/// network.
139pub mod auth {
140 pub use miden_lib::AuthScheme;
141 pub use miden_objects::account::AuthSecretKey;
142 pub use miden_tx::auth::{BasicAuthenticator, TransactionAuthenticator};
143}
144
145/// Provides types for working with blocks within the Miden network.
146pub mod block {
147 pub use miden_objects::block::BlockHeader;
148}
149
150/// Provides cryptographic types and utilities used within the Miden rollup
151/// network. It re-exports commonly used types and random number generators like `FeltRng` from
152/// the `miden_objects` crate.
153pub mod crypto {
154 pub use miden_objects::{
155 Digest,
156 crypto::{
157 dsa::rpo_falcon512::SecretKey,
158 merkle::{
159 InOrderIndex, LeafIndex, MerklePath, MmrDelta, MmrPeaks, MmrProof, SmtLeaf,
160 SmtProof,
161 },
162 rand::{FeltRng, RpoRandomCoin},
163 },
164 };
165}
166
167pub use errors::{AuthenticationError, ClientError, IdPrefixFetchError};
168pub use miden_objects::{Felt, ONE, StarkField, Word, ZERO};
169pub use miden_proving_service_client::proving_service::tx_prover::RemoteTransactionProver;
170
171/// Provides various utilities that are commonly used throughout the Miden
172/// client library.
173pub mod utils {
174 pub use miden_tx::utils::{
175 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
176 bytes_to_hex_string,
177 sync::{LazyLock, RwLock, RwLockReadGuard, RwLockWriteGuard},
178 };
179}
180
181/// Provides test utilities for working with accounts and account IDs
182/// within the Miden network. This module is only available when the `testing` feature is
183/// enabled.
184#[cfg(feature = "testing")]
185pub mod testing {
186 pub use miden_objects::testing::*;
187}
188
189use alloc::sync::Arc;
190
191use miden_objects::crypto::rand::FeltRng;
192use miden_tx::{
193 DataStore, LocalTransactionProver, TransactionExecutor, auth::TransactionAuthenticator,
194};
195use rand::RngCore;
196use rpc::NodeRpcClient;
197use store::{Store, data_store::ClientDataStore};
198use tracing::info;
199
200// MIDEN CLIENT
201// ================================================================================================
202
203/// A light client for connecting to the Miden network.
204///
205/// Miden client is responsible for managing a set of accounts. Specifically, the client:
206/// - Keeps track of the current and historical states of a set of accounts and related objects such
207/// as notes and transactions.
208/// - Connects to a Miden node to periodically sync with the current state of the network.
209/// - Executes, proves, and submits transactions to the network as directed by the user.
210pub struct Client {
211 /// The client's store, which provides a way to write and read entities to provide persistence.
212 store: Arc<dyn Store>,
213 /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
214 /// serial numbers, etc.
215 rng: ClientRng,
216 /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
217 /// Miden node.
218 rpc_api: Arc<dyn NodeRpcClient + Send>,
219 /// An instance of a [`LocalTransactionProver`] which will be the default prover for the
220 /// client.
221 tx_prover: Arc<LocalTransactionProver>,
222 /// An instance of a [`TransactionExecutor`] that will be used to execute transactions.
223 tx_executor: TransactionExecutor,
224 /// Flag to enable the debug mode for scripts compilation and execution.
225 in_debug_mode: bool,
226}
227
228/// Construction and access methods.
229impl Client {
230 // CONSTRUCTOR
231 // --------------------------------------------------------------------------------------------
232
233 /// Returns a new instance of [`Client`].
234 ///
235 /// ## Arguments
236 ///
237 /// - `api`: An instance of [`NodeRpcClient`] which provides a way for the client to connect to
238 /// the Miden node.
239 /// - `store`: An instance of [`Store`], which provides a way to write and read entities to
240 /// provide persistence.
241 /// - `executor_store`: An instance of [`Store`] that provides a way for [`TransactionExecutor`]
242 /// to retrieve relevant inputs at the moment of transaction execution. It should be the same
243 /// store as the one for `store`, but it doesn't have to be the **same instance**.
244 /// - `authenticator`: Defines the transaction authenticator that will be used by the
245 /// transaction executor whenever a signature is requested from within the VM.
246 /// - `in_debug_mode`: Instantiates the transaction executor (and in turn, its compiler) in
247 /// debug mode, which will enable debug logs for scripts compiled with this mode for easier
248 /// MASM debugging.
249 ///
250 /// # Errors
251 ///
252 /// Returns an error if the client couldn't be instantiated.
253 pub fn new(
254 rpc_api: Arc<dyn NodeRpcClient + Send>,
255 rng: Box<dyn FeltRng>,
256 store: Arc<dyn Store>,
257 authenticator: Arc<dyn TransactionAuthenticator>,
258 in_debug_mode: bool,
259 ) -> Self {
260 let data_store = Arc::new(ClientDataStore::new(store.clone())) as Arc<dyn DataStore>;
261 let authenticator = Some(authenticator);
262 let mut tx_executor = TransactionExecutor::new(data_store, authenticator);
263 let tx_prover = Arc::new(LocalTransactionProver::default());
264
265 if in_debug_mode {
266 info!("Creating the Client in debug mode.");
267 tx_executor = tx_executor.with_debug_mode();
268 }
269
270 Self {
271 store,
272 rng: ClientRng::new(rng),
273 rpc_api,
274 tx_prover,
275 tx_executor,
276 in_debug_mode,
277 }
278 }
279
280 /// Returns true if the client is in debug mode.
281 pub fn is_in_debug_mode(&self) -> bool {
282 self.in_debug_mode
283 }
284
285 /// Returns a reference to the client's random number generator. This can be used to generate
286 /// randomness for various purposes such as serial numbers, keys, etc.
287 pub fn rng(&mut self) -> &mut ClientRng {
288 &mut self.rng
289 }
290
291 // TEST HELPERS
292 // --------------------------------------------------------------------------------------------
293
294 #[cfg(any(test, feature = "testing"))]
295 pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient + Send> {
296 &mut self.rpc_api
297 }
298
299 #[cfg(any(test, feature = "testing"))]
300 pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
301 &mut self.store
302 }
303}
304
305// CLIENT RNG
306// ================================================================================================
307
308/// A wrapper around a [`FeltRng`] that implements the [`RngCore`] trait.
309/// This allows the user to pass their own generic RNG so that it's used by the client.
310pub struct ClientRng(Box<dyn FeltRng>);
311
312impl ClientRng {
313 pub fn new(rng: Box<dyn FeltRng>) -> Self {
314 Self(rng)
315 }
316
317 pub fn inner_mut(&mut self) -> &mut Box<dyn FeltRng> {
318 &mut self.0
319 }
320}
321
322impl RngCore for ClientRng {
323 fn next_u32(&mut self) -> u32 {
324 self.0.next_u32()
325 }
326
327 fn next_u64(&mut self) -> u64 {
328 self.0.next_u64()
329 }
330
331 fn fill_bytes(&mut self, dest: &mut [u8]) {
332 self.0.fill_bytes(dest);
333 }
334}
335
336impl FeltRng for ClientRng {
337 fn draw_element(&mut self) -> Felt {
338 self.0.draw_element()
339 }
340
341 fn draw_word(&mut self) -> Word {
342 self.0.draw_word()
343 }
344}