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://docs.miden.xyz/).
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//! - **`AggLayer`:** Bridge account components, note constructors, and Ethereum-compatible helper
40//!   types from the Miden `AggLayer` protocol crate.
41//!
42//! The library is designed to work in both `no_std` and `std` environments and is
43//! configurable via Cargo features.
44//!
45//! ## Usage
46//!
47//! To use the Miden client library in your project, add it as a dependency in your `Cargo.toml`:
48//!
49//! ```toml
50//! [dependencies]
51//! miden-client = "0.10"
52//! ```
53//!
54//! ## Example
55//!
56//! Below is a brief example illustrating how to instantiate the client using `ClientBuilder`:
57//!
58//! ```rust,ignore
59//! use std::sync::Arc;
60//!
61//! use miden_client::DebugMode;
62//! use miden_client::builder::ClientBuilder;
63//! use miden_client::keystore::FilesystemKeyStore;
64//! use miden_client::rpc::{Endpoint, GrpcClient};
65//! use miden_client_sqlite_store::SqliteStore;
66//!
67//! # pub async fn create_test_client() -> Result<(), Box<dyn std::error::Error>> {
68//! // Create the SQLite store.
69//! let sqlite_store = SqliteStore::new("path/to/store".try_into()?).await?;
70//! let store = Arc::new(sqlite_store);
71//!
72//! // Create the keystore for transaction signing.
73//! let keystore = FilesystemKeyStore::new("path/to/keys/directory".try_into()?)?;
74//!
75//! // Create the RPC client.
76//! let endpoint = Endpoint::new("https".into(), "localhost".into(), Some(57291));
77//!
78//! // Instantiate the client using the builder.
79//! let client = ClientBuilder::new()
80//!     .rpc(Arc::new(GrpcClient::new(&endpoint, 10_000)))
81//!     .store(store)
82//!     .authenticator(Arc::new(keystore))
83//!     .in_debug_mode(DebugMode::Disabled)
84//!     .build()
85//!     .await?;
86//!
87//! # Ok(())
88//! # }
89//! ```
90//!
91//! For network-specific defaults, use the convenience constructors:
92//!
93//! ```ignore
94//! // For testnet (includes remote prover and note transport)
95//! let client = ClientBuilder::for_testnet()
96//!     .store(store)
97//!     .authenticator(Arc::new(keystore))
98//!     .build()
99//!     .await?;
100//!
101//! // For local development
102//! let client = ClientBuilder::for_localhost()
103//!     .store(store)
104//!     .authenticator(Arc::new(keystore))
105//!     .build()
106//!     .await?;
107//! ```
108//!
109//! For additional usage details, configuration options, and examples, consult the documentation for
110//! each module.
111
112#![no_std]
113
114#[macro_use]
115extern crate alloc;
116use alloc::boxed::Box;
117
118#[cfg(feature = "std")]
119extern crate std;
120
121pub mod account;
122pub mod grpc_support;
123pub mod keystore;
124pub mod note;
125pub mod note_transport;
126pub mod pswap;
127pub mod rpc;
128pub mod settings;
129pub mod store;
130pub mod sync;
131pub mod transaction;
132pub mod utils;
133
134pub mod builder;
135
136#[cfg(feature = "testing")]
137mod test_utils;
138
139pub mod errors;
140
141pub use miden_protocol::utils::serde::{Deserializable, Serializable, SliceReader};
142
143// RE-EXPORTS
144// ================================================================================================
145
146pub mod notes {
147    pub use miden_protocol::note::NoteFile;
148}
149
150/// Provides `AggLayer` bridge components, note constructors, and helper types.
151pub mod agglayer {
152    pub use miden_agglayer::*;
153}
154
155/// Provides types and utilities for working with Miden Assembly.
156pub mod assembly {
157    pub use miden_protocol::MastForest;
158    pub use miden_protocol::assembly::debuginfo::SourceManagerSync;
159    #[cfg(feature = "std")]
160    pub use miden_protocol::assembly::debuginfo::{SourceManagerExt, Uri};
161    pub use miden_protocol::assembly::diagnostics::Report;
162    pub use miden_protocol::assembly::diagnostics::reporting::PrintDiagnostic;
163    pub use miden_protocol::assembly::mast::MastNodeExt;
164    pub use miden_protocol::assembly::{
165        Assembler,
166        DefaultSourceManager,
167        Library,
168        Module,
169        ModuleKind,
170        Path,
171    };
172    pub use miden_standards::code_builder::CodeBuilder;
173}
174
175/// Provides types and utilities for working with assets within the Miden network.
176pub mod asset {
177    pub use miden_protocol::account::delta::{
178        AccountStorageDelta,
179        AccountVaultDelta,
180        FungibleAssetDelta,
181        NonFungibleAssetDelta,
182        NonFungibleDeltaAction,
183        StorageMapDelta,
184        StorageSlotDelta,
185    };
186    pub use miden_protocol::account::{
187        AccountStorageHeader,
188        StorageMapWitness,
189        StorageSlotContent,
190        StorageSlotHeader,
191    };
192    pub use miden_protocol::asset::{
193        Asset,
194        AssetAmount,
195        AssetCallbackFlag,
196        AssetCallbacks,
197        AssetComposition,
198        AssetId,
199        AssetVault,
200        AssetVaultKey,
201        AssetWitness,
202        FungibleAsset,
203        NonFungibleAsset,
204        NonFungibleAssetDetails,
205        PartialVault,
206        TokenSymbol,
207    };
208}
209
210/// Provides authentication-related types and functionalities for the Miden
211/// network.
212pub mod auth {
213    pub use miden_protocol::account::auth::{
214        AuthScheme as AuthSchemeId,
215        AuthSecretKey,
216        PublicKey,
217        PublicKeyCommitment,
218        Signature,
219    };
220    pub use miden_standards::AuthMethod;
221    pub use miden_standards::account::auth::{
222        AuthMultisig,
223        AuthMultisigConfig,
224        AuthSingleSig,
225        AuthSingleSigAcl,
226        AuthSingleSigAclConfig,
227        NoAuth,
228    };
229    pub use miden_tx::auth::{BasicAuthenticator, SigningInputs, TransactionAuthenticator};
230
231    pub use crate::account::component::AuthScheme;
232
233    pub const RPO_FALCON_SCHEME_ID: AuthSchemeId = AuthSchemeId::Falcon512Poseidon2;
234    pub const ECDSA_K256_KECCAK_SCHEME_ID: AuthSchemeId = AuthSchemeId::EcdsaK256Keccak;
235}
236
237/// Provides types for working with blocks within the Miden network.
238pub mod block {
239    pub use miden_protocol::block::{BlockHeader, BlockNumber};
240}
241
242/// Provides cryptographic types and utilities used within the Miden rollup
243/// network. It re-exports commonly used types and random number generators like `FeltRng` from
244/// the `miden_standards` crate.
245pub mod crypto {
246    pub mod rpo_falcon512 {
247        pub use miden_protocol::crypto::dsa::falcon512_poseidon2::{
248            PublicKey,
249            SecretKey,
250            Signature,
251        };
252    }
253    pub use miden_protocol::crypto::hash::blake::Blake3Digest;
254    pub use miden_protocol::crypto::hash::poseidon2::Poseidon2;
255    pub use miden_protocol::crypto::hash::rpo::Rpo256;
256    pub use miden_protocol::crypto::merkle::mmr::{
257        Forest,
258        InOrderIndex,
259        MmrDelta,
260        MmrPeaks,
261        MmrProof,
262        PartialMmr,
263    };
264    pub use miden_protocol::crypto::merkle::smt::{
265        LeafIndex,
266        SMT_DEPTH,
267        Smt,
268        SmtForest,
269        SmtLeaf,
270        SmtProof,
271    };
272    pub use miden_protocol::crypto::merkle::store::MerkleStore;
273    pub use miden_protocol::crypto::merkle::{
274        EmptySubtreeRoots,
275        MerkleError,
276        MerklePath,
277        MerkleTree,
278        NodeIndex,
279        SparseMerklePath,
280    };
281    pub use miden_protocol::crypto::rand::{FeltRng, RandomCoin};
282}
283
284/// Provides types for working with addresses within the Miden network.
285pub mod address {
286    pub use miden_protocol::address::{
287        Address,
288        AddressId,
289        AddressInterface,
290        CustomNetworkId,
291        NetworkId,
292        RoutingParameters,
293    };
294}
295
296/// Provides types for working with the virtual machine within the Miden network.
297pub mod vm {
298    pub use miden_protocol::vm::{
299        AdviceInputs,
300        AdviceMap,
301        AttributeSet,
302        MIN_STACK_DEPTH,
303        Package,
304        PackageExport,
305        PackageManifest,
306        ProcedureExport,
307        Program,
308        QualifiedProcedureName,
309        Section,
310        SectionId,
311        TargetType,
312    };
313}
314
315pub use async_trait::async_trait;
316pub use errors::*;
317use miden_protocol::assembly::SourceManagerSync;
318pub use miden_protocol::{
319    EMPTY_WORD,
320    Felt,
321    MAX_TX_EXECUTION_CYCLES,
322    MIN_TX_EXECUTION_CYCLES,
323    ONE,
324    PrettyPrint,
325    WORD_SIZE,
326    Word,
327    ZERO,
328};
329pub use miden_remote_prover_client::RemoteTransactionProver;
330pub use miden_tx::ExecutionOptions;
331
332/// Provides test utilities for working with accounts and account IDs
333/// within the Miden network. This module is only available when the `testing` feature is
334/// enabled.
335#[cfg(feature = "testing")]
336pub mod testing {
337    pub use miden_protocol::testing::account_id;
338    /// Raw access to `miden-standards` testing modules for items not curated by
339    /// `miden-client`.
340    pub use miden_standards::testing as standards;
341    pub use miden_standards::testing::note::NoteBuilder;
342    pub use miden_testing::*;
343
344    pub use crate::test_utils::*;
345}
346
347use alloc::sync::Arc;
348use alloc::vec::Vec;
349
350use miden_protocol::block::BlockNumber;
351use miden_protocol::crypto::merkle::mmr::PartialMmr;
352use miden_protocol::crypto::rand::FeltRng;
353use miden_tx::auth::TransactionAuthenticator;
354use rand::RngCore;
355use rpc::NodeRpcClient;
356use store::Store;
357
358use crate::note_transport::NoteTransportClient;
359use crate::transaction::TransactionProver;
360
361// MIDEN CLIENT
362// ================================================================================================
363
364/// A light client for connecting to the Miden network.
365///
366/// Miden client is responsible for managing a set of accounts. Specifically, the client:
367/// - Keeps track of the current and historical states of a set of accounts and related objects such
368///   as notes and transactions.
369/// - Connects to a Miden node to periodically sync with the current state of the network.
370/// - Executes, proves, and submits transactions to the network as directed by the user.
371pub struct Client<AUTH> {
372    /// The client's store, which provides a way to write and read entities to provide persistence.
373    store: Arc<dyn Store>,
374    /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
375    /// serial numbers, etc.
376    rng: ClientRng,
377    /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
378    /// Miden node.
379    rpc_api: Arc<dyn NodeRpcClient>,
380    /// An instance of a [`TransactionProver`] which will be the default prover for the
381    /// client.
382    tx_prover: Arc<dyn TransactionProver + Send + Sync>,
383    /// An instance of a [`TransactionAuthenticator`] which will be used by the transaction
384    /// executor whenever a signature is requested from within the VM.
385    authenticator: Option<Arc<AUTH>>,
386    /// Shared source manager used to retain MASM source information for assembled programs.
387    source_manager: Arc<dyn SourceManagerSync>,
388    /// Options that control the transaction executor's runtime behaviour (e.g. debug mode).
389    exec_options: ExecutionOptions,
390    /// Number of blocks after which pending transactions are considered stale and discarded.
391    tx_discard_delta: Option<u32>,
392    /// Number of synced blocks between automatic irrelevant-block pruning runs.
393    irrelevant_block_prune_interval: Option<u32>,
394    /// Sync height at which the last automatic irrelevant-block prune completed.
395    last_irrelevant_block_prune_sync_height: Option<BlockNumber>,
396    /// Maximum number of blocks the client can be behind the network for transactions and account
397    /// proofs to be considered valid.
398    max_block_number_delta: Option<u32>,
399    /// An instance of [`NoteTransportClient`] which provides a way for the client to connect to
400    /// the Miden Note Transport network.
401    note_transport_api: Option<Arc<dyn NoteTransportClient>>,
402    /// Whether the client should cache the current Partial MMR in memory.
403    cache_partial_mmr_in_memory: bool,
404    /// Cached [`PartialMmr`] for the chain's MMR. Lazily built from the store and kept in sync
405    /// across sync/prune operations. `None` forces a rebuild on next access.
406    partial_mmr: Option<CachedPartialMmr>,
407    /// Observers fired by `apply_transaction`. See
408    /// [`Client::with_transaction_observer`].
409    transaction_observers: Vec<Arc<dyn transaction::TransactionObserver>>,
410}
411
412/// Cached [`PartialMmr`] with a two-part freshness fingerprint:
413///
414/// - `store_peaks_hash`: peaks at the current sync height - guards against chain/height drift.
415/// - `tracked_blocks_hash`: hash of the store's tracked block numbers - guards against drift
416///   between store-tracked and cache-tracked blocks. Required because a same-height update can mark
417///   an existing block relevant without changing peaks; pruning the cached MMR while it's missing
418///   such a block would over-delete auth nodes that the store still needs.
419///
420/// The cached MMR includes the sync-height block as a tracked leaf; the store persists the
421/// peaks committed by that block's header, i.e. the peaks over the chain *before* that block
422/// was added, so the two states are offset by one leaf.
423pub(crate) struct CachedPartialMmr {
424    pub(crate) store_peaks_hash: Word,
425    pub(crate) tracked_blocks_hash: Word,
426    pub(crate) mmr: PartialMmr,
427}
428
429/// Constructors.
430impl<AUTH> Client<AUTH>
431where
432    AUTH: builder::BuilderAuthenticator,
433{
434    /// Returns a new [`ClientBuilder`](builder::ClientBuilder) for constructing a client.
435    ///
436    /// This is a convenience method equivalent to calling `ClientBuilder::new()`.
437    ///
438    /// # Example
439    ///
440    /// ```ignore
441    /// let client = Client::builder()
442    ///     .rpc(rpc_client)
443    ///     .store(store)
444    ///     .authenticator(Arc::new(keystore))
445    ///     .build()
446    ///     .await?;
447    /// ```
448    pub fn builder() -> builder::ClientBuilder<AUTH> {
449        builder::ClientBuilder::new()
450    }
451}
452
453/// Access methods.
454impl<AUTH> Client<AUTH>
455where
456    AUTH: TransactionAuthenticator,
457{
458    /// Returns true if the client is in debug mode.
459    pub fn in_debug_mode(&self) -> bool {
460        self.exec_options.enable_debugging()
461    }
462
463    /// Returns an instance of the `CodeBuilder`
464    pub fn code_builder(&self) -> assembly::CodeBuilder {
465        assembly::CodeBuilder::with_source_manager(self.source_manager.clone())
466    }
467
468    /// Returns an instance of [`note::NoteScreener`] configured for this client.
469    pub fn note_screener(&self) -> note::NoteScreener {
470        note::NoteScreener::new(self.store.clone(), self.rpc_api.clone())
471    }
472
473    /// Returns a reference to the client's random number generator. This can be used to generate
474    /// randomness for various purposes such as serial numbers, keys, etc.
475    pub fn rng(&mut self) -> &mut ClientRng {
476        &mut self.rng
477    }
478
479    pub fn prover(&self) -> Arc<dyn TransactionProver + Send + Sync> {
480        self.tx_prover.clone()
481    }
482
483    pub fn authenticator(&self) -> Option<&Arc<AUTH>> {
484        self.authenticator.as_ref()
485    }
486
487    /// Returns the shared source manager used to retain MASM source information for assembled
488    /// programs.
489    pub fn source_manager(&self) -> Arc<dyn SourceManagerSync> {
490        self.source_manager.clone()
491    }
492}
493
494impl<AUTH> Client<AUTH> {
495    /// Returns the identifier of the underlying store (e.g. `IndexedDB` database name, `SQLite`
496    /// file path).
497    pub fn store_identifier(&self) -> &str {
498        self.store.identifier()
499    }
500
501    /// Registers a [`transaction::TransactionObserver`]. Per-observer failures are logged.
502    pub fn with_transaction_observer(
503        &mut self,
504        observer: Arc<dyn transaction::TransactionObserver>,
505    ) {
506        self.transaction_observers.push(observer);
507    }
508
509    /// Returns the network ID of the node the client is connected to.
510    pub async fn network_id(&self) -> Result<address::NetworkId, ClientError> {
511        Ok(self.rpc_api.get_network_id().await?)
512    }
513
514    // TEST HELPERS
515    // --------------------------------------------------------------------------------------------
516
517    #[cfg(any(test, feature = "testing"))]
518    pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient> {
519        &mut self.rpc_api
520    }
521
522    #[cfg(any(test, feature = "testing"))]
523    pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
524        &mut self.store
525    }
526
527    #[cfg(any(test, feature = "testing"))]
528    pub fn test_has_cached_partial_mmr(&self) -> bool {
529        self.partial_mmr.is_some()
530    }
531}
532
533// CLIENT RNG
534// ================================================================================================
535
536// NOTE: The idea of having `ClientRng` is to enforce `Send` and `Sync` over `FeltRng`.
537// This allows `Client`` to be `Send` and `Sync`. There may be users that would want to use clients
538// with !Send/!Sync RNGs. For this we have two options:
539//
540// - We can make client generic over R (adds verbosity but is more flexible and maybe even correct)
541// - We can optionally (e.g., based on features/target) change `ClientRng` definition to not enforce
542//   these bounds. (similar to TransactionAuthenticator)
543
544/// Marker trait for RNGs that can be shared across threads and used by the client.
545pub trait ClientFeltRng: FeltRng + Send + Sync {}
546impl<T> ClientFeltRng for T where T: FeltRng + Send + Sync {}
547
548/// Boxed RNG trait object used by the client.
549pub type ClientRngBox = Box<dyn ClientFeltRng>;
550
551/// A wrapper around a [`FeltRng`] that implements the [`RngCore`] trait.
552/// This allows the user to pass their own generic RNG so that it's used by the client.
553pub struct ClientRng(ClientRngBox);
554
555impl ClientRng {
556    pub fn new(rng: ClientRngBox) -> Self {
557        Self(rng)
558    }
559
560    pub fn inner_mut(&mut self) -> &mut ClientRngBox {
561        &mut self.0
562    }
563}
564
565impl RngCore for ClientRng {
566    fn next_u32(&mut self) -> u32 {
567        self.0.next_u32()
568    }
569
570    fn next_u64(&mut self) -> u64 {
571        self.0.next_u64()
572    }
573
574    fn fill_bytes(&mut self, dest: &mut [u8]) {
575        self.0.fill_bytes(dest);
576    }
577}
578
579impl FeltRng for ClientRng {
580    fn draw_element(&mut self) -> Felt {
581        self.0.draw_element()
582    }
583
584    fn draw_word(&mut self) -> Word {
585        self.0.draw_word()
586    }
587}
588
589/// Indicates whether the client is operating in debug mode.
590#[derive(Debug, Clone, Copy)]
591pub enum DebugMode {
592    Enabled,
593    Disabled,
594}
595
596impl From<DebugMode> for bool {
597    fn from(debug_mode: DebugMode) -> Self {
598        match debug_mode {
599            DebugMode::Enabled => true,
600            DebugMode::Disabled => false,
601        }
602    }
603}
604
605impl From<bool> for DebugMode {
606    fn from(debug_mode: bool) -> DebugMode {
607        if debug_mode {
608            DebugMode::Enabled
609        } else {
610            DebugMode::Disabled
611        }
612    }
613}
614
615#[cfg(test)]
616mod tests {
617    use super::Client;
618
619    fn assert_send_sync<T: Send + Sync>() {}
620
621    #[test]
622    fn client_is_send_sync() {
623        assert_send_sync::<Client<()>>();
624    }
625}