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}