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::builder::ClientBuilder;
62//! use miden_client::keystore::FilesystemKeyStore;
63//! use miden_client::rpc::{Endpoint, GrpcClient};
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(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 pswap;
125#[cfg(feature = "tonic")]
126pub mod remote_prover;
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_standards::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        AccountVaultDelta,
179        FungibleAssetDelta,
180        NonFungibleAssetDelta,
181        NonFungibleDeltaAction,
182    };
183    pub use miden_protocol::account::{
184        AccountStorageHeader,
185        AssetCallbackFlag,
186        StorageMapWitness,
187        StorageSlotContent,
188        StorageSlotHeader,
189    };
190    pub use miden_protocol::asset::{
191        Asset,
192        AssetAmount,
193        AssetCallbacks,
194        AssetComposition,
195        AssetId,
196        AssetVault,
197        AssetWitness,
198        FungibleAsset,
199        NonFungibleAsset,
200        NonFungibleAssetDetails,
201        PartialVault,
202        TokenSymbol,
203    };
204}
205
206/// Provides authentication-related types and functionalities for the Miden
207/// network.
208pub mod auth {
209    pub use miden_protocol::account::auth::{
210        AuthScheme as AuthSchemeId,
211        AuthSecretKey,
212        PublicKey,
213        PublicKeyCommitment,
214        Signature,
215    };
216    pub use miden_standards::account::auth::{
217        Approver,
218        AuthMultisig,
219        AuthMultisigConfig,
220        AuthSingleSig,
221        AuthSingleSigAcl,
222        AuthSingleSigAclConfig,
223        NoAuth,
224    };
225    pub use miden_tx::auth::{BasicAuthenticator, SigningInputs, TransactionAuthenticator};
226
227    pub use crate::account::component::AuthScheme;
228
229    pub const RPO_FALCON_SCHEME_ID: AuthSchemeId = AuthSchemeId::Falcon512Poseidon2;
230    pub const ECDSA_K256_KECCAK_SCHEME_ID: AuthSchemeId = AuthSchemeId::EcdsaK256Keccak;
231}
232
233/// Provides types for working with blocks within the Miden network.
234pub mod block {
235    pub use miden_protocol::block::{BlockHeader, BlockNumber, FeeParameters, ValidatorKeys};
236}
237
238/// Provides cryptographic types and utilities used within the Miden rollup
239/// network. It re-exports commonly used types and random number generators like `FeltRng` from
240/// the `miden_standards` crate.
241pub mod crypto {
242    pub mod rpo_falcon512 {
243        pub use miden_protocol::crypto::dsa::falcon512_poseidon2::{
244            PublicKey,
245            SecretKey,
246            Signature,
247        };
248    }
249    pub use miden_protocol::crypto::hash::blake::Blake3Digest;
250    pub use miden_protocol::crypto::hash::poseidon2::Poseidon2;
251    pub use miden_protocol::crypto::hash::rpo::Rpo256;
252    pub use miden_protocol::crypto::merkle::mmr::{
253        Forest,
254        InOrderIndex,
255        MmrDelta,
256        MmrPeaks,
257        MmrProof,
258        PartialMmr,
259    };
260    pub use miden_protocol::crypto::merkle::smt::{
261        LeafIndex,
262        SMT_DEPTH,
263        Smt,
264        SmtForest,
265        SmtLeaf,
266        SmtProof,
267    };
268    pub use miden_protocol::crypto::merkle::store::MerkleStore;
269    pub use miden_protocol::crypto::merkle::{
270        EmptySubtreeRoots,
271        MerkleError,
272        MerklePath,
273        MerkleTree,
274        NodeIndex,
275        SparseMerklePath,
276    };
277    pub use miden_protocol::crypto::rand::{FeltRng, RandomCoin};
278}
279
280/// Provides types for working with addresses within the Miden network.
281pub mod address {
282    pub use miden_protocol::address::{
283        Address,
284        AddressId,
285        AddressInterface,
286        CustomNetworkId,
287        NetworkId,
288        RoutingParameters,
289    };
290}
291
292/// Provides types for working with the virtual machine within the Miden network.
293pub mod vm {
294    pub use miden_protocol::vm::{
295        AdviceInputs,
296        AdviceMap,
297        AttributeSet,
298        MIN_STACK_DEPTH,
299        Package,
300        PackageExport,
301        PackageManifest,
302        ProcedureExport,
303        Program,
304        QualifiedProcedureName,
305        Section,
306        SectionId,
307        TargetType,
308    };
309}
310
311pub use async_trait::async_trait;
312pub use errors::*;
313use miden_protocol::assembly::SourceManagerSync;
314pub use miden_protocol::{
315    EMPTY_WORD,
316    Felt,
317    MAX_TX_EXECUTION_CYCLES,
318    MIN_TX_EXECUTION_CYCLES,
319    ONE,
320    PrettyPrint,
321    WORD_SIZE,
322    Word,
323    ZERO,
324};
325pub use miden_tx::ExecutionOptions;
326#[cfg(feature = "tonic")]
327pub use remote_prover::RemoteTransactionProver;
328
329/// Provides test utilities for working with accounts and account IDs
330/// within the Miden network. This module is only available when the `testing` feature is
331/// enabled.
332#[cfg(feature = "testing")]
333pub mod testing {
334    pub use miden_protocol::testing::account_id;
335    /// Raw access to `miden-standards` testing modules for items not curated by
336    /// `miden-client`.
337    pub use miden_standards::testing as standards;
338    pub use miden_standards::testing::note::NoteBuilder;
339    pub use miden_testing::*;
340
341    pub use crate::test_utils::*;
342}
343
344use alloc::sync::Arc;
345use alloc::vec::Vec;
346use core::convert::Infallible;
347
348use miden_protocol::block::BlockNumber;
349use miden_protocol::crypto::merkle::mmr::PartialMmr;
350use miden_protocol::crypto::rand::FeltRng;
351use miden_tx::auth::TransactionAuthenticator;
352use rand::TryRng;
353use rpc::NodeRpcClient;
354use store::Store;
355
356use crate::note_transport::NoteTransportClient;
357use crate::transaction::TransactionProver;
358
359// MIDEN CLIENT
360// ================================================================================================
361
362/// A light client for connecting to the Miden network.
363///
364/// Miden client is responsible for managing a set of accounts. Specifically, the client:
365/// - Keeps track of the current and historical states of a set of accounts and related objects such
366///   as notes and transactions.
367/// - Connects to a Miden node to periodically sync with the current state of the network.
368/// - Executes, proves, and submits transactions to the network as directed by the user.
369pub struct Client<AUTH> {
370    /// The client's store, which provides a way to write and read entities to provide persistence.
371    store: Arc<dyn Store>,
372    /// An instance of [`FeltRng`] which provides randomness tools for generating new keys,
373    /// serial numbers, etc.
374    rng: ClientRng,
375    /// An instance of [`NodeRpcClient`] which provides a way for the client to connect to the
376    /// Miden node.
377    rpc_api: Arc<dyn NodeRpcClient>,
378    /// An instance of a [`TransactionProver`] which will be the default prover for the
379    /// client.
380    tx_prover: Arc<dyn TransactionProver + Send + Sync>,
381    /// An instance of a [`TransactionAuthenticator`] which will be used by the transaction
382    /// executor whenever a signature is requested from within the VM.
383    authenticator: Option<Arc<AUTH>>,
384    /// Shared source manager used to retain MASM source information for assembled programs.
385    source_manager: Arc<dyn SourceManagerSync>,
386    /// Options that control the transaction executor's runtime behaviour (e.g. cycle limits).
387    exec_options: ExecutionOptions,
388    /// Number of blocks after which pending transactions are considered stale and discarded.
389    tx_discard_delta: Option<u32>,
390    /// Number of synced blocks between automatic irrelevant-block pruning runs.
391    irrelevant_block_prune_interval: Option<u32>,
392    /// Sync height at which the last automatic irrelevant-block prune completed.
393    last_irrelevant_block_prune_sync_height: Option<BlockNumber>,
394    /// Maximum number of blocks the client can be behind the network for transactions and account
395    /// proofs to be considered valid.
396    max_block_number_delta: Option<u32>,
397    /// An instance of [`NoteTransportClient`] which provides a way for the client to connect to
398    /// the Miden Note Transport network.
399    note_transport_api: Option<Arc<dyn NoteTransportClient>>,
400    /// Whether the client should cache the current Partial MMR in memory.
401    cache_partial_mmr_in_memory: bool,
402    /// Cached [`PartialMmr`] for the chain's MMR. Lazily built from the store and kept in sync
403    /// across sync/prune operations. `None` forces a rebuild on next access.
404    partial_mmr: Option<CachedPartialMmr>,
405    /// Observers fired by `apply_transaction`. See
406    /// [`Client::with_transaction_observer`].
407    transaction_observers: Vec<Arc<dyn transaction::TransactionObserver>>,
408}
409
410/// Cached [`PartialMmr`] with a two-part freshness fingerprint:
411///
412/// - `store_peaks_hash`: peaks at the current sync height - guards against chain/height drift.
413/// - `tracked_blocks_hash`: hash of the store's tracked block numbers - guards against drift
414///   between store-tracked and cache-tracked blocks. Required because a same-height update can mark
415///   an existing block relevant without changing peaks; pruning the cached MMR while it's missing
416///   such a block would over-delete auth nodes that the store still needs.
417///
418/// The cached MMR includes the sync-height block as a tracked leaf; the store persists the
419/// peaks committed by that block's header, i.e. the peaks over the chain *before* that block
420/// was added, so the two states are offset by one leaf.
421pub(crate) struct CachedPartialMmr {
422    pub(crate) store_peaks_hash: Word,
423    pub(crate) tracked_blocks_hash: Word,
424    pub(crate) mmr: PartialMmr,
425}
426
427/// Constructors.
428impl<AUTH> Client<AUTH>
429where
430    AUTH: builder::BuilderAuthenticator,
431{
432    /// Returns a new [`ClientBuilder`](builder::ClientBuilder) for constructing a client.
433    ///
434    /// This is a convenience method equivalent to calling `ClientBuilder::new()`.
435    ///
436    /// # Example
437    ///
438    /// ```ignore
439    /// let client = Client::builder()
440    ///     .rpc(rpc_client)
441    ///     .store(store)
442    ///     .authenticator(Arc::new(keystore))
443    ///     .build()
444    ///     .await?;
445    /// ```
446    pub fn builder() -> builder::ClientBuilder<AUTH> {
447        builder::ClientBuilder::new()
448    }
449}
450
451/// Access methods.
452impl<AUTH> Client<AUTH>
453where
454    AUTH: TransactionAuthenticator,
455{
456    /// Returns an instance of the `CodeBuilder`
457    pub fn code_builder(&self) -> assembly::CodeBuilder {
458        assembly::CodeBuilder::with_source_manager(self.source_manager.clone())
459    }
460
461    /// Returns an instance of [`note::NoteScreener`] configured for this client.
462    pub fn note_screener(&self) -> note::NoteScreener {
463        note::NoteScreener::new(self.store.clone(), self.rpc_api.clone())
464    }
465
466    /// Returns a reference to the client's random number generator. This can be used to generate
467    /// randomness for various purposes such as serial numbers, keys, etc.
468    pub fn rng(&mut self) -> &mut ClientRng {
469        &mut self.rng
470    }
471
472    pub fn prover(&self) -> Arc<dyn TransactionProver + Send + Sync> {
473        self.tx_prover.clone()
474    }
475
476    pub fn authenticator(&self) -> Option<&Arc<AUTH>> {
477        self.authenticator.as_ref()
478    }
479
480    /// Returns the shared source manager used to retain MASM source information for assembled
481    /// programs.
482    pub fn source_manager(&self) -> Arc<dyn SourceManagerSync> {
483        self.source_manager.clone()
484    }
485}
486
487impl<AUTH> Client<AUTH> {
488    /// Returns the identifier of the underlying store (e.g. `IndexedDB` database name, `SQLite`
489    /// file path).
490    pub fn store_identifier(&self) -> &str {
491        self.store.identifier()
492    }
493
494    /// Registers a [`transaction::TransactionObserver`]. Per-observer failures are logged.
495    pub fn with_transaction_observer(
496        &mut self,
497        observer: Arc<dyn transaction::TransactionObserver>,
498    ) {
499        self.transaction_observers.push(observer);
500    }
501
502    /// Returns the network ID of the node the client is connected to.
503    pub async fn network_id(&self) -> Result<address::NetworkId, ClientError> {
504        Ok(self.rpc_api.get_network_id().await?)
505    }
506
507    // TEST HELPERS
508    // --------------------------------------------------------------------------------------------
509
510    #[cfg(any(test, feature = "testing"))]
511    pub fn test_rpc_api(&mut self) -> &mut Arc<dyn NodeRpcClient> {
512        &mut self.rpc_api
513    }
514
515    #[cfg(any(test, feature = "testing"))]
516    pub fn test_store(&mut self) -> &mut Arc<dyn Store> {
517        &mut self.store
518    }
519
520    #[cfg(any(test, feature = "testing"))]
521    pub fn test_has_cached_partial_mmr(&self) -> bool {
522        self.partial_mmr.is_some()
523    }
524}
525
526// CLIENT RNG
527// ================================================================================================
528
529// NOTE: The idea of having `ClientRng` is to enforce `Send` and `Sync` over `FeltRng`.
530// This allows `Client`` to be `Send` and `Sync`. There may be users that would want to use clients
531// with !Send/!Sync RNGs. For this we have two options:
532//
533// - We can make client generic over R (adds verbosity but is more flexible and maybe even correct)
534// - We can optionally (e.g., based on features/target) change `ClientRng` definition to not enforce
535//   these bounds. (similar to TransactionAuthenticator)
536
537/// Marker trait for RNGs that can be shared across threads and used by the client.
538pub trait ClientFeltRng: FeltRng + Send + Sync {}
539impl<T> ClientFeltRng for T where T: FeltRng + Send + Sync {}
540
541/// Boxed RNG trait object used by the client.
542pub type ClientRngBox = Box<dyn ClientFeltRng>;
543
544/// A wrapper around a [`FeltRng`] that implements the [`TryRng`] trait.
545/// This allows the user to pass their own generic RNG so that it's used by the client.
546pub struct ClientRng(ClientRngBox);
547
548impl ClientRng {
549    pub fn new(rng: ClientRngBox) -> Self {
550        Self(rng)
551    }
552
553    pub fn inner_mut(&mut self) -> &mut ClientRngBox {
554        &mut self.0
555    }
556}
557
558impl TryRng for ClientRng {
559    type Error = Infallible;
560
561    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
562        Ok(self.0.next_u32())
563    }
564
565    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
566        Ok(self.0.next_u64())
567    }
568
569    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
570        self.0.fill_bytes(dest);
571        Ok(())
572    }
573}
574
575impl FeltRng for ClientRng {
576    fn draw_element(&mut self) -> Felt {
577        self.0.draw_element()
578    }
579
580    fn draw_word(&mut self) -> Word {
581        self.0.draw_word()
582    }
583}
584
585#[cfg(test)]
586mod tests {
587    use super::Client;
588
589    fn assert_send_sync<T: Send + Sync>() {}
590
591    #[test]
592    fn client_is_send_sync() {
593        assert_send_sync::<Client<()>>();
594    }
595}