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