diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b18c0511b..873f63208b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,14 @@ ### Breaking Changes * [BREAKING][type][rust] Added the `TransactionRequestError::SwapNoteWithZeroAsset` variant, so exhaustive matches on `TransactionRequestError` must handle it ([#2459](https://github.com/0xMiden/rust-sdk/pull/2459)). +* [BREAKING][removal][test] Loose helper functions in `miden_client::testing::common` are now methods on `TestClient`. `TestClient::keystore()` exposes the client's keystore, so `ClientConfig::into_client` and `into_unsynced_client` return just the `TestClient` instead of a client/keystore pair ([#2481](https://github.com/0xMiden/rust-sdk/pull/2481)). ### Fixes * [FIX][rust] Added validation of cached transaction encryption keys during deserialization. Unsupported encryption schemes and empty or oversized key IDs are rejected before reading the key ID bytes ([#2411](https://github.com/0xMiden/rust-sdk/pull/2411)). * [FIX][cli] `miden-client import` now rejects invocations without a file path instead of silently succeeding ([#2450](https://github.com/0xMiden/rust-sdk/pull/2450)). * [FIX][rust] `TransactionRequestBuilder::build_swap` and `build_pswap_create` now reject a zero-amount asset on either side of the exchange. A zero requested asset produced a payback P2ID note carrying nothing, and a zero offered asset produced a note whose consumer pays and receives nothing ([#2459](https://github.com/0xMiden/rust-sdk/pull/2459)). +* [FIX][test] The integration tests run again on a chain that charges no fee. A `--funders` path (`MIDEN_FUNDER_ACCOUNTS_DIR`) that is unset, empty, missing, or holds no `.mac` file now leaves the run without funders instead of failing, which is all a fee-free genesis needs, since it declares no wallets for the path to hold. A `.mac` file that is present but unusable stays a hard error ([#2481](https://github.com/0xMiden/rust-sdk/pull/2481)). ## 0.16.0 (2026-09-07) diff --git a/Cargo.lock b/Cargo.lock index a5bf913747..4309716253 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2704,6 +2704,7 @@ dependencies = [ name = "miden-client-unit-tests" version = "0.16.0" dependencies = [ + "anyhow", "miden-client", "miden-client-sqlite-store", "miden-debug", diff --git a/Makefile b/Makefile index db16c52e23..d70be36700 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,7 @@ TEST_MIDEN_NOTE_TRANSPORT_URL?=http://127.0.0.1:57292 # Pre-funded wallets the integration tests draw transaction fees from, either one `.mac` file or a # directory of them, written here by `start-test-node.sh`. Against a deployed network, point this at -# wallets funded out of band. Unused on a fee-free chain, where no account needs funding. +# wallets funded out of band. A path naming no `.mac` file, means no funders. MIDEN_FUNDER_ACCOUNTS_DIR?=$(CURDIR)/data/funders # Pre-deployed agglayer accounts the agglayer tests transact with, written here by @@ -160,7 +160,7 @@ integration-test-dev: ## Run integration tests with debug assertions enabled via .PHONY: integration-test-binary integration-test-binary: ## Run the integration tests using the standalone binary (requires note transport service) - TEST_MIDEN_NOTE_TRANSPORT_URL=$(TEST_MIDEN_NOTE_TRANSPORT_URL) AGGLAYER_ACCOUNTS_DIR=$(AGGLAYER_ACCOUNTS_DIR) cargo run --package miden-client-integration-tests --release --locked -- --funders $(MIDEN_FUNDER_ACCOUNTS_DIR) + TEST_MIDEN_NOTE_TRANSPORT_URL=$(TEST_MIDEN_NOTE_TRANSPORT_URL) MIDEN_FUNDER_ACCOUNTS_DIR=$(MIDEN_FUNDER_ACCOUNTS_DIR) AGGLAYER_ACCOUNTS_DIR=$(AGGLAYER_ACCOUNTS_DIR) cargo run --package miden-client-integration-tests --release --locked # --- Installing ---------------------------------------------------------------------------------- diff --git a/bin/integration-tests/README.md b/bin/integration-tests/README.md index 202b659f44..afb51e13b5 100644 --- a/bin/integration-tests/README.md +++ b/bin/integration-tests/README.md @@ -207,7 +207,9 @@ MIDEN_VERIFICATION_BASE_FEE=0 make start-node-background ``` The suite never mints. It draws the native asset from pre-funded basic wallets named by `--funders` -(or `MIDEN_FUNDER_ACCOUNTS_DIR`), either one `.mac` file or a directory of them. +(or `MIDEN_FUNDER_ACCOUNTS_DIR`), either one `.mac` file or a directory of them. A path naming no +`.mac` file means no funders (useful for fee-free chains) so the Make targets can pass the +same path either way. ```bash # Local node: its genesis pre-funds the wallets and start-test-node.sh writes them here. @@ -242,7 +244,8 @@ chain before every payment, which is what makes sharing one between test process ### Environment variables -- `MIDEN_FUNDER_ACCOUNTS_DIR` - funder `.mac` file or directory, same as `--funders` +- `MIDEN_FUNDER_ACCOUNTS_DIR` - funder `.mac` file or directory, same as `--funders`. Unset, empty + or naming no `.mac` file leaves the run without funders - `MIDEN_VERIFICATION_BASE_FEE` - genesis `verification_base_fee` for the testing node (default `500`; `0` runs the node fee-free and declares no funder wallets) - `MIDEN_NUM_FUNDER_WALLETS` - number of wallets a fee-charging genesis pre-funds (default `16`) diff --git a/bin/integration-tests/src/config.rs b/bin/integration-tests/src/config.rs index 070329dde4..67c9052829 100644 --- a/bin/integration-tests/src/config.rs +++ b/bin/integration-tests/src/config.rs @@ -118,21 +118,19 @@ impl ClientConfig { } /// Loads the pre-funded wallets at `funders`, one `.mac` account file or a directory of them, - /// as the fee funder. `None` leaves the config without one, which is all a fee-free chain - /// needs. + /// as the fee funder. A path naming no funder file leaves the config without one, which is all + /// a fee-free chain needs. pub fn with_funders(self, funders: Option<&Path>) -> Result { let fee_funder = fee_funding::load(&self, funders)?; Ok(self.with_fee_funder(fee_funder)) } - /// Creates a `TestClient` builder and keystore. + /// Creates a `TestClient` builder. /// /// The store is a `SQLite` database at a temporary location, and the keystore a temporary /// directory, both created here rather than held on the config, so every client this is called /// on gets its own. - pub fn into_client_builder( - self, - ) -> Result<(ClientBuilder, FilesystemKeyStore)> { + pub fn into_client_builder(self) -> Result> { let store_config = create_test_store_path(); let auth_path = create_test_auth_path(); @@ -154,7 +152,7 @@ impl ClientConfig { .rpc(rpc_client) .rng(Box::new(rng)) .sqlite_store(store_config) - .authenticator(Arc::new(keystore.clone())) + .authenticator(Arc::new(keystore)) .tx_discard_delta(None); if let Some(prover_url) = &self.prover_endpoint { @@ -172,31 +170,32 @@ impl ClientConfig { builder = builder.note_transport(nt_client); } - Ok((builder, keystore)) + Ok(builder) } /// Creates a `TestClient` without syncing it, for tests that have to wait for the node first. /// - /// The client gets its own store and keystore. - pub async fn into_unsynced_client(self) -> Result<(TestClient, FilesystemKeyStore)> { + /// The client gets its own store and keystore, the latter reachable through + /// `TestClient::keystore`. + pub async fn into_unsynced_client(self) -> Result { let fee_funder = self.fee_funder.clone(); - let (builder, keystore) = self.into_client_builder()?; + let builder = self.into_client_builder()?; let client = builder.build().await.with_context(|| "failed to build test client")?; - Ok((TestClient::from(client).with_fee_funder(fee_funder), keystore)) + Ok(TestClient::from(client).with_fee_funder(fee_funder)) } /// Creates a `TestClient`. /// /// The client gets its own store and keystore, and is synced to the current state before being /// returned. - pub async fn into_client(self) -> Result<(TestClient, FilesystemKeyStore)> { - let (mut client, keystore) = self.into_unsynced_client().await?; + pub async fn into_client(self) -> Result { + let mut client = self.into_unsynced_client().await?; client.sync_state().await.with_context(|| "failed to sync client state")?; - Ok((client, keystore)) + Ok(client) } } diff --git a/bin/integration-tests/src/fee_funding.rs b/bin/integration-tests/src/fee_funding.rs index 652849ebdc..4fe72574a2 100644 --- a/bin/integration-tests/src/fee_funding.rs +++ b/bin/integration-tests/src/fee_funding.rs @@ -17,7 +17,7 @@ use miden_client::asset::FungibleAsset; use miden_client::block::BlockNumber; use miden_client::keystore::Keystore; use miden_client::note::{Note, NoteType, P2idNote}; -use miden_client::testing::common::{TestClient, wait_for_node, wait_for_tx}; +use miden_client::testing::common::TestClient; use miden_client::testing::fee::FeeFunder; use miden_client::transaction::TransactionRequestBuilder; use rand::RngExt; @@ -40,30 +40,36 @@ const FUNDING_AMOUNT: u64 = 10_000_000; // LOADING // ================================================================================================ -/// Returns the funder path named by [`FUNDER_ACCOUNTS_ENV`], for runners that take no arguments. +/// Returns the funder path named by [`FUNDER_ACCOUNTS_ENV`], for runners that read it themselves +/// rather than taking it as an argument. [`load`] decides what a path holding no funder means. pub fn funders_path_from_env() -> Option { - std::env::var_os(FUNDER_ACCOUNTS_ENV) - .map(PathBuf::from) - .filter(|p| !p.as_os_str().is_empty()) + std::env::var_os(FUNDER_ACCOUNTS_ENV).map(PathBuf::from) } -/// Loads the wallets at `funders` as a [`FeeFunder`] paying out of whichever one is free. `None` -/// yields no funder. The funder client is built from `client_config`'s endpoints. +/// Loads the wallets at `funders` as a [`FeeFunder`] paying out of whichever one is free. The +/// funder client is built from `client_config`'s endpoints. +/// +/// Yields no funder when `funders` names no funder file. A file that is there but cannot be used as +/// a funder is still an error. pub fn load( client_config: &ClientConfig, funders: Option<&Path>, ) -> Result>> { - let Some(path) = funders else { + let wallets = load_funders(funders)?; + if wallets.is_empty() { return Ok(None); - }; - - let wallets = load_funders(path)?; + } Ok(Some(Arc::new(Funder::new(client_config, wallets)))) } -/// Loads the funder wallets at `path`, which is either one `.mac` file or a directory of them. -fn load_funders(path: &Path) -> Result> { +/// Loads the funder wallets at `path`, which is either one `.mac` file or a directory of them, and +/// none at all when `path` names no such file. +fn load_funders(path: Option<&Path>) -> Result> { + let Some(path) = path.filter(|path| !path.as_os_str().is_empty()) else { + return Ok(Vec::new()); + }; + let paths = if path.is_dir() { let mut mac_files: Vec = std::fs::read_dir(path) .with_context(|| format!("failed to read funder directory {}", path.display()))? @@ -77,14 +83,12 @@ fn load_funders(path: &Path) -> Result> { // tests over distinct wallets. mac_files.sort(); mac_files - } else { + } else if path.is_file() { vec![path.to_path_buf()] + } else { + Vec::new() }; - if paths.is_empty() { - bail!("no `.mac` funder account files in {}", path.display()); - } - // A private funder's state lives only in the file, so sharing one across processes would build // every transaction from the same stale snapshot. A public one is re-read from the chain. paths @@ -152,7 +156,7 @@ impl Funder { } async fn build_client(&self) -> Result { - let (mut client, keystore) = self + let mut client = self .client_config .clone() .into_unsynced_client() @@ -160,13 +164,13 @@ impl Funder { .context("failed to build the funder client")?; // Some tests create their accounts before waiting for the node, so the wait happens here. - wait_for_node(&mut client).await; + client.wait_for_node().await; client.sync_state().await.context("failed to sync the funder client")?; for wallet in &self.wallets { let id = wallet.account.id(); for key in &wallet.auth_secret_keys { - keystore.add_key(key, id).await.context("failed to add a funder key")?; + client.keystore().add_key(key, id).await.context("failed to add a funder key")?; } } @@ -234,7 +238,8 @@ impl Funder { // Waited on before the wallet is released: another process claiming it reads its state from // the chain, which does not carry this payment until it commits. - wait_for_tx(client, tx_id) + client + .wait_for_tx(tx_id) .await .with_context(|| format!("the payment from funder {wallet_id} never committed"))?; diff --git a/bin/integration-tests/src/main.rs b/bin/integration-tests/src/main.rs index 89099cba2f..818240ad6d 100644 --- a/bin/integration-tests/src/main.rs +++ b/bin/integration-tests/src/main.rs @@ -162,8 +162,9 @@ struct Args { note_transport_url: Option, /// Path to the pre-funded basic wallets the tests draw transaction fees from: either one `.mac` - /// account file or a directory of them. - #[arg(long, env = fee_funding::FUNDER_ACCOUNTS_ENV)] + /// account file or a directory of them. Defaults to `MIDEN_FUNDER_ACCOUNTS_DIR`. A path naming + /// no such file leaves the run without funders. + #[arg(long)] funders: Option, /// Enable verbose tracing output (info-level logs from tests and client). @@ -235,12 +236,17 @@ impl TryFrom for BaseConfig { } }; + let funders = args + .funders + .or_else(fee_funding::funders_path_from_env) + .filter(|path| !path.as_os_str().is_empty()); + Ok(BaseConfig { rpc_endpoint: endpoint, timeout: timeout_ms, prover_endpoint, note_transport_endpoint, - funders: args.funders, + funders, verbose: args.verbose, }) } diff --git a/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs b/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs index b3214b3f54..919ca92ddb 100644 --- a/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs +++ b/bin/integration-tests/src/tests/agglayer/agglayer_bridge_in_out.rs @@ -34,14 +34,7 @@ use miden_agglayer::{ use miden_client::account::AccountType; use miden_client::agglayer::{EthAddress, EthEmbeddedAccountId}; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::note::NoteAssets; -use miden_client::testing::common::{ - insert_new_wallet, - wait_for_blocks, - wait_for_consumable_notes, - wait_for_tx, -}; use miden_client::transaction::TransactionRequestBuilder; use super::agglayer_test_utils::generate_claim_data_for_account; @@ -79,26 +72,18 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< // SETUP: Destination account (always fresh) + faucet // ============================================================================================ - let (destination_account, ..) = insert_new_wallet( - &mut user.client, - AccountType::Public, - &user.keystore, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let destination_account = user.insert_wallet(AccountType::Public).await?; println!("[bridge_in_out] Destination account created: {:?}", destination_account.id()); - user.client.deploy_account(destination_account.id()).await?; + user.deploy_account(destination_account.id()).await?; println!("[bridge_in_out] Destination account deployed on-chain"); // The agglayer faucet is an `AuthNetworkAccount`, so like the bridge it is pre-deployed and // imported rather than created here. let agglayer_faucet_id = agglayer_config.faucet_id(); println!("[bridge_in_out] Importing faucet: {agglayer_faucet_id}"); - for pair in [&mut bridge_admin, &mut ger_manager, &mut user] { - agglayer_config - .import_account(agglayer_faucet_id, &mut pair.client, &pair.keystore) - .await?; + for client in [&mut bridge_admin, &mut ger_manager, &mut user] { + agglayer_config.import_account(agglayer_faucet_id, client).await?; } // Register the faucet on the (genesis-deployed, unconfigured) bridge via a CONFIG_AGG_BRIDGE @@ -120,20 +105,17 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< }, bridge_admin_id, bridge_id, - bridge_admin.client.rng(), + bridge_admin.rng(), )?; let config_output_tx = TransactionRequestBuilder::new().own_output_notes(vec![config_note]).build()?; - let tx_id = bridge_admin - .client - .submit_new_transaction(bridge_admin_id, config_output_tx) - .await?; - wait_for_tx(&mut bridge_admin.client, tx_id).await?; + let tx_id = bridge_admin.submit_new_transaction(bridge_admin_id, config_output_tx).await?; + bridge_admin.wait_for_tx(tx_id).await?; println!("[bridge_in_out] CONFIG_AGG_BRIDGE note submitted"); // Wait for the bridge to consume the config note as a network transaction. In CI the node's // network transaction queue may be congested, so allow more blocks than the local minimum. - wait_for_blocks(&mut bridge_admin.client, 5).await; + bridge_admin.wait_for_blocks(5).await?; println!("[bridge_in_out] Waited for bridge to consume CONFIG_AGG_BRIDGE note"); // ============================================================================================ @@ -157,19 +139,19 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< "foundry-generated destination must match our wallet's AccountId" ); - ger_manager.client.sync_state().await?; + ger_manager.sync_state().await?; // Submit UPDATE_GER note: done by the ger manager let update_ger_note = - UpdateGerNote::create(ger, ger_manager_id, bridge_id, ger_manager.client.rng())?; + UpdateGerNote::create(ger, ger_manager_id, bridge_id, ger_manager.rng())?; let tx_request = TransactionRequestBuilder::new() .own_output_notes(vec![update_ger_note]) .build()?; - let tx_id = ger_manager.client.submit_new_transaction(ger_manager_id, tx_request).await?; - wait_for_tx(&mut ger_manager.client, tx_id).await?; + let tx_id = ger_manager.submit_new_transaction(ger_manager_id, tx_request).await?; + ger_manager.wait_for_tx(tx_id).await?; println!("[bridge_in_out] Round {round}: UPDATE_GER note submitted"); - wait_for_blocks(&mut ger_manager.client, 5).await; + ger_manager.wait_for_blocks(5).await?; println!("[bridge_in_out] Round {round}: waited for bridge to consume UPDATE_GER note"); // Submit CLAIM note: done by the user (or could also be a claim manager entity) @@ -184,17 +166,12 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< leaf_data, miden_claim_amount, }; - let claim_note = ClaimNote::create( - claim_inputs, - bridge_id, - destination_account.id(), - user.client.rng(), - )?; + let claim_note = + ClaimNote::create(claim_inputs, bridge_id, destination_account.id(), user.rng())?; let tx_request = TransactionRequestBuilder::new().own_output_notes(vec![claim_note]).build()?; - let tx_id = - user.client.submit_new_transaction(destination_account.id(), tx_request).await?; - wait_for_tx(&mut user.client, tx_id).await?; + let tx_id = user.submit_new_transaction(destination_account.id(), tx_request).await?; + user.wait_for_tx(tx_id).await?; println!("[bridge_in_out] Round {round}: CLAIM note submitted"); // Wait for the P2ID note to arrive at the destination. The budget spans a network @@ -202,7 +179,7 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< // is far more load-sensitive than a directly submitted transaction, so it is set well above // the ~5 blocks that round trip normally takes. let consumable_notes = - wait_for_consumable_notes(&mut user.client, destination_account.id(), 120).await; + user.wait_for_consumable_notes(destination_account.id(), 120).await?; println!( "[bridge_in_out] Round {round}: found {} consumable notes for destination", consumable_notes.len() @@ -213,14 +190,12 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< .map(|(note, _)| note.try_into().map_err(|e| anyhow::anyhow!("{e}"))) .collect::, _>>()?; let consume_tx = TransactionRequestBuilder::new().build_consume_notes(notes_to_consume)?; - let tx_id = - user.client.submit_new_transaction(destination_account.id(), consume_tx).await?; - wait_for_tx(&mut user.client, tx_id).await?; + let tx_id = user.submit_new_transaction(destination_account.id(), consume_tx).await?; + user.wait_for_tx(tx_id).await?; println!("[bridge_in_out] Round {round}: destination consumed P2ID note"); - user.client.sync_state().await?; + user.sync_state().await?; let dest_balance = user - .client .account_reader(destination_account.id()) .get_balance(agglayer_faucet_id) .await?; @@ -237,7 +212,7 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< // PHASE 2: BRIDGE-OUT // ============================================================================================ - user.client.sync_state().await?; + user.sync_state().await?; let l1_destination_address = EthAddress::from_hex(TEST_L1_DESTINATION).expect("valid L1 destination address"); @@ -255,22 +230,19 @@ pub async fn test_agglayer_bridge_in_out(client_config: ClientConfig) -> Result< NoteAssets::new(vec![bridge_asset])?, bridge_id, destination_account.id(), - user.client.rng(), + user.rng(), )?; println!("[bridge_in_out] B2AGG note created with amount: {}", BRIDGE_OUT_AMOUNT); let b2agg_output_tx = TransactionRequestBuilder::new().own_output_notes(vec![b2agg_note]).build()?; - let tx_id = user - .client - .submit_new_transaction(destination_account.id(), b2agg_output_tx) - .await?; - wait_for_tx(&mut user.client, tx_id).await?; + let tx_id = user.submit_new_transaction(destination_account.id(), b2agg_output_tx).await?; + user.wait_for_tx(tx_id).await?; println!("[bridge_in_out] B2AGG note submitted from destination account"); // Wait for bridge to consume the B2AGG note as network transaction. Allow extra blocks for CI // where the node processes many concurrent network transactions. - wait_for_blocks(&mut user.client, 5).await; + user.wait_for_blocks(5).await?; println!("[bridge_in_out] Waited for bridge to consume B2AGG note"); println!("[bridge_in_out] Test completed successfully"); diff --git a/bin/integration-tests/src/tests/agglayer/ger.rs b/bin/integration-tests/src/tests/agglayer/ger.rs index bea3484db0..8cf9d1a556 100644 --- a/bin/integration-tests/src/tests/agglayer/ger.rs +++ b/bin/integration-tests/src/tests/agglayer/ger.rs @@ -1,6 +1,5 @@ use anyhow::Result; use miden_agglayer::{AggLayerBridge, ExitRoot, UpdateGerNote}; -use miden_client::testing::common::{wait_for_blocks, wait_for_tx}; use miden_client::transaction::TransactionRequestBuilder; use miden_protocol::account::StorageMapKey; use miden_protocol::{Hasher, ONE, Word, ZERO}; @@ -26,14 +25,13 @@ pub async fn test_agglayer_update_ger(client_config: ClientConfig) -> Result<()> let ger_bytes: [u8; 32] = rand::random(); let ger = ExitRoot::from(ger_bytes); println!("Submitting UpdateGerNote with random GER: {ger_bytes:02x?}"); - let update_ger_note = - UpdateGerNote::create(ger, ger_manager_id, bridge_id, ger_manager.client.rng())?; + let update_ger_note = UpdateGerNote::create(ger, ger_manager_id, bridge_id, ger_manager.rng())?; let tx_request = TransactionRequestBuilder::new() .own_output_notes(vec![update_ger_note]) .build()?; - let tx_id = ger_manager.client.submit_new_transaction(ger_manager_id, tx_request).await?; - wait_for_tx(&mut ger_manager.client, tx_id).await?; + let tx_id = ger_manager.submit_new_transaction(ger_manager_id, tx_request).await?; + ger_manager.wait_for_tx(tx_id).await?; // WAIT FOR NETWORK ACCOUNT TO PROCESS UPDATE_GER NOTE // -------------------------------------------------------------------------------------------- @@ -49,7 +47,6 @@ pub async fn test_agglayer_update_ger(client_config: ClientConfig) -> Result<()> let mut is_registered = false; for _ in 0..MAX_POLL_BLOCKS { let stored_value = ger_manager - .client .account_reader(bridge_id) .get_storage_map_item( AggLayerBridge::ger_map_slot_name().clone(), @@ -62,7 +59,7 @@ pub async fn test_agglayer_update_ger(client_config: ClientConfig) -> Result<()> break; } - wait_for_blocks(&mut ger_manager.client, 1).await; + ger_manager.wait_for_blocks(1).await?; } // VERIFY GER HASH WAS STORED IN MAP diff --git a/bin/integration-tests/src/tests/agglayer/mod.rs b/bin/integration-tests/src/tests/agglayer/mod.rs index 89a8e75f94..aaf96bf145 100644 --- a/bin/integration-tests/src/tests/agglayer/mod.rs +++ b/bin/integration-tests/src/tests/agglayer/mod.rs @@ -4,7 +4,7 @@ use anyhow::{Context, Result}; use miden_client::Deserializable; use miden_client::account::{AccountFile, AccountId}; use miden_client::keystore::Keystore; -use miden_client::testing::common::{FilesystemKeyStore, TestClient, wait_for_node}; +use miden_client::testing::common::TestClient; use crate::ClientConfig; use crate::fee_funding::AccountLock; @@ -81,13 +81,12 @@ impl AgglayerConfig { self.faucet.account.id() } - /// Imports a single account (by ID) into the given client and keystore. Fetches the latest + /// Imports a single account (by ID) into the given client and its keystore. Fetches the latest /// state from the network. Adds any matching secret keys. pub async fn import_account( &self, account_id: AccountId, client: &mut TestClient, - keystore: &FilesystemKeyStore, ) -> Result<()> { let account_file = [&self.bridge_admin, &self.ger_manager, &self.bridge, &self.faucet] .into_iter() @@ -100,7 +99,7 @@ impl AgglayerConfig { .with_context(|| format!("failed to import account {account_id} from network"))?; for secret_key in &account_file.auth_secret_keys { - keystore.add_key(secret_key, account_id).await.with_context(|| { + client.keystore().add_key(secret_key, account_id).await.with_context(|| { format!("failed to add key for account {account_id} to keystore") })?; } @@ -119,32 +118,23 @@ impl AgglayerConfig { // SHARED TEST SETUP // ================================================================================================ -/// A client + keystore pair for a single test entity. -pub struct ClientPair { - pub client: TestClient, - pub keystore: FilesystemKeyStore, -} - /// Account IDs produced by the core setup: `(bridge_admin_id, ger_manager_id, bridge_id)`. pub type CoreAccountIds = (AccountId, AccountId, AccountId); /// Creates three clients sharing the same RPC endpoint, for bridge admin, GER manager, and user. pub async fn create_agglayer_clients( client_config: &ClientConfig, -) -> Result<(ClientPair, ClientPair, ClientPair)> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; - client.sync_state().await?; +) -> Result<(TestClient, TestClient, TestClient)> { + let mut bridge_admin = client_config.clone().into_client().await?; + bridge_admin.wait_for_node().await; + bridge_admin.sync_state().await?; println!("[setup] Bridge admin client initialized"); - let bridge_admin = ClientPair { client, keystore }; - let (client, keystore) = client_config.clone().into_client().await?; + let ger_manager = client_config.clone().into_client().await?; println!("[setup] GER manager client initialized"); - let ger_manager = ClientPair { client, keystore }; - let (client, keystore) = client_config.clone().into_client().await?; + let user = client_config.clone().into_client().await?; println!("[setup] User client initialized"); - let user = ClientPair { client, keystore }; Ok((bridge_admin, ger_manager, user)) } @@ -155,26 +145,20 @@ pub async fn create_agglayer_clients( /// admin and the GER manager go only into the client that signs for them. pub async fn setup_core_accounts( config: &AgglayerConfig, - bridge_admin: &mut ClientPair, - ger_manager: &mut ClientPair, - user: &mut ClientPair, + bridge_admin: &mut TestClient, + ger_manager: &mut TestClient, + user: &mut TestClient, ) -> Result { println!("[setup] Loading core accounts"); println!("[setup] bridge admin: {}", config.bridge_admin_id()); println!("[setup] GER manager: {}", config.ger_manager_id()); println!("[setup] bridge: {}", config.bridge_id()); - config - .import_account(config.bridge_admin_id(), &mut bridge_admin.client, &bridge_admin.keystore) - .await?; - config - .import_account(config.ger_manager_id(), &mut ger_manager.client, &ger_manager.keystore) - .await?; - - for pair in [&mut *bridge_admin, &mut *ger_manager, &mut *user] { - config - .import_account(config.bridge_id(), &mut pair.client, &pair.keystore) - .await?; + config.import_account(config.bridge_admin_id(), bridge_admin).await?; + config.import_account(config.ger_manager_id(), ger_manager).await?; + + for client in [&mut *bridge_admin, &mut *ger_manager, &mut *user] { + config.import_account(config.bridge_id(), client).await?; } Ok((config.bridge_admin_id(), config.ger_manager_id(), config.bridge_id())) diff --git a/bin/integration-tests/src/tests/agglayer/note_reader.rs b/bin/integration-tests/src/tests/agglayer/note_reader.rs index f07f296590..ebf635477b 100644 --- a/bin/integration-tests/src/tests/agglayer/note_reader.rs +++ b/bin/integration-tests/src/tests/agglayer/note_reader.rs @@ -1,6 +1,5 @@ use anyhow::Result; use miden_agglayer::{ExitRoot, UpdateGerNote}; -use miden_client::testing::common::{wait_for_blocks, wait_for_tx}; use miden_client::transaction::TransactionRequestBuilder; use super::{AgglayerConfig, create_agglayer_clients, setup_core_accounts}; @@ -39,18 +38,18 @@ pub async fn test_agglayer_note_reader_reads_consumed_notes( let mut expected = Vec::with_capacity(NOTE_COUNT); for _ in 0..NOTE_COUNT { let ger = ExitRoot::from(rand::random::<[u8; 32]>()); - let note = UpdateGerNote::create(ger, ger_manager_id, bridge_id, ger_manager.client.rng())?; + let note = UpdateGerNote::create(ger, ger_manager_id, bridge_id, ger_manager.rng())?; expected.push(note.details_commitment()); let tx = TransactionRequestBuilder::new().own_output_notes(vec![note]).build()?; - let tx_id = ger_manager.client.submit_new_transaction(ger_manager_id, tx).await?; - wait_for_tx(&mut ger_manager.client, tx_id).await?; + let tx_id = ger_manager.submit_new_transaction(ger_manager_id, tx).await?; + ger_manager.wait_for_tx(tx_id).await?; let mut consumed = Vec::new(); for _ in 0..MAX_POLL_BLOCKS { - ger_manager.client.sync_state().await?; + ger_manager.sync_state().await?; consumed.clear(); - let mut reader = ger_manager.client.input_note_reader(bridge_id); + let mut reader = ger_manager.input_note_reader(bridge_id); while let Some(note) = reader.next().await? { consumed.push(note.details_commitment()); } @@ -58,7 +57,7 @@ pub async fn test_agglayer_note_reader_reads_consumed_notes( if consumed.len() == expected.len() { break; } - wait_for_blocks(&mut ger_manager.client, 1).await; + ger_manager.wait_for_blocks(1).await?; } assert_eq!( diff --git a/bin/integration-tests/src/tests/batch.rs b/bin/integration-tests/src/tests/batch.rs index 85ef61c9d9..9e20fdea3b 100644 --- a/bin/integration-tests/src/tests/batch.rs +++ b/bin/integration-tests/src/tests/batch.rs @@ -2,7 +2,6 @@ use anyhow::{Context, Result}; use miden_client::Felt; use miden_client::account::AccountType; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::note::NoteType; use miden_client::store::TransactionFilter; use miden_client::testing::common::*; @@ -28,26 +27,21 @@ use crate::ClientConfig; pub async fn test_batch_builder_submits_two_p2id_on_one_account( client_config: ClientConfig, ) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client.setup_two_wallets_and_faucet(AccountType::Private).await?; let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // Mint tokens into first_regular_account (covers both transfers). - let tx_id = - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id).await?; + let tx_id = client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id).await?; client.sync_state().await.unwrap(); let nonce_before = client.account_reader(from_account_id).nonce().await?; @@ -103,7 +97,7 @@ pub async fn test_batch_builder_submits_two_p2id_on_one_account( // from the batch). Give the node a reasonable window to finalize the batch's block. let mut committed_count = 0; for attempt in 0..30 { - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; client.sync_state().await.unwrap(); let all_transactions = client.get_transactions(TransactionFilter::All).await.unwrap(); committed_count = all_transactions @@ -161,17 +155,11 @@ pub async fn test_batch_builder_submits_two_p2id_on_one_account( /// `MINT_AMOUNT + TRANSFER_AMOUNT`, and both accounts' nonces advanced by exactly 1 during the /// batch. pub async fn test_batch_builder_multiple_accounts(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client.setup_two_wallets_and_faucet(AccountType::Private).await?; let account_id_a = first_regular_account.id(); let account_id_b = second_regular_account.id(); @@ -179,12 +167,14 @@ pub async fn test_batch_builder_multiple_accounts(client_config: ClientConfig) - // Pre-batch: get BOTH A and B on-chain (each with MINT_AMOUNT) so their first batch-tx deltas // are partial, not full-state. The batch apply path requires partial deltas. - let tx_id_a = - mint_and_consume(&mut client, account_id_a, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_a).await?; - let tx_id_b = - mint_and_consume(&mut client, account_id_b, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_b).await?; + let tx_id_a = client + .mint_and_consume(account_id_a, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id_a).await?; + let tx_id_b = client + .mint_and_consume(account_id_b, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id_b).await?; client.sync_state().await.unwrap(); let nonce_a_before = client.account_reader(account_id_a).nonce().await?; @@ -231,7 +221,7 @@ pub async fn test_batch_builder_multiple_accounts(client_config: ClientConfig) - let mut a_committed = 0; let mut b_committed = 0; for attempt in 0..30 { - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; client.sync_state().await.unwrap(); let all_transactions = client.get_transactions(TransactionFilter::All).await.unwrap(); a_committed = all_transactions @@ -303,29 +293,25 @@ pub async fn test_batch_builder_multiple_accounts(client_config: ClientConfig) - /// Asserts A advances by 2 nonces and B by 1, A's balance reflects two outbound notes, and B's /// reflects one outbound note (all output notes remain pending consumption). pub async fn test_batch_builder_interleaved_pushes(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client.setup_two_wallets_and_faucet(AccountType::Private).await?; let account_id_a = first_regular_account.id(); let account_id_b = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // Pre-batch: fund both A and B on-chain so their first batch-tx deltas are partial. - let tx_id_a = - mint_and_consume(&mut client, account_id_a, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_a).await?; - let tx_id_b = - mint_and_consume(&mut client, account_id_b, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_b).await?; + let tx_id_a = client + .mint_and_consume(account_id_a, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id_a).await?; + let tx_id_b = client + .mint_and_consume(account_id_b, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id_b).await?; client.sync_state().await.unwrap(); let nonce_a_before = client.account_reader(account_id_a).nonce().await?; @@ -374,7 +360,7 @@ pub async fn test_batch_builder_interleaved_pushes(client_config: ClientConfig) let mut a_committed = 0; let mut b_committed = 0; for attempt in 0..30 { - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; client.sync_state().await.unwrap(); let all_transactions = client.get_transactions(TransactionFilter::All).await.unwrap(); a_committed = all_transactions diff --git a/bin/integration-tests/src/tests/client.rs b/bin/integration-tests/src/tests/client.rs index f6a0dcdff6..07d91fdbbf 100644 --- a/bin/integration-tests/src/tests/client.rs +++ b/bin/integration-tests/src/tests/client.rs @@ -23,7 +23,7 @@ use miden_client::account::{ }; use miden_client::assembly::CodeBuilder; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig, RPO_FALCON_SCHEME_ID}; +use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig}; use miden_client::builder::ClientBuilder; use miden_client::keystore::FilesystemKeyStore; use miden_client::note::standards::NoteSyncHint; @@ -78,25 +78,20 @@ pub async fn test_client_builder_initializes_client_with_endpoint( } pub async fn test_multiple_tx_on_same_block(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client.setup_two_wallets_and_faucet(AccountType::Private).await?; let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - let tx_id = - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id).await?; + let tx_id = client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id).await?; // Build two P2ID transfer requests of TRANSFER_AMOUNT each. let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); @@ -152,7 +147,7 @@ pub async fn test_multiple_tx_on_same_block(client_config: ClientConfig) -> Resu let sender_committed = { let mut found: Vec<_> = Vec::new(); for _ in 0..30 { - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; client.sync_state().await?; found = client .get_transactions(TransactionFilter::All) @@ -201,25 +196,14 @@ pub async fn test_multiple_tx_on_same_block(client_config: ClientConfig) -> Resu } pub async fn test_import_expected_notes(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator_1) = client_config.clone().into_client().await?; - let (first_basic_account, faucet_account) = setup_wallet_and_faucet( - &mut client_1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (mut client_2, authenticator_2) = client_config.into_client().await?; - let (client_2_account, _) = insert_new_wallet( - &mut client_2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let (first_basic_account, faucet_account) = + client_1.setup_wallet_and_faucet(AccountType::Private).await?; - wait_for_node(&mut client_2).await; + let mut client_2 = client_config.into_client().await?; + let client_2_account = client_2.insert_wallet(AccountType::Private).await?; + + client_2.wait_for_node().await; let tx_request = TransactionRequestBuilder::new() .build_mint_fungible_asset( @@ -242,10 +226,10 @@ pub async fn test_import_expected_notes(client_config: ClientConfig) -> Result<( .to_string(), "note import error: No notes fetched from node".to_string() ); - execute_tx_and_sync(&mut client_1, faucet_account.id(), tx_request).await?; + client_1.execute_tx_and_sync(faucet_account.id(), tx_request).await?; // Use client 1 to wait until a couple of blocks have passed - wait_for_blocks(&mut client_1, 3).await; + client_1.wait_for_blocks(3).await?; let new_sync_data = client_2.sync_state().await.unwrap(); @@ -264,10 +248,10 @@ pub async fn test_import_expected_notes(client_config: ClientConfig) -> Result<( ); // If client 2 successfully consumes the note, we confirm we have MMR and block header data - let tx_id = - consume_notes(&mut client_2, client_2_account.id(), &[input_note.try_into().unwrap()]) - .await; - wait_for_tx(&mut client_2, tx_id).await?; + let tx_id = client_2 + .consume_notes(client_2_account.id(), &[input_note.try_into().unwrap()]) + .await?; + client_2.wait_for_tx(tx_id).await?; let tx_request = TransactionRequestBuilder::new() .build_mint_fungible_asset( @@ -303,7 +287,7 @@ pub async fn test_import_expected_notes(client_config: ClientConfig) -> Result<( // If imported before execution, the note should be imported in `Expected` state assert!(matches!(input_note.state(), InputNoteState::Expected { .. })); - execute_tx_and_sync(&mut client_1, faucet_account.id(), tx_request).await?; + client_1.execute_tx_and_sync(faucet_account.id(), tx_request).await?; client_2.sync_state().await.unwrap(); // After sync, the imported note should have inclusion proof even if it's not relevant for its @@ -316,35 +300,21 @@ pub async fn test_import_expected_notes(client_config: ClientConfig) -> Result<( assert!(input_note.inclusion_proof().is_some(), "Expected inclusion proof to be present"); // If inclusion proof is invalid this should panic - let tx_id = - consume_notes(&mut client_1, first_basic_account.id(), &[input_note.try_into().unwrap()]) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .consume_notes(first_basic_account.id(), &[input_note.try_into().unwrap()]) + .await?; + client_1.wait_for_tx(tx_id).await?; Ok(()) } pub async fn test_import_expected_note_uncommitted(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator) = client_config.clone().into_client().await?; - let faucet_account = insert_new_fungible_faucet( - &mut client_1, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap() - .0; - - let (mut client_2, authenticator_2) = client_config.clone().into_client().await?; - let (client_2_account, _) = insert_new_wallet( - &mut client_2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let faucet_account = client_1.insert_faucet(AccountType::Private).await?; + + let mut client_2 = client_config.clone().into_client().await?; + let client_2_account = client_2.insert_wallet(AccountType::Private).await?; - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( FungibleAsset::new(faucet_account.id(), MINT_AMOUNT).unwrap(), @@ -378,18 +348,13 @@ pub async fn test_import_expected_note_uncommitted(client_config: ClientConfig) pub async fn test_import_expected_notes_from_the_past_as_committed( client_config: ClientConfig, ) -> Result<()> { - let (mut client_1, authenticator_1) = client_config.clone().into_client().await?; - let (first_basic_account, faucet_account) = setup_wallet_and_faucet( - &mut client_1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let (first_basic_account, faucet_account) = + client_1.setup_wallet_and_faucet(AccountType::Private).await?; - let (mut client_2, _) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( FungibleAsset::new(faucet_account.id(), MINT_AMOUNT).unwrap(), @@ -402,7 +367,7 @@ pub async fn test_import_expected_notes_from_the_past_as_committed( let block_height_before = client_1.get_sync_height().await.unwrap(); - execute_tx_and_sync(&mut client_1, faucet_account.id(), tx_request).await?; + client_1.execute_tx_and_sync(faucet_account.id(), tx_request).await?; // importing the note before client_2 is synced will result in a note with `Expected` state let commitment = client_2 @@ -453,30 +418,23 @@ pub async fn test_import_expected_notes_from_the_past_as_committed( pub async fn test_get_account_update(client_config: ClientConfig) -> Result<()> { // Create a client with both public and private accounts. - let (mut client, authenticator) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; - let (basic_wallet_1, faucet_account) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - wait_for_node(&mut client).await; + let (basic_wallet_1, faucet_account) = + client.setup_wallet_and_faucet(AccountType::Private).await?; + client.wait_for_node().await; - let (basic_wallet_2, ..) = - insert_new_wallet(&mut client, AccountType::Public, &authenticator, RPO_FALCON_SCHEME_ID) - .await?; + let basic_wallet_2 = client.insert_wallet(AccountType::Public).await?; // Mint and consume notes with both accounts so they are included in the node. - let tx_id_1 = - mint_and_consume(&mut client, basic_wallet_1.id(), faucet_account.id(), NoteType::Private) - .await; - wait_for_tx(&mut client, tx_id_1).await?; - let tx_id_2 = - mint_and_consume(&mut client, basic_wallet_2.id(), faucet_account.id(), NoteType::Private) - .await; - wait_for_tx(&mut client, tx_id_2).await?; + let tx_id_1 = client + .mint_and_consume(basic_wallet_1.id(), faucet_account.id(), NoteType::Private) + .await?; + client.wait_for_tx(tx_id_1).await?; + let tx_id_2 = client + .mint_and_consume(basic_wallet_2.id(), faucet_account.id(), NoteType::Private) + .await?; + client.wait_for_tx(tx_id_2).await?; // Request updates from node for both accounts. The request should not fail and both types of // [`AccountDetails`] should be received. @@ -497,35 +455,25 @@ pub async fn test_get_account_update(client_config: ClientConfig) -> Result<()> } pub async fn test_sync_detail_values(client_config: ClientConfig) -> Result<()> { - let (mut client1, authenticator_1) = client_config.clone().into_client().await?; - let (mut client2, authenticator_2) = client_config.clone().into_client().await?; - wait_for_node(&mut client1).await; - wait_for_node(&mut client2).await; - - let (first_regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client1 = client_config.clone().into_client().await?; + let mut client2 = client_config.clone().into_client().await?; + client1.wait_for_node().await; + client2.wait_for_node().await; - let (second_regular_account, ..) = insert_new_wallet( - &mut client2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let (first_regular_account, faucet_account_header) = + client1.setup_wallet_and_faucet(AccountType::Private).await?; + + let second_regular_account = client2.insert_wallet(AccountType::Private).await?; let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - let tx_id = - mint_and_consume(&mut client1, from_account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client1, tx_id).await?; + let tx_id = client1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client1.wait_for_tx(tx_id).await?; // Second client sync shouldn't have any new changes let new_details = client2.sync_state().await.unwrap(); @@ -540,7 +488,7 @@ pub async fn test_sync_detail_values(client_config: ClientConfig) -> Result<()> client1.rng(), )?; let note = tx_request.expected_output_own_notes().pop().unwrap(); - execute_tx_and_sync(&mut client1, from_account_id, tx_request).await?; + client1.execute_tx_and_sync(from_account_id, tx_request).await?; // Second client sync should have new note let new_details = client2.sync_state().await.unwrap(); @@ -551,7 +499,7 @@ pub async fn test_sync_detail_values(client_config: ClientConfig) -> Result<()> // Consume the note with the second account let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![note]).unwrap(); - execute_tx_and_sync(&mut client2, to_account_id, tx_request).await?; + client2.execute_tx_and_sync(to_account_id, tx_request).await?; // First client sync should have a new nullifier as the note was consumed let new_details = client1.sync_state().await.unwrap(); @@ -566,15 +514,9 @@ pub async fn test_sync_notes_chunks_when_exceeding_limits( ) -> Result<()> { let rpc_endpoint = client_config.rpc_endpoint.clone(); let rpc_timeout = client_config.rpc_timeout_ms; - let (mut client, authenticator) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; - let (wallet, faucet) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await?; let fungible_asset = FungibleAsset::new(faucet.id(), MINT_AMOUNT)?; let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( @@ -584,7 +526,7 @@ pub async fn test_sync_notes_chunks_when_exceeding_limits( client.rng(), )?; let minted_note = tx_request.expected_output_own_notes().pop().unwrap(); - execute_tx_and_sync(&mut client, faucet.id(), tx_request).await?; + client.execute_tx_and_sync(faucet.id(), tx_request).await?; let real_tag = minted_note.metadata().tag(); @@ -610,15 +552,9 @@ pub async fn test_sync_transactions_chunks_when_exceeding_limits( ) -> Result<()> { let rpc_endpoint = client_config.rpc_endpoint.clone(); let rpc_timeout = client_config.rpc_timeout_ms; - let (mut client, authenticator) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; - let (wallet, faucet) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await?; // A mint cannot double as the account's deploy. client.deploy_account(faucet.id()).await?; @@ -631,7 +567,7 @@ pub async fn test_sync_transactions_chunks_when_exceeding_limits( client.rng(), )?; let tx_id = client.submit_new_transaction(faucet.id(), tx_request).await?; - wait_for_tx(&mut client, tx_id).await?; + client.wait_for_tx(tx_id).await?; let grpc = GrpcClient::new(&rpc_endpoint, rpc_timeout); let limits = grpc.get_rpc_limits().await?; @@ -659,15 +595,10 @@ pub async fn test_sync_transactions_chunks_when_exceeding_limits( pub async fn test_multiple_transactions_can_be_committed_in_different_blocks_without_sync( client_config: ClientConfig, ) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; - let (first_regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let (first_regular_account, faucet_account_header) = + client.setup_wallet_and_faucet(AccountType::Private).await?; let from_account_id = first_regular_account.id(); let faucet_account_id = faucet_account_header.id(); @@ -814,26 +745,15 @@ pub async fn test_multiple_transactions_can_be_committed_in_different_blocks_wit /// - Consuming authenticated notes. /// - Consuming unauthenticated notes. pub async fn test_consume_multiple_expected_notes(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator_1) = client_config.clone().into_client().await?; - let (mut unauth_client, authenticator_2) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; + let mut unauth_client = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + client.wait_for_node().await; // Setup accounts - let (target_basic_account_1, faucet_account_header) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (target_basic_account_2, ..) = insert_new_wallet( - &mut unauth_client, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let (target_basic_account_1, faucet_account_header) = + client.setup_wallet_and_faucet(AccountType::Private).await?; + let target_basic_account_2 = unauth_client.insert_wallet(AccountType::Private).await?; unauth_client.sync_state().await.unwrap(); let faucet_account_id = faucet_account_header.id(); @@ -842,14 +762,13 @@ pub async fn test_consume_multiple_expected_notes(client_config: ClientConfig) - let fungible_asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); // Mint tokens to the accounts - let mint_tx_request = mint_multiple_fungible_asset( + let mint_tx_request = client.mint_multiple_fungible_asset( fungible_asset, &[to_account_ids[0], to_account_ids[0], to_account_ids[1], to_account_ids[1]], NoteType::Private, - client.rng(), - ); + )?; let all_expected_notes = mint_tx_request.expected_output_own_notes(); - execute_tx_and_sync(&mut client, faucet_account_id, mint_tx_request).await?; + client.execute_tx_and_sync(faucet_account_id, mint_tx_request).await?; unauth_client.sync_state().await.unwrap(); @@ -880,8 +799,8 @@ pub async fn test_consume_multiple_expected_notes(client_config: ClientConfig) - assert!(!client.get_input_notes(NoteFilter::Processing).await.unwrap().is_empty()); assert!(!unauth_client.get_input_notes(NoteFilter::Processing).await.unwrap().is_empty()); - wait_for_tx(&mut client, tx_id_1).await?; - wait_for_tx(&mut unauth_client, tx_id_2).await?; + client.wait_for_tx(tx_id_1).await?; + unauth_client.wait_for_tx(tx_id_2).await?; // Verify no remaining expected notes and all notes are consumed assert!(client.get_input_notes(NoteFilter::Expected).await.unwrap().is_empty()); @@ -898,46 +817,31 @@ pub async fn test_consume_multiple_expected_notes(client_config: ClientConfig) - // Validate the final asset amounts in each account for (client, account_id) in [(client, to_account_ids[0]), (unauth_client, to_account_ids[1])] { - assert_account_has_single_asset( - &client, - account_id, - faucet_account_id, - TRANSFER_AMOUNT * 2, - ) - .await; + client + .assert_account_has_single_asset(account_id, faucet_account_id, TRANSFER_AMOUNT * 2) + .await; } Ok(()) } pub async fn test_import_consumed_note_with_proof(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator_1) = client_config.clone().into_client().await?; - let (first_regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client_1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (mut client_2, authenticator_2) = client_config.clone().into_client().await?; - let (client_2_account, _) = insert_new_wallet( - &mut client_2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let (first_regular_account, faucet_account_header) = + client_1.setup_wallet_and_faucet(AccountType::Private).await?; + + let mut client_2 = client_config.clone().into_client().await?; + let client_2_account = client_2.insert_wallet(AccountType::Private).await?; - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; let from_account_id = first_regular_account.id(); let to_account_id = client_2_account.id(); let faucet_account_id = faucet_account_header.id(); - let tx_id = - mint_and_consume(&mut client_1, from_account_id, faucet_account_id, NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; let current_block_num = client_1.get_sync_height().await.unwrap(); let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); @@ -949,7 +853,7 @@ pub async fn test_import_consumed_note_with_proof(client_config: ClientConfig) - NoteType::Private, client_1.rng(), )?; - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; let note = client_1 .get_input_notes(NoteFilter::Committed) .await @@ -964,7 +868,7 @@ pub async fn test_import_consumed_note_with_proof(client_config: ClientConfig) - let tx_request = TransactionRequestBuilder::new() .build_consume_notes(vec![note.clone().try_into().unwrap()]) .unwrap(); - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; // Import the consumed note client_2 @@ -986,28 +890,22 @@ pub async fn test_import_consumed_note_with_proof(client_config: ClientConfig) - } pub async fn test_import_consumed_note_with_id(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator) = client_config.clone().into_client().await?; + let mut client_1 = client_config.clone().into_client().await?; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client_1, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client_1.setup_two_wallets_and_faucet(AccountType::Private).await?; - let (mut client_2, _) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); - let tx_id = - mint_and_consume(&mut client_1, from_account_id, faucet_account_id, NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; let current_block_num = client_1.get_sync_height().await.unwrap(); let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); @@ -1019,7 +917,7 @@ pub async fn test_import_consumed_note_with_id(client_config: ClientConfig) -> R NoteType::Public, client_1.rng(), )?; - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; let note = client_1 .get_input_notes(NoteFilter::Committed) .await @@ -1034,7 +932,7 @@ pub async fn test_import_consumed_note_with_id(client_config: ClientConfig) -> R let tx_request = TransactionRequestBuilder::new() .build_consume_notes(vec![note.clone().try_into().unwrap()]) .unwrap(); - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; client_2.sync_state().await.unwrap(); // Import the consumed note @@ -1052,28 +950,22 @@ pub async fn test_import_consumed_note_with_id(client_config: ClientConfig) -> R } pub async fn test_import_note_with_proof(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator) = client_config.clone().into_client().await?; + let mut client_1 = client_config.clone().into_client().await?; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client_1, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client_1.setup_two_wallets_and_faucet(AccountType::Private).await?; - let (mut client_2, _) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); - let tx_id = - mint_and_consume(&mut client_1, from_account_id, faucet_account_id, NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; let current_block_num = client_1.get_sync_height().await.unwrap(); let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); @@ -1085,7 +977,7 @@ pub async fn test_import_note_with_proof(client_config: ClientConfig) -> Result< NoteType::Private, client_1.rng(), )?; - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; let note = client_1 .get_input_notes(NoteFilter::Committed) @@ -1113,34 +1005,23 @@ pub async fn test_import_note_with_proof(client_config: ClientConfig) -> Result< } pub async fn test_discarded_transaction(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator_1) = client_config.clone().into_client().await?; - let (first_regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client_1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (mut client_2, authenticator_2) = client_config.clone().into_client().await?; - let (second_regular_account, ..) = insert_new_wallet( - &mut client_2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let (first_regular_account, faucet_account_header) = + client_1.setup_wallet_and_faucet(AccountType::Private).await?; + + let mut client_2 = client_config.clone().into_client().await?; + let second_regular_account = client_2.insert_wallet(AccountType::Private).await?; - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); - let tx_id = - mint_and_consume(&mut client_1, from_account_id, faucet_account_id, NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; let current_block_num = client_1.get_sync_height().await.unwrap(); let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); @@ -1153,7 +1034,7 @@ pub async fn test_discarded_transaction(client_config: ClientConfig) -> Result<( client_1.rng(), )?; - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; client_2.sync_state().await.unwrap(); let note = client_1 .get_input_notes(NoteFilter::Committed) @@ -1197,7 +1078,7 @@ pub async fn test_discarded_transaction(client_config: ClientConfig) -> Result<( assert!(matches!(note_record.state(), InputNoteState::ProcessingAuthenticated(_))); // Consume the note in client 2 - execute_tx_and_sync(&mut client_2, to_account_id, tx_request).await?; + client_2.execute_tx_and_sync(to_account_id, tx_request).await?; let note_record = client_2.get_input_note(note.id().unwrap()).await?.unwrap(); assert!(matches!(note_record.state(), InputNoteState::ConsumedAuthenticatedLocal(_))); @@ -1261,14 +1142,9 @@ impl TransactionProver for AlwaysFailingProver { pub async fn test_custom_transaction_prover_error_caught( client_config: ClientConfig, ) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - let (first_regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client = client_config.into_client().await?; + let (first_regular_account, faucet_account_header) = + client.setup_wallet_and_faucet(AccountType::Private).await?; let from_account_id = first_regular_account.id(); let faucet_account_id = faucet_account_header.id(); @@ -1300,33 +1176,21 @@ pub async fn test_custom_transaction_prover_error_caught( } pub async fn test_locked_account(client_config: ClientConfig) -> Result<()> { - let (mut client_1, authenticator) = client_config.clone().into_client().await?; + let mut client_1 = client_config.clone().into_client().await?; - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let faucet_account = client_1.insert_faucet(AccountType::Private).await?; - let (private_account, _) = insert_new_wallet( - &mut client_1, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let private_account = client_1.insert_wallet(AccountType::Private).await?; let from_account_id = private_account.id(); let faucet_account_id = faucet_account.id(); - wait_for_node(&mut client_1).await; + client_1.wait_for_node().await; - let tx_id = - mint_and_consume(&mut client_1, from_account_id, faucet_account_id, NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; // Get full account from store for export to client_2 let private_account: Account = @@ -1335,19 +1199,19 @@ pub async fn test_locked_account(client_config: ClientConfig) -> Result<()> { let original_seed = private_account.seed(); // Import private account in client 2 - let (mut client_2, _) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; client_2.add_account(&private_account, false).await.unwrap(); - wait_for_node(&mut client_2).await; + client_2.wait_for_node().await; // When imported the account shouldn't be locked assert!(!client_2.account_reader(from_account_id).status().await.unwrap().is_locked()); // Consume note with private account in client 1 - let tx_id = - mint_and_consume(&mut client_1, from_account_id, faucet_account_id, NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; // After sync the private account should be locked in client 2 let summary = client_2.sync_state().await.unwrap(); @@ -1368,23 +1232,15 @@ pub async fn test_locked_account(client_config: ClientConfig) -> Result<()> { } pub async fn test_expired_transaction_fails(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client = client_config.into_client().await?; + let faucet_account = client.insert_faucet(AccountType::Private).await?; - let (private_account, ..) = - insert_new_wallet(&mut client, AccountType::Private, &authenticator, RPO_FALCON_SCHEME_ID) - .await?; + let private_account = client.insert_wallet(AccountType::Private).await?; let from_account_id = private_account.id(); let faucet_account_id = faucet_account.id(); - wait_for_node(&mut client).await; + client.wait_for_node().await; let expiration_delta = 2; @@ -1405,7 +1261,7 @@ pub async fn test_expired_transaction_fails(client_config: ClientConfig) -> Resu client.execute_transaction(faucet_account_id, tx_request).await.unwrap(); info!(tx_id = %transaction_result.id(), "Transaction executed, waiting for expiration"); - wait_for_blocks(&mut client, (expiration_delta + 1).into()).await; + client.wait_for_blocks((expiration_delta + 1).into()).await?; info!("Sending expired transaction to node (expecting failure)"); let proven_transaction = client.prove_transaction(&transaction_result).await.unwrap(); @@ -1427,13 +1283,12 @@ pub async fn test_expired_transaction_fails(client_config: ClientConfig) -> Resu /// Tests that RPC methods that are not directly related to the client logic (like GetBlockByNumber) /// work correctly pub async fn test_unused_rpc_api(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; let (first_basic_account, faucet_account) = - setup_wallet_and_faucet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + client.setup_wallet_and_faucet(AccountType::Public).await?; - wait_for_node(&mut client).await; + client.wait_for_node().await; client.sync_state().await.unwrap(); let first_block_num = client.get_sync_height().await.unwrap(); @@ -1446,14 +1301,15 @@ pub async fn test_unused_rpc_api(client_config: ClientConfig) -> Result<()> { assert_eq!(&block_header, block.header()); - let (tx_id, note) = - mint_note(&mut client, first_basic_account.id(), faucet_account.id(), NoteType::Public) - .await; - wait_for_tx(&mut client, tx_id).await?; + let (tx_id, note) = client + .mint_note(first_basic_account.id(), faucet_account.id(), NoteType::Public) + .await?; + client.wait_for_tx(tx_id).await?; - let tx_id = - consume_notes(&mut client, first_basic_account.id(), std::slice::from_ref(¬e)).await; - wait_for_tx(&mut client, tx_id).await?; + let tx_id = client + .consume_notes(first_basic_account.id(), std::slice::from_ref(¬e)) + .await?; + client.wait_for_tx(tx_id).await?; // Test get_account retrieval (account must be deployed on-chain first) let (proof_block_num, account_proof) = client @@ -1503,14 +1359,18 @@ pub async fn test_unused_rpc_api(client_config: ClientConfig) -> Result<()> { let map_slot_name = StorageSlotName::new("miden::testing::client::map").expect("slot name should be valid"); let storage_slots = vec![StorageSlot::with_map(map_slot_name, storage_map)]; - let (account_with_map_item, _) = insert_account_with_custom_component( - &mut client, - custom_code, + let component_code = CodeBuilder::default() + .compile_component_code("custom::component", custom_code) + .context("failed to compile component code")?; + let custom_component = AccountComponent::new( + component_code, storage_slots, - AccountType::Public, - &keystore, + AccountComponentMetadata::new("miden::testing::custom_component"), ) - .await?; + .map_err(|err| anyhow::anyhow!(err))?; + let (account_with_map_item, _) = client + .insert_account(AccountSetup::wallet(AccountType::Public).component(custom_component)) + .await?; client.sync_state().await.unwrap(); @@ -1529,17 +1389,12 @@ pub async fn test_unused_rpc_api(client_config: ClientConfig) -> Result<()> { )?; let tx_request = TransactionRequestBuilder::new().custom_script(tx_script).build()?; - execute_tx_and_sync(&mut client, account_with_map_item.id(), tx_request.clone()).await?; + client + .execute_tx_and_sync(account_with_map_item.id(), tx_request.clone()) + .await?; // Mint a new fungible asset to check account vault changes - let faucet = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &keystore, - RPO_FALCON_SCHEME_ID, - ) - .await? - .0; + let faucet = client.insert_faucet(AccountType::Private).await?; let fungible_asset = FungibleAsset::new(faucet.id(), MINT_AMOUNT)?; let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( @@ -1549,10 +1404,12 @@ pub async fn test_unused_rpc_api(client_config: ClientConfig) -> Result<()> { client.rng(), )?; let note = tx_request.expected_output_own_notes().pop().unwrap(); - execute_tx_and_sync(&mut client, fungible_asset.faucet_id(), tx_request.clone()).await?; + client + .execute_tx_and_sync(fungible_asset.faucet_id(), tx_request.clone()) + .await?; let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![note.clone()])?; - execute_tx_and_sync(&mut client, first_basic_account.id(), tx_request).await?; + client.execute_tx_and_sync(first_basic_account.id(), tx_request).await?; let nullifier = note.nullifier(); @@ -1596,15 +1453,9 @@ pub async fn test_unused_rpc_api(client_config: ClientConfig) -> Result<()> { } pub async fn test_ignore_invalid_notes(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; let (regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + client.setup_two_wallets_and_faucet(AccountType::Private).await?; let account_id = regular_account.id(); let second_account_id = second_regular_account.id(); @@ -1612,19 +1463,21 @@ pub async fn test_ignore_invalid_notes(client_config: ClientConfig) -> Result<() // Mint 2 valid notes let (tx_id_1, note_1) = - mint_note(&mut client, account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_1).await?; + client.mint_note(account_id, faucet_account_id, NoteType::Private).await?; + client.wait_for_tx(tx_id_1).await?; let (tx_id_2, note_2) = - mint_note(&mut client, account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_2).await?; + client.mint_note(account_id, faucet_account_id, NoteType::Private).await?; + client.wait_for_tx(tx_id_2).await?; // Mint 2 invalid notes - let (tx_id_3, note_3) = - mint_note(&mut client, second_account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_3).await?; - let (tx_id_4, note_4) = - mint_note(&mut client, second_account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client, tx_id_4).await?; + let (tx_id_3, note_3) = client + .mint_note(second_account_id, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id_3).await?; + let (tx_id_4, note_4) = client + .mint_note(second_account_id, faucet_account_id, NoteType::Private) + .await?; + client.wait_for_tx(tx_id_4).await?; // Create a transaction to consume all 4 notes but ignore the invalid ones let tx_request = TransactionRequestBuilder::new() @@ -1636,7 +1489,7 @@ pub async fn test_ignore_invalid_notes(client_config: ClientConfig) -> Result<() note_4.clone(), ])?; - execute_tx_and_sync(&mut client, account_id, tx_request).await?; + client.execute_tx_and_sync(account_id, tx_request).await?; let consumed_notes = client.get_input_notes(NoteFilter::Consumed).await.unwrap(); // Checked by ID rather than by count: on a fee-charging chain the account also consumed its @@ -1654,17 +1507,9 @@ pub async fn test_ignore_invalid_notes(client_config: ClientConfig) -> Result<() } pub async fn test_output_only_note(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; - let faucet = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap() - .0; + let faucet = client.insert_faucet(AccountType::Private).await?; let fungible_asset = FungibleAsset::new(faucet.id(), MINT_AMOUNT).unwrap(); let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( @@ -1674,7 +1519,9 @@ pub async fn test_output_only_note(client_config: ClientConfig) -> Result<()> { client.rng(), )?; let note_id = tx_request.expected_output_own_notes().pop().unwrap().id(); - execute_tx_and_sync(&mut client, fungible_asset.faucet_id(), tx_request.clone()).await?; + client + .execute_tx_and_sync(fungible_asset.faucet_id(), tx_request.clone()) + .await?; // The created note should be an output only note because it is not consumable by any client // account. @@ -1695,8 +1542,8 @@ pub async fn test_output_only_note(client_config: ClientConfig) -> Result<()> { /// - Requesting several keys, one of them absent from the map, returns a single `PartialMap` /// covering all of them, proving the absent one holds no value. pub async fn test_get_account_storage_map_key_filtering(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; let map_slot_name = StorageSlotName::new("miden::testing::client::map").expect("valid slot name"); @@ -1745,7 +1592,11 @@ pub async fn test_get_account_storage_map_key_filtering(client_config: ClientCon .context("failed to build account")?; let account_id = account.id(); - keystore.add_key(&key_pair, account_id).await.context("failed to add key")?; + client + .keystore() + .add_key(&key_pair, account_id) + .await + .context("failed to add key")?; client.add_account(&account, false).await?; // Deploy the account (first tx updates nonce) @@ -1854,16 +1705,14 @@ pub async fn test_get_account_storage_map_key_filtering(client_config: ClientCon /// assets are empty. /// - [`VaultFetch::Skip`] (default): vault data not requested, so assets are empty. pub async fn test_get_account_returns_vault_details(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Public).await?; // Mint tokens so the wallet has assets in its vault - let tx_id = mint_and_consume(&mut client, wallet.id(), faucet.id(), NoteType::Public).await; - wait_for_tx(&mut client, tx_id).await?; + let tx_id = client.mint_and_consume(wallet.id(), faucet.id(), NoteType::Public).await?; + client.wait_for_tx(tx_id).await?; let rpc = client.test_rpc_api(); @@ -1929,26 +1778,21 @@ pub async fn test_get_account_returns_vault_details(client_config: ClientConfig) /// `prune_account_history` deletes intermediate states while keeping the account readable and /// unchanged. pub async fn test_prune_account_history(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; - - let (basic_account, faucet_account) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; + + let (basic_account, faucet_account) = + client.setup_wallet_and_faucet(AccountType::Private).await?; let faucet_id = faucet_account.id(); let wallet_id = basic_account.id(); // Mint twice: each mint advances the faucet nonce, creating historical entries. - let (tx_id_1, _) = mint_note(&mut client, wallet_id, faucet_id, NoteType::Public).await; - wait_for_tx(&mut client, tx_id_1).await?; + let (tx_id_1, _) = client.mint_note(wallet_id, faucet_id, NoteType::Public).await?; + client.wait_for_tx(tx_id_1).await?; - let (tx_id_2, _) = mint_note(&mut client, wallet_id, faucet_id, NoteType::Public).await; - wait_for_tx(&mut client, tx_id_2).await?; + let (tx_id_2, _) = client.mint_note(wallet_id, faucet_id, NoteType::Public).await?; + client.wait_for_tx(tx_id_2).await?; // Record faucet state before pruning. let faucet_before = client.get_account(faucet_id).await?.unwrap(); diff --git a/bin/integration-tests/src/tests/custom_transaction.rs b/bin/integration-tests/src/tests/custom_transaction.rs index c7781d1625..4a0c7e9a2a 100644 --- a/bin/integration-tests/src/tests/custom_transaction.rs +++ b/bin/integration-tests/src/tests/custom_transaction.rs @@ -1,7 +1,6 @@ use anyhow::{Context, Result}; use miden_client::account::{AccountId, AccountType}; use miden_client::asset::FungibleAsset; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::crypto::{FeltRng, MerkleStore, MerkleTree, NodeIndex, Poseidon2, RandomCoin}; use miden_client::note::{ Note, @@ -53,22 +52,14 @@ const NOTE_ARGS: [Felt; 8] = [ ]; pub async fn test_transaction_request(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; client.sync_state().await?; // Insert Account - let (regular_account, _) = - insert_new_wallet(&mut client, AccountType::Private, &authenticator, RPO_FALCON_SCHEME_ID) - .await?; - - let (fungible_faucet, _) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let regular_account = client.insert_wallet(AccountType::Private).await?; + + let fungible_faucet = client.insert_faucet(AccountType::Private).await?; // The transaction below cannot double as the account's deploy. client.deploy_account(regular_account.id()).await?; @@ -145,7 +136,7 @@ pub async fn test_transaction_request(client_config: ClientConfig) -> Result<()> .any(|nullifier| nullifier == note.nullifier().as_word()) ); - wait_for_tx(&mut client, tx_id).await?; + client.wait_for_tx(tx_id).await?; // Assert that the note was consumed on chain let input_note = client @@ -157,22 +148,14 @@ pub async fn test_transaction_request(client_config: ClientConfig) -> Result<()> } pub async fn test_merkle_store(client_config: ClientConfig) -> Result<()> { - let (mut client, authenticator) = client_config.into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.into_client().await?; + client.wait_for_node().await; client.sync_state().await?; // Insert Account - let (regular_account, _) = - insert_new_wallet(&mut client, AccountType::Private, &authenticator, RPO_FALCON_SCHEME_ID) - .await?; - - let (fungible_faucet, _) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let regular_account = client.insert_wallet(AccountType::Private).await?; + + let fungible_faucet = client.insert_faucet(AccountType::Private).await?; // Execute mint transaction in order to increase nonce let note = mint_custom_note(&mut client, fungible_faucet.id(), regular_account.id()).await?; client.sync_state().await?; @@ -235,7 +218,7 @@ pub async fn test_merkle_store(client_config: ClientConfig) -> Result<()> { .extend_merkle_store(merkle_store.inner_nodes()) .build()?; - execute_tx_and_sync(&mut client, regular_account.id(), transaction_request).await?; + client.execute_tx_and_sync(regular_account.id(), transaction_request).await?; client.sync_state().await?; Ok(()) @@ -243,21 +226,18 @@ pub async fn test_merkle_store(client_config: ClientConfig) -> Result<()> { pub async fn test_onchain_notes_sync_with_tag(client_config: ClientConfig) -> Result<()> { // Client 1 has an private faucet which will mint an onchain note for client 2 - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; + let mut client_1 = client_config.clone().into_client().await?; // Client 2 will be used to sync and check that by adding the tag we can still fetch notes whose // tag doesn't necessarily match any of its accounts - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; // Client 3 will be the control client. We won't add any tags and expect the note not to be // fetched - let (mut client_3, ..) = client_config.clone().into_client().await?; - wait_for_node(&mut client_3).await; + let mut client_3 = client_config.clone().into_client().await?; + client_3.wait_for_node().await; // Create accounts - let (basic_account_1, ..) = - insert_new_wallet(&mut client_1, AccountType::Private, &keystore_1, RPO_FALCON_SCHEME_ID) - .await?; - insert_new_wallet(&mut client_2, AccountType::Private, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + let basic_account_1 = client_1.insert_wallet(AccountType::Private).await?; + client_2.insert_wallet(AccountType::Private).await?; client_1.sync_state().await?; client_2.sync_state().await?; @@ -289,7 +269,7 @@ pub async fn test_onchain_notes_sync_with_tag(client_config: ClientConfig) -> Re .pop() .with_context(|| "no expected output notes found in transaction request")? .clone(); - execute_tx_and_sync(&mut client_1, basic_account_1.id(), tx_request).await?; + client_1.execute_tx_and_sync(basic_account_1.id(), tx_request).await?; // Load tag into client 2 client_2 @@ -323,7 +303,7 @@ async fn mint_custom_note( let transaction_request = TransactionRequestBuilder::new().own_output_notes(vec![note.clone()]).build()?; - execute_tx_and_sync(client, faucet_account_id, transaction_request).await?; + client.execute_tx_and_sync(faucet_account_id, transaction_request).await?; Ok(note) } diff --git a/bin/integration-tests/src/tests/fpi.rs b/bin/integration-tests/src/tests/fpi.rs index 4d56d98baf..49e44e2fa8 100644 --- a/bin/integration-tests/src/tests/fpi.rs +++ b/bin/integration-tests/src/tests/fpi.rs @@ -24,7 +24,7 @@ use miden_client::auth::{ AuthSingleSig, RPO_FALCON_SCHEME_ID, }; -use miden_client::keystore::{FilesystemKeyStore, Keystore}; +use miden_client::keystore::Keystore; use miden_client::note::NoteType; use miden_client::rpc::domain::account::AccountStorageRequirements; use miden_client::testing::common::*; @@ -60,13 +60,12 @@ pub async fn test_standard_fpi_private(client_config: ClientConfig) -> Result<() } pub async fn test_fpi_execute_program(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; client.sync_state().await?; // Deploy a foreign account let (foreign_account, proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, " use miden::protocol::active_account @@ -125,15 +124,13 @@ pub async fn test_fpi_execute_program(client_config: ClientConfig) -> Result<()> // We create a new client here to force the creation of a new, fresh prover with no previous // MAST forest data. - let (mut client2, keystore2) = client_config.clone().into_client().await?; + let mut client2 = client_config.clone().into_client().await?; // NOTE: Syncing the client is important because the client needs to be beyond the account // creation block client2.sync_state().await?; - let (wallet, ..) = - insert_new_wallet(&mut client2, AccountType::Private, &keystore2, RPO_FALCON_SCHEME_ID) - .await?; + let wallet = client2.insert_wallet(AccountType::Private).await?; let output_stack = client2 .execute_program( @@ -155,12 +152,11 @@ pub async fn test_fpi_execute_program(client_config: ClientConfig) -> Result<()> } pub async fn test_nested_fpi_calls(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.clone().into_client().await?; + client.wait_for_node().await; let (inner_foreign_account, inner_proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, " use miden::protocol::active_account @@ -178,7 +174,6 @@ pub async fn test_nested_fpi_calls(client_config: ClientConfig) -> Result<()> { let (outer_foreign_account, outer_proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, format!( " @@ -279,11 +274,9 @@ pub async fn test_nested_fpi_calls(client_config: ClientConfig) -> Result<()> { // We create a new client here to force the creation of a new, fresh prover with no previous // MAST forest data. - let (mut client2, keystore2) = client_config.clone().into_client().await?; + let mut client2 = client_config.clone().into_client().await?; - let (native_account, ..) = - insert_new_wallet(&mut client2, AccountType::Public, &keystore2, RPO_FALCON_SCHEME_ID) - .await?; + let native_account = client2.insert_wallet(AccountType::Public).await?; _ = client2.submit_new_transaction(native_account.id(), tx_request).await?; @@ -293,8 +286,8 @@ pub async fn test_nested_fpi_calls(client_config: ClientConfig) -> Result<()> { /// Tests that foreign accounts are lazily loaded via RPC when not specified upfront in the /// `TransactionRequestBuilder`. pub async fn test_lazy_fpi_loading(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.clone().into_client().await?; + client.wait_for_node().await; // Create a simple foreign account with a constant-returning procedure. let constant_value: Word = @@ -302,7 +295,6 @@ pub async fn test_lazy_fpi_loading(client_config: ClientConfig) -> Result<()> { let (foreign_account, proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, format!( r#" @@ -336,18 +328,16 @@ pub async fn test_lazy_fpi_loading(client_config: ClientConfig) -> Result<()> { client.sync_state().await?; // Wait for blocks so the account is committed on-chain. - wait_for_blocks(&mut client, 2).await; + client.wait_for_blocks(2).await?; // Create a new client to ensure no cached data. - let (mut client2, keystore2) = client_config.clone().into_client().await?; + let mut client2 = client_config.clone().into_client().await?; client2.sync_state().await?; - let (native_account, ..) = - insert_new_wallet(&mut client2, AccountType::Public, &keystore2, RPO_FALCON_SCHEME_ID) - .await?; + let native_account = client2.insert_wallet(AccountType::Public).await?; - wait_for_blocks_no_sync(&mut client2, 2).await; + client2.wait_for_blocks_no_sync(2).await?; // Before the transaction there are no cached foreign accounts. let cached = client2.test_store().get_foreign_account_code(vec![foreign_account_id]).await?; @@ -372,13 +362,12 @@ pub async fn test_lazy_fpi_loading(client_config: ClientConfig) -> Result<()> { /// the procedure reads from the storage map, `get_storage_map_witness` detects the cache miss and /// makes a second RPC call to fetch the storage map entries. pub async fn test_lazy_fpi_loading_with_storage_map(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.clone().into_client().await?; + client.wait_for_node().await; // Deploy a foreign account with a storage map (same as standard FPI tests). let (foreign_account, proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, format!( r#" @@ -417,17 +406,15 @@ pub async fn test_lazy_fpi_loading_with_storage_map(client_config: ClientConfig) let tx_script = client.code_builder().compile_tx_script(&tx_script)?; client.sync_state().await?; - wait_for_blocks(&mut client, 2).await; + client.wait_for_blocks(2).await?; // Create a new client to ensure no cached data. - let (mut client2, keystore2) = client_config.clone().into_client().await?; + let mut client2 = client_config.clone().into_client().await?; client2.sync_state().await?; - let (native_account, ..) = - insert_new_wallet(&mut client2, AccountType::Public, &keystore2, RPO_FALCON_SCHEME_ID) - .await?; + let native_account = client2.insert_wallet(AccountType::Public).await?; - wait_for_blocks_no_sync(&mut client2, 2).await; + client2.wait_for_blocks_no_sync(2).await?; // Build request WITHOUT specifying the foreign account — lazy loading should handle both the // account inputs and the storage map entries via separate RPC calls. @@ -452,12 +439,11 @@ async fn standard_fpi( client_config: ClientConfig, auth_scheme: AuthSchemeId, ) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.clone().into_client().await?; + client.wait_for_node().await; let (foreign_account, proc_root) = deploy_foreign_account( &mut client, - &keystore, account_type, " use miden::protocol::active_account @@ -557,18 +543,16 @@ async fn standard_fpi( // We create a new client here to force the creation of a new, fresh prover with no previous // MAST forest data. - let (mut client2, keystore2) = client_config.clone().into_client().await?; + let mut client2 = client_config.clone().into_client().await?; // NOTE: Syncing the client is important because the client needs to be beyond the account // creation block client2.sync_state().await?; - let (native_account, ..) = - insert_new_wallet(&mut client2, AccountType::Public, &keystore2, RPO_FALCON_SCHEME_ID) - .await?; + let native_account = client2.insert_wallet(AccountType::Public).await?; let block_before_wait = client2.get_sync_height().await.unwrap(); - wait_for_blocks_no_sync(&mut client2, 2).await; + client2.wait_for_blocks_no_sync(2).await?; // Second client should be able to submit a transaction Without being synced to latest state let _ = client2.submit_new_transaction(native_account.id(), tx_request).await?; @@ -600,14 +584,13 @@ async fn standard_fpi( async fn setup_fpi_vault_asset_read( client_config: &ClientConfig, ) -> Result<(AccountId, String, [Felt; 16])> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + let mut client = client_config.clone().into_client().await?; + client.wait_for_node().await; client.sync_state().await?; // Deploy a foreign account exposing a procedure that reads an asset from its own vault. let (foreign_account, proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, " use miden::protocol::active_account @@ -623,18 +606,13 @@ async fn setup_fpi_vault_asset_read( let foreign_account_id = foreign_account.id(); // Fund the foreign account's vault so the asset read runs against a non-empty vault. - let (faucet_account, ..) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &keystore, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (tx_id, note) = - mint_note(&mut client, foreign_account_id, faucet_account.id(), NoteType::Private).await; - wait_for_tx(&mut client, tx_id).await?; - let tx_id = consume_notes(&mut client, foreign_account_id, &[note]).await; - wait_for_tx(&mut client, tx_id).await?; + let faucet_account = client.insert_faucet(AccountType::Private).await?; + let (tx_id, note) = client + .mint_note(foreign_account_id, faucet_account.id(), NoteType::Private) + .await?; + client.wait_for_tx(tx_id).await?; + let tx_id = client.consume_notes(foreign_account_id, &[note]).await?; + client.wait_for_tx(tx_id).await?; let fungible_asset = FungibleAsset::new(faucet_account.id(), MINT_AMOUNT) .context("failed to build the expected fungible asset")?; @@ -685,11 +663,9 @@ pub async fn test_fpi_vault_asset_read_untracked(client_config: ClientConfig) -> setup_fpi_vault_asset_read(&client_config).await?; // A fresh client, so no foreign account data is cached or tracked. - let (mut client, keystore) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; client.sync_state().await?; - let (wallet, ..) = - insert_new_wallet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let wallet = client.insert_wallet(AccountType::Private).await?; let tx_script = client.code_builder().compile_tx_script(&tx_script_code)?; let foreign_accounts = BTreeMap::from([( foreign_account_id, @@ -715,11 +691,9 @@ pub async fn test_fpi_vault_asset_read_tracked(client_config: ClientConfig) -> R let (foreign_account_id, tx_script_code, expected_stack) = setup_fpi_vault_asset_read(&client_config).await?; - let (mut client, keystore) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; client.sync_state().await?; - let (wallet, ..) = - insert_new_wallet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let wallet = client.insert_wallet(AccountType::Private).await?; // Track the foreign account so the client's stored vault root matches the node's. client.import_account_by_id(foreign_account_id).await?; @@ -824,7 +798,6 @@ fn foreign_account_with_code( /// - `Word` - The procedure root of the foreign account. pub(crate) async fn deploy_foreign_account( client: &mut TestClient, - keystore: &FilesystemKeyStore, account_type: AccountType, code: String, auth_scheme: AuthSchemeId, @@ -833,7 +806,8 @@ pub(crate) async fn deploy_foreign_account( foreign_account_with_code(account_type, code, auth_scheme)?; let foreign_account_id = foreign_account.id(); - keystore + client + .keystore() .add_key(&secret_key, foreign_account_id) .await .with_context(|| "failed to add key to keystore")?; diff --git a/bin/integration-tests/src/tests/network_fpi.rs b/bin/integration-tests/src/tests/network_fpi.rs index 1b668f0647..0078937b99 100644 --- a/bin/integration-tests/src/tests/network_fpi.rs +++ b/bin/integration-tests/src/tests/network_fpi.rs @@ -1,7 +1,6 @@ use anyhow::{Context, Result}; use miden_client::account::AccountType; use miden_client::auth::RPO_FALCON_SCHEME_ID; -use miden_client::testing::common::{execute_tx_and_sync, insert_new_wallet, wait_for_blocks}; use miden_client::transaction::TransactionRequestBuilder; use miden_client::{Felt, Word, ZERO}; @@ -28,12 +27,11 @@ use crate::ClientConfig; /// account. In order to check whether the FPI was successful (note script was executed /// successfully), note script updates the counter of the network (counter) account. pub async fn test_network_fpi(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; client.sync_state().await?; let (foreign_account, proc_root) = deploy_foreign_account( &mut client, - &keystore, AccountType::Public, format!( r#" @@ -69,7 +67,7 @@ pub async fn test_network_fpi(client_config: ClientConfig) -> Result<()> { client.sync_state().await?; - let (mut client2, keystore2) = client_config.into_client().await?; + let mut client2 = client_config.into_client().await?; // NOTE: Syncing the client is important because the client needs to be beyond the account // creation block @@ -113,9 +111,7 @@ pub async fn test_network_fpi(client_config: ClientConfig) -> Result<()> { client2.sync_state().await?; - let (sender_account, ..) = - insert_new_wallet(&mut client2, AccountType::Private, &keystore2, RPO_FALCON_SCHEME_ID) - .await?; + let sender_account = client2.insert_wallet(AccountType::Private).await?; let network_note = get_network_note_with_script( sender_account.id(), @@ -127,7 +123,7 @@ pub async fn test_network_fpi(client_config: ClientConfig) -> Result<()> { let tx_request = TransactionRequestBuilder::new().own_output_notes([network_note]).build()?; - execute_tx_and_sync(&mut client2, sender_account.id(), tx_request).await?; + client2.execute_tx_and_sync(sender_account.id(), tx_request).await?; // The node runs the network transaction some blocks after the note is committed. The number of // blocks depends on the proving time of the node, so poll the counter instead of waiting for a @@ -145,7 +141,7 @@ pub async fn test_network_fpi(client_config: ClientConfig) -> Result<()> { return Ok(()); } - wait_for_blocks(&mut client2, 1).await; + client2.wait_for_blocks(1).await?; } let updated_network_account = client2 diff --git a/bin/integration-tests/src/tests/network_transaction.rs b/bin/integration-tests/src/tests/network_transaction.rs index 86bdcbf21f..70964bde63 100644 --- a/bin/integration-tests/src/tests/network_transaction.rs +++ b/bin/integration-tests/src/tests/network_transaction.rs @@ -31,7 +31,6 @@ use miden_client::account::{ }; use miden_client::assembly::{CodeBuilder, SourceManagerSync}; use miden_client::asset::{AssetAmount, FungibleAsset, TokenSymbol}; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::block::BlockNumber; use miden_client::crypto::FeltRng; use miden_client::note::{ @@ -59,15 +58,7 @@ use miden_client::note::{ }; use miden_client::store::{InputNoteState, NoteFilter}; use miden_client::sync::NoteTagSource; -use miden_client::testing::common::{ - TestClient, - assert_account_has_single_asset, - consume_notes, - execute_tx_and_sync, - insert_new_wallet, - wait_for_blocks, - wait_for_tx, -}; +use miden_client::testing::common::TestClient; use miden_client::transaction::TransactionRequestBuilder; use miden_client::{Felt, Word, ZERO}; use rand::{Rng, RngExt}; @@ -378,7 +369,7 @@ async fn wait_for_committed_note( max_blocks: u32, ) -> Result { for _ in 0..max_blocks { - wait_for_blocks(block_client, 1).await; + block_client.wait_for_blocks(1).await?; observer.sync_state().await?; if let Some(rec) = observer .get_input_notes(NoteFilter::DetailsCommitments(vec![details_commitment])) @@ -465,7 +456,7 @@ fn build_non_standard_mint( /// account consumes them and the counter is bumped. pub async fn test_counter_contract_ntx(client_config: ClientConfig) -> Result<()> { const BUMP_NOTE_NUMBER: u64 = 5; - let (mut client, keystore) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; client.sync_state().await?; let incr_note_root = note_script_root(INCR_NOTE_SCRIPT_CODE, client.source_manager())?; @@ -478,9 +469,7 @@ pub async fn test_counter_contract_ntx(client_config: ClientConfig) -> Result<() .context("failed to find network account after deployment")?; assert_eq!(counter_value, Word::from([ZERO, ZERO, ZERO, ZERO])); - let (native_account, ..) = - insert_new_wallet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let native_account = client.insert_wallet(AccountType::Public).await?; let mut network_notes = vec![]; @@ -497,7 +486,7 @@ pub async fn test_counter_contract_ntx(client_config: ClientConfig) -> Result<() let tx_request = TransactionRequestBuilder::new().own_output_notes(network_notes).build()?; - execute_tx_and_sync(&mut client, native_account.id(), tx_request).await?; + client.execute_tx_and_sync(native_account.id(), tx_request).await?; // Wait for the node to consume the network notes in subsequent blocks let expected_counter = Word::from([Felt::new_unchecked(BUMP_NOTE_NUMBER), ZERO, ZERO, ZERO]); @@ -512,7 +501,7 @@ pub async fn test_counter_contract_ntx(client_config: ClientConfig) -> Result<() return Ok(()); } - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; } let a = client @@ -526,7 +515,7 @@ pub async fn test_counter_contract_ntx(client_config: ClientConfig) -> Result<() } pub async fn test_recall_note_before_ntx_consumes_it(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; client.sync_state().await?; let incr_note_root = note_script_root(INCR_NOTE_SCRIPT_CODE, client.source_manager())?; @@ -535,10 +524,7 @@ pub async fn test_recall_note_before_ntx_consumes_it(client_config: ClientConfig // ordinary public account: the node rejects user transactions against network accounts. let native_account = deploy_counter_contract(&mut client).await?; - let wallet = - insert_new_wallet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await? - .0; + let wallet = client.insert_wallet(AccountType::Public).await?; let network_note = get_network_note( wallet.id(), @@ -571,7 +557,7 @@ pub async fn test_recall_note_before_ntx_consumes_it(client_config: ClientConfig client.submit_proven_transaction(consume_proven, &consume_result).await?; client.apply_transaction(&consume_result, consume_submission_height).await?; - wait_for_blocks(&mut client, 2).await; + client.wait_for_blocks(2).await?; // The network account should have original value let network_counter = client @@ -597,16 +583,14 @@ pub async fn test_recall_note_before_ntx_consumes_it(client_config: ClientConfig pub async fn test_note_reader_finds_note_consumed_by_ntx( client_config: ClientConfig, ) -> Result<()> { - let (mut client, keystore) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; client.sync_state().await?; let incr_note_root = note_script_root(INCR_NOTE_SCRIPT_CODE, client.source_manager())?; let network_account = deploy_network_counter_contract(&mut client, &[incr_note_root]).await?; let network_account_id = network_account.id(); - let (sender_account, ..) = - insert_new_wallet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let sender_account = client.insert_wallet(AccountType::Public).await?; let network_note = get_network_note( sender_account.id(), @@ -620,7 +604,7 @@ pub async fn test_note_reader_finds_note_consumed_by_ntx( let tx_request = TransactionRequestBuilder::new().own_output_notes(vec![network_note]).build()?; - execute_tx_and_sync(&mut client, sender_account.id(), tx_request).await?; + client.execute_tx_and_sync(sender_account.id(), tx_request).await?; // Wait for the network account to consume the note (check counter increment). let expected_counter = Word::from([Felt::from(2u32), ZERO, ZERO, ZERO]); @@ -635,7 +619,7 @@ pub async fn test_note_reader_finds_note_consumed_by_ntx( if account_details.storage().get_item(&COUNTER_SLOT_NAME)? == expected_counter { break; } - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; } client.sync_state().await?; @@ -668,16 +652,14 @@ pub async fn test_note_reader_finds_note_consumed_by_ntx( /// consumer rather than attributed to the network account. The test therefore asserts the note /// reaches a consumed state, not the consumer identity. pub async fn test_network_note_consumed_by_ntx(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.into_client().await?; + let mut client = client_config.into_client().await?; client.sync_state().await?; let incr_note_root = note_script_root(INCR_NOTE_SCRIPT_CODE, client.source_manager())?; let network_account = deploy_network_counter_contract(&mut client, &[incr_note_root]).await?; let network_account_id = network_account.id(); - let (sender_account, ..) = - insert_new_wallet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let sender_account = client.insert_wallet(AccountType::Public).await?; let network_note = get_network_note( sender_account.id(), @@ -691,7 +673,7 @@ pub async fn test_network_note_consumed_by_ntx(client_config: ClientConfig) -> R let tx_request = TransactionRequestBuilder::new().own_output_notes(vec![network_note]).build()?; - execute_tx_and_sync(&mut client, sender_account.id(), tx_request).await?; + client.execute_tx_and_sync(sender_account.id(), tx_request).await?; // Wait for the network account to consume the note (check counter increment). let expected_counter = Word::from([Felt::from(2u32), ZERO, ZERO, ZERO]); @@ -706,7 +688,7 @@ pub async fn test_network_note_consumed_by_ntx(client_config: ClientConfig) -> R if account_details.storage().get_item(&COUNTER_SLOT_NAME)? == expected_counter { break; } - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; } // The note is consumed via same-batch erasure, so the consumer is not derivable and the note is @@ -723,7 +705,7 @@ pub async fn test_network_note_consumed_by_ntx(client_config: ClientConfig) -> R consumed = true; break; } - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; } assert!( @@ -737,15 +719,11 @@ pub async fn test_network_note_consumed_by_ntx(client_config: ClientConfig) -> R /// End-to-end integration test for the standard MINT note -> network faucet -> public P2ID output /// note flow. pub async fn test_ntx_mint_produces_public_p2id(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; - let (alice, ..) = - insert_new_wallet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; - let (bob, ..) = - insert_new_wallet(&mut client_2, AccountType::Public, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + let alice = client.insert_wallet(AccountType::Public).await?; + let bob = client_2.insert_wallet(AccountType::Public).await?; let faucet = deploy_network_fungible_faucet(&mut client, alice.id()).await?; @@ -780,7 +758,7 @@ pub async fn test_ntx_mint_produces_public_p2id(client_config: ClientConfig) -> .into(); let mint_tx = TransactionRequestBuilder::new().own_output_notes(vec![mint_note]).build()?; - execute_tx_and_sync(&mut client, alice.id(), mint_tx).await?; + client.execute_tx_and_sync(alice.id(), mint_tx).await?; ensure!( wait_for_committed_note(&mut client, &mut client_2, expected_output_commitment, 15).await?, @@ -818,15 +796,11 @@ pub async fn test_ntx_mint_produces_public_p2id(client_config: ClientConfig) -> pub async fn test_ntx_mint_produces_public_note_with_non_standard_script( client_config: ClientConfig, ) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; - let (alice, ..) = - insert_new_wallet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await?; - let (bob, ..) = - insert_new_wallet(&mut client_2, AccountType::Public, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + let alice = client.insert_wallet(AccountType::Public).await?; + let bob = client_2.insert_wallet(AccountType::Public).await?; let faucet = deploy_network_fungible_faucet(&mut client, alice.id()).await?; @@ -857,13 +831,13 @@ pub async fn test_ntx_mint_produces_public_note_with_non_standard_script( .custom_script(noop_script) .expected_ntx_scripts(vec![registered_script]) .build()?; - execute_tx_and_sync(&mut client, alice.id(), register_tx).await?; - wait_for_blocks(&mut client, 1).await; + client.execute_tx_and_sync(alice.id(), register_tx).await?; + client.wait_for_blocks(1).await?; let registered_mint_tx = TransactionRequestBuilder::new() .own_output_notes(vec![registered_mint]) .build()?; - execute_tx_and_sync(&mut client, alice.id(), registered_mint_tx).await?; + client.execute_tx_and_sync(alice.id(), registered_mint_tx).await?; // The NTX builder resolves the registered script and emits the public note. Observe it // `Committed` on Bob's client. @@ -880,10 +854,11 @@ pub async fn test_ntx_mint_produces_public_note_with_non_standard_script( .pop() .context("expected the committed public note to be present on Bob's client")? .try_into()?; - let consume_tx_id = consume_notes(&mut client_2, bob.id(), &[note]).await; - wait_for_tx(&mut client_2, consume_tx_id).await?; + let consume_tx_id = client_2.consume_notes(bob.id(), &[note]).await?; + client_2.wait_for_tx(consume_tx_id).await?; - assert_account_has_single_asset(&client_2, bob.id(), faucet.id(), amount.as_canonical_u64()) + client_2 + .assert_account_has_single_asset(bob.id(), faucet.id(), amount.as_canonical_u64()) .await; // Unregistered case: mint a note whose public output uses a different non-standard script that @@ -902,7 +877,7 @@ pub async fn test_ntx_mint_produces_public_note_with_non_standard_script( let unregistered_mint_tx = TransactionRequestBuilder::new() .own_output_notes(vec![unregistered_mint]) .build()?; - execute_tx_and_sync(&mut client, alice.id(), unregistered_mint_tx).await?; + client.execute_tx_and_sync(alice.id(), unregistered_mint_tx).await?; ensure!( !wait_for_committed_note(&mut client, &mut client_2, unregistered_output_id, 10).await?, @@ -980,8 +955,8 @@ pub(crate) fn get_network_note_with_script( pub async fn test_watch_network_account(client_config: ClientConfig) -> Result<()> { const BUMP_NOTE_NUMBER: u64 = 3; - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, _keystore_2) = client_config.clone().into_client().await?; + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; client_1.sync_state().await?; let incr_note_root = note_script_root(INCR_NOTE_SCRIPT_CODE, client_1.source_manager())?; @@ -1019,9 +994,7 @@ pub async fn test_watch_network_account(client_config: ClientConfig) -> Result<( // client_1 emits BUMP_NOTE_NUMBER network notes targeted at the counter; the node will consume // them in subsequent blocks and bump the counter to BUMP_NOTE_NUMBER. - let (native_account, ..) = - insert_new_wallet(&mut client_1, AccountType::Public, &keystore_1, RPO_FALCON_SCHEME_ID) - .await?; + let native_account = client_1.insert_wallet(AccountType::Public).await?; let source_manager = client_1.source_manager(); let mut network_notes = vec![]; @@ -1036,13 +1009,13 @@ pub async fn test_watch_network_account(client_config: ClientConfig) -> Result<( } let tx_request = TransactionRequestBuilder::new().own_output_notes(network_notes).build()?; - execute_tx_and_sync(&mut client_1, native_account.id(), tx_request).await?; + client_1.execute_tx_and_sync(native_account.id(), tx_request).await?; // Poll the watched client until it observes the bumped counter. let expected_counter = Word::from([Felt::new_unchecked(BUMP_NOTE_NUMBER), ZERO, ZERO, ZERO]); let mut observed = false; for _ in 0..10 { - wait_for_blocks(&mut client_1, 1).await; + client_1.wait_for_blocks(1).await?; client_2.sync_state().await?; let counter = client_2 .account_reader(network_account_id) diff --git a/bin/integration-tests/src/tests/note_tags.rs b/bin/integration-tests/src/tests/note_tags.rs index 88feb6a29f..4759f94b20 100644 --- a/bin/integration-tests/src/tests/note_tags.rs +++ b/bin/integration-tests/src/tests/note_tags.rs @@ -1,7 +1,6 @@ use anyhow::{Context, Result}; use miden_client::account::AccountType; use miden_client::asset::FungibleAsset; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::note::{NoteFile, NoteSyncHint, NoteType}; use miden_client::store::{InputNoteRecord, NoteFilter}; use miden_client::sync::NoteTagSource; @@ -31,21 +30,13 @@ async fn assert_no_note_sourced_tags(client: &TestClient, context: &str) -> Resu pub async fn test_output_notes_do_not_register_tags(client_config: ClientConfig) -> Result<()> { // Client 1 runs the faucet; client 2 tracks the recipient wallet, so from client 1's // perspective the minted note goes to an external account. - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().with_note_transport_endpoint(None).into_client().await?; - wait_for_node(&mut client_2).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Private, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (basic_wallet, ..) = - insert_new_wallet(&mut client_2, AccountType::Private, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + client_2.wait_for_node().await; + + let faucet_account = client_1.insert_faucet(AccountType::Private).await?; + let basic_wallet = client_2.insert_wallet(AccountType::Private).await?; client_1.sync_state().await?; client_2.sync_state().await?; @@ -65,7 +56,7 @@ pub async fn test_output_notes_do_not_register_tags(client_config: ClientConfig) // Applying the transaction must not have registered a tag for the output note. assert_no_note_sourced_tags(&client_1, "after applying a mint to an external account").await?; - wait_for_tx(&mut client_1, tx_id).await?; + client_1.wait_for_tx(tx_id).await?; // The output note must be committed with its inclusion proof, obtained purely via // account-matched transaction sync. @@ -91,10 +82,12 @@ pub async fn test_output_notes_do_not_register_tags(client_config: ClientConfig) // an inclusion proof, so committedness must be asserted explicitly. assert!(received_record.is_committed(), "received note should be committed"); let received_note: InputNote = received_record.try_into()?; - let tx_id = - consume_notes(&mut client_2, basic_wallet.id(), &[received_note.note().clone()]).await; - wait_for_tx(&mut client_2, tx_id).await?; - assert_account_has_single_asset(&client_2, basic_wallet.id(), faucet_account.id(), MINT_AMOUNT) + let tx_id = client_2 + .consume_notes(basic_wallet.id(), &[received_note.note().clone()]) + .await?; + client_2.wait_for_tx(tx_id).await?; + client_2 + .assert_account_has_single_asset(basic_wallet.id(), faucet_account.id(), MINT_AMOUNT) .await; Ok(()) @@ -103,35 +96,23 @@ pub async fn test_output_notes_do_not_register_tags(client_config: ClientConfig) /// Expected input notes register exactly one tag and it is cleaned up on commit — covered for a /// self-directed transfer and for an expected note imported by details. pub async fn test_input_note_tag_lifecycle(client_config: ClientConfig) -> Result<()> { - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().with_note_transport_endpoint(None).into_client().await?; - wait_for_node(&mut client_1).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Private, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (wallet_a, ..) = - insert_new_wallet(&mut client_1, AccountType::Private, &keystore_1, RPO_FALCON_SCHEME_ID) - .await?; - let (wallet_b, ..) = - insert_new_wallet(&mut client_1, AccountType::Private, &keystore_1, RPO_FALCON_SCHEME_ID) - .await?; - let (wallet_c, ..) = - insert_new_wallet(&mut client_2, AccountType::Private, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + client_1.wait_for_node().await; + + let faucet_account = client_1.insert_faucet(AccountType::Private).await?; + let wallet_a = client_1.insert_wallet(AccountType::Private).await?; + let wallet_b = client_1.insert_wallet(AccountType::Private).await?; + let wallet_c = client_2.insert_wallet(AccountType::Private).await?; client_1.sync_state().await?; client_2.sync_state().await?; // Fund wallet A. - let tx_id = - mint_and_consume(&mut client_1, wallet_a.id(), faucet_account.id(), NoteType::Private) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(wallet_a.id(), faucet_account.id(), NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; // Self-directed transfer: sender and recipient are both tracked by client 1, so the note is // registered as an expected input note with a tag. @@ -161,7 +142,7 @@ pub async fn test_input_note_tag_lifecycle(client_config: ClientConfig) -> Resul "a self-directed expected input note should register exactly one tag" ); - wait_for_tx(&mut client_1, tx_id).await?; + client_1.wait_for_tx(tx_id).await?; // Once the note commits, the tag is cleaned up and both note records carry their state. assert_no_note_sourced_tags(&client_1, "after the self-directed note committed").await?; @@ -178,8 +159,8 @@ pub async fn test_input_note_tag_lifecycle(client_config: ClientConfig) -> Resul .context("self-directed note should be tracked as an input note")?; assert!(received_record.is_committed(), "self-directed input note should be committed"); let received_note: InputNote = received_record.try_into()?; - let tx_id = consume_notes(&mut client_1, wallet_b.id(), &[received_note.note().clone()]).await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1.consume_notes(wallet_b.id(), &[received_note.note().clone()]).await?; + client_1.wait_for_tx(tx_id).await?; // Importing an expected note by details (before it is committed on chain) registers a tag and // cleans it up once the note commits. @@ -215,7 +196,7 @@ pub async fn test_input_note_tag_lifecycle(client_config: ClientConfig) -> Resul ); let tx_id = Box::pin(client_1.submit_new_transaction(faucet_account.id(), tx_request)).await?; - wait_for_tx(&mut client_1, tx_id).await?; + client_1.wait_for_tx(tx_id).await?; client_2.sync_state().await?; assert_no_note_sourced_tags(&client_2, "after the imported note committed").await?; @@ -225,8 +206,8 @@ pub async fn test_input_note_tag_lifecycle(client_config: ClientConfig) -> Resul .context("imported note should be committed for the recipient")?; assert!(received_record.is_committed(), "imported note should be committed"); let received_note: InputNote = received_record.try_into()?; - let tx_id = consume_notes(&mut client_2, wallet_c.id(), &[received_note.note().clone()]).await; - wait_for_tx(&mut client_2, tx_id).await?; + let tx_id = client_2.consume_notes(wallet_c.id(), &[received_note.note().clone()]).await?; + client_2.wait_for_tx(tx_id).await?; Ok(()) } diff --git a/bin/integration-tests/src/tests/onchain.rs b/bin/integration-tests/src/tests/onchain.rs index d04bdd4b42..6533db61c7 100644 --- a/bin/integration-tests/src/tests/onchain.rs +++ b/bin/integration-tests/src/tests/onchain.rs @@ -3,7 +3,6 @@ use std::collections::BTreeMap; use anyhow::{Context, Result}; use miden_client::account::{AccountType, build_wallet_id}; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::keystore::Keystore; use miden_client::note::standards::NoteSyncHint; use miden_client::note::{ @@ -37,30 +36,20 @@ use crate::ClientConfig; pub async fn test_onchain_notes_flow(client_config: ClientConfig) -> Result<()> { // Client 1 is an private faucet which will mint an onchain note for client 2 - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; + let mut client_1 = client_config.clone().into_client().await?; // Client 2 is an private account which will consume the note that it will sync from the node - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; // Client 3 will be transferred part of the assets by client 2's account - let (mut client_3, keystore_3) = client_config.clone().into_client().await?; - wait_for_node(&mut client_3).await; + let mut client_3 = client_config.clone().into_client().await?; + client_3.wait_for_node().await; // Create faucet account - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Private, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let faucet_account = client_1.insert_faucet(AccountType::Private).await?; // Create regular accounts - let (basic_wallet_1, ..) = - insert_new_wallet(&mut client_2, AccountType::Private, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + let basic_wallet_1 = client_2.insert_wallet(AccountType::Private).await?; // Create regular accounts - let (basic_wallet_2, ..) = - insert_new_wallet(&mut client_3, AccountType::Private, &keystore_3, RPO_FALCON_SCHEME_ID) - .await?; + let basic_wallet_2 = client_3.insert_wallet(AccountType::Private).await?; client_1.sync_state().await?; client_2.sync_state().await?; @@ -75,7 +64,7 @@ pub async fn test_onchain_notes_flow(client_config: ClientConfig) -> Result<()> .pop() .with_context(|| "no expected output notes found in onchain transaction from faucet")? .clone(); - execute_tx_and_sync(&mut client_1, faucet_account.id(), tx_request).await?; + client_1.execute_tx_and_sync(faucet_account.id(), tx_request).await?; // Client 2's account should receive the note here: client_2.sync_state().await?; @@ -94,16 +83,13 @@ pub async fn test_onchain_notes_flow(client_config: ClientConfig) -> Result<()> // assert_eq!(received_note.note(), ¬e); // consume the note - let tx_id = - consume_notes(&mut client_2, basic_wallet_1.id(), &[received_note.note().clone()]).await; - wait_for_tx(&mut client_2, tx_id).await?; - assert_account_has_single_asset( - &client_2, - basic_wallet_1.id(), - faucet_account.id(), - MINT_AMOUNT, - ) - .await; + let tx_id = client_2 + .consume_notes(basic_wallet_1.id(), &[received_note.note().clone()]) + .await?; + client_2.wait_for_tx(tx_id).await?; + client_2 + .assert_account_has_single_asset(basic_wallet_1.id(), faucet_account.id(), MINT_AMOUNT) + .await; let p2id_asset = FungibleAsset::new(faucet_account.id(), TRANSFER_AMOUNT)?; let tx_request = TransactionRequestBuilder::new().build_pay_to_id( @@ -115,7 +101,7 @@ pub async fn test_onchain_notes_flow(client_config: ClientConfig) -> Result<()> NoteType::Public, client_2.rng(), )?; - execute_tx_and_sync(&mut client_2, basic_wallet_1.id(), tx_request).await?; + client_2.execute_tx_and_sync(basic_wallet_1.id(), tx_request).await?; // Create a note for client 3 that is already consumed before syncing let tx_request = TransactionRequestBuilder::new().build_pay_to_id( @@ -133,11 +119,11 @@ pub async fn test_onchain_notes_flow(client_config: ClientConfig) -> Result<()> .pop() .with_context(|| "no expected output notes found in onchain transaction from basic wallet")? .clone(); - execute_tx_and_sync(&mut client_2, basic_wallet_1.id(), tx_request).await?; + client_2.execute_tx_and_sync(basic_wallet_1.id(), tx_request).await?; let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![reclaimed_note.clone()])?; - execute_tx_and_sync(&mut client_2, basic_wallet_1.id(), tx_request).await?; + client_2.execute_tx_and_sync(basic_wallet_1.id(), tx_request).await?; // sync client 3 (basic account 2) client_3.sync_state().await?; @@ -160,52 +146,40 @@ pub async fn test_onchain_notes_flow(client_config: ClientConfig) -> Result<()> .clone() .try_into()?; - let tx_id = consume_notes(&mut client_3, basic_wallet_2.id(), &[note]).await; - wait_for_tx(&mut client_3, tx_id).await?; - assert_account_has_single_asset( - &client_3, - basic_wallet_2.id(), - faucet_account.id(), - TRANSFER_AMOUNT, - ) - .await; + let tx_id = client_3.consume_notes(basic_wallet_2.id(), &[note]).await?; + client_3.wait_for_tx(tx_id).await?; + client_3 + .assert_account_has_single_asset(basic_wallet_2.id(), faucet_account.id(), TRANSFER_AMOUNT) + .await; Ok(()) } pub async fn test_onchain_accounts(client_config: ClientConfig) -> Result<()> { - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; - wait_for_node(&mut client_2).await; - - let (faucet_account_header, secret_key) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Public, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (first_regular_account, ..) = - insert_new_wallet(&mut client_1, AccountType::Private, &keystore_1, RPO_FALCON_SCHEME_ID) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; + client_2.wait_for_node().await; - let (second_client_first_regular_account, ..) = - insert_new_wallet(&mut client_2, AccountType::Private, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + let (faucet_account_header, secret_key) = + client_1.insert_account(AccountSetup::faucet(AccountType::Public)).await?; + + let first_regular_account = client_1.insert_wallet(AccountType::Private).await?; + + let second_client_first_regular_account = client_2.insert_wallet(AccountType::Private).await?; let target_account_id = first_regular_account.id(); let second_client_target_account_id = second_client_first_regular_account.id(); let faucet_account_id = faucet_account_header.id(); - keystore_2.add_key(&secret_key, faucet_account_id).await?; + client_2.keystore().add_key(&secret_key, faucet_account_id).await?; client_2.add_account(&faucet_account_header, false).await?; // First Mint necessary token info!(account_id = %target_account_id, faucet_id = %faucet_account_id, "First client minting note"); client_1.sync_state().await?; - let (tx_id, note) = - mint_note(&mut client_1, target_account_id, faucet_account_id, NoteType::Private).await; - wait_for_tx(&mut client_1, tx_id).await?; + let (tx_id, note) = client_1 + .mint_note(target_account_id, faucet_account_id, NoteType::Private) + .await?; + client_1.wait_for_tx(tx_id).await?; // Update the state in the other client and ensure the onchain faucet commitment is consistent // between clients @@ -226,34 +200,32 @@ pub async fn test_onchain_accounts(client_config: ClientConfig) -> Result<()> { // Now use the faucet in the second client to mint to its own account info!(account_id = %second_client_target_account_id, faucet_id = %faucet_account_id, "Second client minting note"); - let (tx_id, second_client_note) = mint_note( - &mut client_2, - second_client_target_account_id, - faucet_account_id, - NoteType::Private, - ) - .await; - wait_for_tx(&mut client_2, tx_id).await?; + let (tx_id, second_client_note) = client_2 + .mint_note(second_client_target_account_id, faucet_account_id, NoteType::Private) + .await?; + client_2.wait_for_tx(tx_id).await?; // Update the state in the other client and ensure the onchain faucet commitment is consistent // between clients client_1.sync_state().await?; info!(account_id = %target_account_id, "Consuming note on first client"); - let tx_id = consume_notes(&mut client_1, target_account_id, &[note]).await; - wait_for_tx(&mut client_1, tx_id).await?; - assert_account_has_single_asset(&client_1, target_account_id, faucet_account_id, MINT_AMOUNT) + let tx_id = client_1.consume_notes(target_account_id, &[note]).await?; + client_1.wait_for_tx(tx_id).await?; + client_1 + .assert_account_has_single_asset(target_account_id, faucet_account_id, MINT_AMOUNT) + .await; + let tx_id = client_2 + .consume_notes(second_client_target_account_id, &[second_client_note]) + .await?; + client_2.wait_for_tx(tx_id).await?; + client_2 + .assert_account_has_single_asset( + second_client_target_account_id, + faucet_account_id, + MINT_AMOUNT, + ) .await; - let tx_id = - consume_notes(&mut client_2, second_client_target_account_id, &[second_client_note]).await; - wait_for_tx(&mut client_2, tx_id).await?; - assert_account_has_single_asset( - &client_2, - second_client_target_account_id, - faucet_account_id, - MINT_AMOUNT, - ) - .await; let (client_1_faucet, _) = client_1 @@ -294,7 +266,7 @@ pub async fn test_onchain_accounts(client_config: ClientConfig) -> Result<()> { NoteType::Public, client_1.rng(), )?; - execute_tx_and_sync(&mut client_1, from_account_id, tx_request).await?; + client_1.execute_tx_and_sync(from_account_id, tx_request).await?; // sync on second client until we receive the note info!("Syncing state on second client"); @@ -309,7 +281,7 @@ pub async fn test_onchain_accounts(client_config: ClientConfig) -> Result<()> { info!(note_id = %note_id, account_id = %to_account_id, "Consuming note on second client"); let tx_request = TransactionRequestBuilder::new() .build_consume_notes(vec![notes[0].clone().try_into().unwrap()])?; - execute_tx_and_sync(&mut client_2, to_account_id, tx_request).await?; + client_2.execute_tx_and_sync(to_account_id, tx_request).await?; // sync on first client info!("Syncing state on first client"); @@ -348,50 +320,40 @@ pub async fn test_onchain_accounts(client_config: ClientConfig) -> Result<()> { } pub async fn test_import_account_by_id(client_config: ClientConfig) -> Result<()> { - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; - wait_for_node(&mut client_1).await; + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; + client_1.wait_for_node().await; let mut user_seed = [0u8; 32]; client_1.rng().fill_bytes(&mut user_seed); - let (faucet_account_header, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Public, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (first_regular_account, secret_key) = insert_new_wallet_with_seed( - &mut client_1, - AccountType::Public, - &keystore_1, - user_seed, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let faucet_account_header = client_1.insert_faucet(AccountType::Public).await?; + + let (first_regular_account, secret_key) = client_1 + .insert_account(AccountSetup::wallet(AccountType::Public).seed(user_seed)) + .await?; let target_account_id = first_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First mint and consume in the first client - let tx_id = - mint_and_consume(&mut client_1, target_account_id, faucet_account_id, NoteType::Public) - .await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1 + .mint_and_consume(target_account_id, faucet_account_id, NoteType::Public) + .await?; + client_1.wait_for_tx(tx_id).await?; // Mint a note for the second client - let (tx_id, note) = - mint_note(&mut client_1, target_account_id, faucet_account_id, NoteType::Public).await; - wait_for_tx(&mut client_1, tx_id).await?; + let (tx_id, note) = client_1 + .mint_note(target_account_id, faucet_account_id, NoteType::Public) + .await?; + client_1.wait_for_tx(tx_id).await?; // Import the public account by id let built_wallet_id = build_wallet_id(user_seed, &secret_key.public_key(), AccountType::Public)?; assert_eq!(built_wallet_id, first_regular_account.id()); client_2.import_account_by_id(built_wallet_id).await?; - keystore_2.add_key(&secret_key, built_wallet_id).await?; + client_2.keystore().add_key(&secret_key, built_wallet_id).await?; let original_commitment = client_1 .account_reader(first_regular_account.id()) @@ -412,15 +374,11 @@ pub async fn test_import_account_by_id(client_config: ClientConfig) -> Result<() // Now use the wallet in the second client to consume the generated note info!(account_id = %target_account_id, "Second client consuming note"); client_2.sync_state().await?; - let tx_id = consume_notes(&mut client_2, target_account_id, &[note]).await; - wait_for_tx(&mut client_2, tx_id).await?; - assert_account_has_single_asset( - &client_2, - target_account_id, - faucet_account_id, - MINT_AMOUNT * 2, - ) - .await; + let tx_id = client_2.consume_notes(target_account_id, &[note]).await?; + client_2.wait_for_tx(tx_id).await?; + client_2 + .assert_account_has_single_asset(target_account_id, faucet_account_id, MINT_AMOUNT * 2) + .await; Ok(()) } @@ -431,26 +389,18 @@ pub async fn test_import_account_by_id(client_config: ClientConfig) -> Result<() /// new account commitment matching `client_1`, and (b) no output note record for the account's /// txs (watched accounts track on-chain state, not their note outputs). pub async fn test_import_watched_account_by_id(client_config: ClientConfig) -> Result<()> { - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, _keystore_2) = client_config.clone().into_client().await?; - wait_for_node(&mut client_1).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Public, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (wallet, _) = - insert_new_wallet(&mut client_1, AccountType::Public, &keystore_1, RPO_FALCON_SCHEME_ID) - .await?; + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; + client_1.wait_for_node().await; + + let faucet_account = client_1.insert_faucet(AccountType::Public).await?; + let wallet = client_1.insert_wallet(AccountType::Public).await?; let wallet_id = wallet.id(); let faucet_id = faucet_account.id(); // Fill the wallet with an asset so the watched account has non-trivial state. - let tx_id = mint_and_consume(&mut client_1, wallet_id, faucet_id, NoteType::Public).await; - wait_for_tx(&mut client_1, tx_id).await?; + let tx_id = client_1.mint_and_consume(wallet_id, faucet_id, NoteType::Public).await?; + client_1.wait_for_tx(tx_id).await?; // client_2 starts watching the wallet. client_2.import_watched_account_by_id(wallet_id).await?; @@ -480,11 +430,10 @@ pub async fn test_import_watched_account_by_id(client_config: ClientConfig) -> R // client_1 mints another note to the wallet and consumes it, giving client_2's watched view // fresh activity to track. No per-account tag is registered, so client_2 watches the account // only through its on-chain state. - let (tx_id, mint_note) = mint_note(&mut client_1, wallet_id, faucet_id, NoteType::Public).await; - wait_for_tx(&mut client_1, tx_id).await?; - let consume_tx_id = - consume_notes(&mut client_1, wallet_id, std::slice::from_ref(&mint_note)).await; - wait_for_tx(&mut client_1, consume_tx_id).await?; + let (tx_id, mint_note) = client_1.mint_note(wallet_id, faucet_id, NoteType::Public).await?; + client_1.wait_for_tx(tx_id).await?; + let consume_tx_id = client_1.consume_notes(wallet_id, std::slice::from_ref(&mint_note)).await?; + client_1.wait_for_tx(consume_tx_id).await?; client_2.sync_state().await?; @@ -537,7 +486,7 @@ pub async fn test_import_watched_account_by_id(client_config: ClientConfig) -> R } pub async fn test_incorrect_genesis(client_config: ClientConfig) -> Result<()> { - let (mut client, _) = client_config.into_unsynced_client().await?; + let mut client = client_config.into_unsynced_client().await?; // Set an incorrect genesis commitment client.test_rpc_api().set_genesis_commitment(EMPTY_WORD).await?; @@ -560,39 +509,31 @@ pub async fn test_incorrect_genesis(client_config: ClientConfig) -> Result<()> { /// land in the same block. After syncing, it verifies that `InputNoteReader` returns the notes in /// submission order. pub async fn test_consumed_note_ordering(client_config: ClientConfig) -> Result<()> { - let (mut client, keystore) = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &keystore, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (wallet_account, ..) = - insert_new_wallet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await?; + let mut client = client_config.clone().into_client().await?; + client.wait_for_node().await; + + let faucet_account = client.insert_faucet(AccountType::Private).await?; + + let wallet_account = client.insert_wallet(AccountType::Private).await?; client.sync_state().await?; // Pre-batch: put the wallet on-chain so the wallet's first batch-tx delta is partial, not // full-state — the batch apply path rejects full-state deltas. - let bootstrap_tx_id = - mint_and_consume(&mut client, wallet_account.id(), faucet_account.id(), NoteType::Private) - .await; - wait_for_tx(&mut client, bootstrap_tx_id).await?; + let bootstrap_tx_id = client + .mint_and_consume(wallet_account.id(), faucet_account.id(), NoteType::Private) + .await?; + client.wait_for_tx(bootstrap_tx_id).await?; client.sync_state().await?; // Mint 3 notes, each in a separate transaction. let mut minted_notes = Vec::new(); for i in 0..3 { - let (tx_id, note) = - mint_note(&mut client, wallet_account.id(), faucet_account.id(), NoteType::Private) - .await; + let (tx_id, note) = client + .mint_note(wallet_account.id(), faucet_account.id(), NoteType::Private) + .await?; info!(tx_id = %tx_id, note_id = %note.id(), index = i, "Minted note"); - wait_for_tx(&mut client, tx_id).await?; + client.wait_for_tx(tx_id).await?; minted_notes.push(note); } client.sync_state().await?; @@ -637,7 +578,7 @@ pub async fn test_consumed_note_ordering(client_config: ClientConfig) -> Result< break; } - wait_for_blocks(&mut client, 1).await; + client.wait_for_blocks(1).await?; } let batch_block = batch_block.with_context(|| "3 consume txs were not committed in the same block")?; @@ -722,38 +663,29 @@ pub async fn test_consumed_note_ordering(client_config: ClientConfig) -> Result< pub async fn test_watched_account_recovers_consumed_public_note( client_config: ClientConfig, ) -> Result<()> { - let (mut client_a, keystore_a) = client_config.clone().into_client().await?; - let (mut client_b, _keystore_b) = client_config.clone().into_client().await?; - wait_for_node(&mut client_a).await; - - let (faucet, _) = insert_new_fungible_faucet( - &mut client_a, - AccountType::Public, - &keystore_a, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (consumer, ..) = - insert_new_wallet(&mut client_a, AccountType::Public, &keystore_a, RPO_FALCON_SCHEME_ID) - .await?; + let mut client_a = client_config.clone().into_client().await?; + let mut client_b = client_config.clone().into_client().await?; + client_a.wait_for_node().await; + + let faucet = client_a.insert_faucet(AccountType::Public).await?; + let consumer = client_a.insert_wallet(AccountType::Public).await?; let consumer_id = consumer.id(); let faucet_id = faucet.id(); // Put the consumer on-chain, then have B watch it. No per-account note tag is registered, so B // can only learn about consumed notes from the consumer's transactions. - let bootstrap_tx = - mint_and_consume(&mut client_a, consumer_id, faucet_id, NoteType::Public).await; - wait_for_tx(&mut client_a, bootstrap_tx).await?; + let bootstrap_tx = client_a.mint_and_consume(consumer_id, faucet_id, NoteType::Public).await?; + client_a.wait_for_tx(bootstrap_tx).await?; client_a.sync_state().await?; client_b.import_watched_account_by_id(consumer_id).await?; client_b.sync_state().await?; // A mints a public note to the consumer, lets it commit, then consumes it (authenticated). B // never tracked this note's tag, so the only trace it can get is the consuming transaction. - let (mint_tx, note) = mint_note(&mut client_a, consumer_id, faucet_id, NoteType::Public).await; - wait_for_tx(&mut client_a, mint_tx).await?; - let consume_tx = consume_notes(&mut client_a, consumer_id, std::slice::from_ref(¬e)).await; - wait_for_tx(&mut client_a, consume_tx).await?; + let (mint_tx, note) = client_a.mint_note(consumer_id, faucet_id, NoteType::Public).await?; + client_a.wait_for_tx(mint_tx).await?; + let consume_tx = client_a.consume_notes(consumer_id, std::slice::from_ref(¬e)).await?; + client_a.wait_for_tx(consume_tx).await?; // B syncs until its reader surfaces the consumed note. let mut found = None; @@ -769,7 +701,7 @@ pub async fn test_watched_account_recovers_consumed_public_note( if found.is_some() { break; } - wait_for_blocks(&mut client_b, 1).await; + client_b.wait_for_blocks(1).await?; } let found = found.context( @@ -793,23 +725,15 @@ pub async fn test_watched_account_recovers_consumed_public_note( /// private note's attachment content. /// 4. Client 2 consumes both notes. pub async fn test_sync_note_with_attachment(client_config: ClientConfig) -> Result<()> { - let (mut client_1, keystore_1) = client_config.clone().into_client().await?; - let (mut client_2, keystore_2) = client_config.clone().into_client().await?; - wait_for_node(&mut client_1).await; + let mut client_1 = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; + client_1.wait_for_node().await; // Create faucet in client 1 - let (faucet_account, _) = insert_new_fungible_faucet( - &mut client_1, - AccountType::Private, - &keystore_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let faucet_account = client_1.insert_faucet(AccountType::Private).await?; // Create wallet in client 2 - let (wallet, ..) = - insert_new_wallet(&mut client_2, AccountType::Private, &keystore_2, RPO_FALCON_SCHEME_ID) - .await?; + let wallet = client_2.insert_wallet(AccountType::Private).await?; client_1.sync_state().await?; client_2.sync_state().await?; @@ -848,7 +772,7 @@ pub async fn test_sync_note_with_attachment(client_config: ClientConfig) -> Resu let tx_request = TransactionRequestBuilder::new() .own_output_notes(vec![public_note.clone(), private_note.clone()]) .build()?; - execute_tx_and_sync(&mut client_1, faucet_account.id(), tx_request).await?; + client_1.execute_tx_and_sync(faucet_account.id(), tx_request).await?; // A private note's details never appear on-chain, so client 2 must receive the details. client_2.add_note_tag(private_note.metadata().tag()).await?; @@ -888,10 +812,11 @@ pub async fn test_sync_note_with_attachment(client_config: ClientConfig) -> Resu // Consume both notes — this fails if either note's attachments weren't resolved. info!("Consuming both notes with attachments in client 2"); - let tx_id = consume_notes(&mut client_2, wallet.id(), &received_notes).await; - wait_for_tx(&mut client_2, tx_id).await?; + let tx_id = client_2.consume_notes(wallet.id(), &received_notes).await?; + client_2.wait_for_tx(tx_id).await?; - assert_account_has_single_asset(&client_2, wallet.id(), faucet_account.id(), MINT_AMOUNT * 2) + client_2 + .assert_account_has_single_asset(wallet.id(), faucet_account.id(), MINT_AMOUNT * 2) .await; Ok(()) diff --git a/bin/integration-tests/src/tests/pass_through.rs b/bin/integration-tests/src/tests/pass_through.rs index 1bb3ae32bc..8a35920592 100644 --- a/bin/integration-tests/src/tests/pass_through.rs +++ b/bin/integration-tests/src/tests/pass_through.rs @@ -9,7 +9,7 @@ use miden_client::account::{ }; use miden_client::assembly::CodeBuilder; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::{AuthSchemeId, NoAuth, TransactionAuthenticator}; +use miden_client::auth::{NoAuth, TransactionAuthenticator}; use miden_client::block::BlockNumber; use miden_client::crypto::FeltRng; use miden_client::note::{ @@ -26,7 +26,6 @@ use miden_client::note::{ PartialNoteMetadata, }; use miden_client::store::{InputNoteState, TransactionFilter}; -use miden_client::testing::common::*; use miden_client::transaction::TransactionRequestBuilder; use miden_client::{Client, ClientRng, Word}; use miden_protocol::MAX_TX_EXECUTION_CYCLES; @@ -41,48 +40,31 @@ use crate::ClientConfig; pub async fn test_pass_through(client_config: ClientConfig) -> Result<()> { const ASSET_AMOUNT: u64 = 1; - let (mut client, authenticator_1) = client_config.clone().into_client().await?; + let mut client = client_config.clone().into_client().await?; // Workaround to show that importing the note into another client works - let (mut client_2, authenticator_2) = client_config.clone().into_client().await?; + let mut client_2 = client_config.clone().into_client().await?; - wait_for_node(&mut client).await; + client.wait_for_node().await; client.sync_state().await?; client_2.sync_state().await?; // Create Client basic wallet (We'll call it accountA) - let (sender, ..) = insert_new_wallet( - &mut client, - AccountType::Private, - &authenticator_1, - AuthSchemeId::Falcon512Poseidon2, - ) - .await?; - let (target, ..) = insert_new_wallet( - &mut client_2, - AccountType::Private, - &authenticator_2, - AuthSchemeId::Falcon512Poseidon2, - ) - .await?; + let sender = client.insert_wallet(AccountType::Private).await?; + let target = client_2.insert_wallet(AccountType::Private).await?; let pass_through_account = create_pass_through_account(&mut client).await?; // Create client with faucets BTC faucet - let (btc_faucet_account, ..) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator_1, - AuthSchemeId::Falcon512Poseidon2, - ) - .await?; + let btc_faucet_account = client.insert_faucet(AccountType::Private).await?; // mint 1000 BTC for accountA info!(account_id = %sender.id(), faucet_id = %btc_faucet_account.id(), "Minting 1000 BTC for sender"); - let tx_id = - mint_and_consume(&mut client, sender.id(), btc_faucet_account.id(), NoteType::Public).await; - wait_for_tx(&mut client, tx_id).await?; + let tx_id = client + .mint_and_consume(sender.id(), btc_faucet_account.id(), NoteType::Public) + .await?; + client.wait_for_tx(tx_id).await?; // Create a note that we will send to a pass-through account info!(sender_id = %sender.id(), target_id = %target.id(), "Creating pass-through note"); @@ -120,7 +102,7 @@ pub async fn test_pass_through(client_config: ClientConfig) -> Result<()> { .own_output_notes(vec![pass_through_note_1.clone(), pass_through_note_2.clone()]) .build()?; - execute_tx_and_sync(&mut client, sender.id(), tx_request).await?; + client.execute_tx_and_sync(sender.id(), tx_request).await?; info!(note_id = %pass_through_note_1.id(), pass_through_account = %pass_through_account.id(), "Consuming pass-through note"); @@ -145,7 +127,7 @@ pub async fn test_pass_through(client_config: ClientConfig) -> Result<()> { .submit_new_transaction(pass_through_account.id(), tx_request.clone()) .await?; - wait_for_tx(&mut client, tx_id).await?; + client.wait_for_tx(tx_id).await?; let tx_record = client .get_transactions(TransactionFilter::Ids(vec![tx_id])) @@ -198,7 +180,7 @@ pub async fn test_pass_through(client_config: ClientConfig) -> Result<()> { .submit_new_transaction(pass_through_account.id(), tx_request.clone()) .await?; - wait_for_tx(&mut client, tx_id).await?; + client.wait_for_tx(tx_id).await?; let tx_record = client .get_transactions(TransactionFilter::Ids(vec![tx_id])) diff --git a/bin/integration-tests/src/tests/pswap_transaction.rs b/bin/integration-tests/src/tests/pswap_transaction.rs index 1dc62cf416..9371157384 100644 --- a/bin/integration-tests/src/tests/pswap_transaction.rs +++ b/bin/integration-tests/src/tests/pswap_transaction.rs @@ -1,7 +1,6 @@ use anyhow::{Context, Result}; use miden_client::account::AccountType; use miden_client::asset::{AssetAmount, FungibleAsset}; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::note::{Note, NoteType, PswapNote}; use miden_client::testing::common::*; use miden_client::transaction::{PswapTransactionData, TransactionRequestBuilder}; @@ -23,59 +22,27 @@ pub async fn test_pswap_full_fill_onchain(client_config: ClientConfig) -> Result const OFFERED_AMOUNT: u64 = 100; const REQUESTED_AMOUNT: u64 = 50; - let (mut alice_client, alice_authenticator) = client_config.clone().into_client().await?; - wait_for_node(&mut alice_client).await; - let (mut bob_client, bob_authenticator) = client_config.clone().into_client().await?; + let mut alice_client = client_config.clone().into_client().await?; + alice_client.wait_for_node().await; + let mut bob_client = client_config.clone().into_client().await?; alice_client.sync_state().await?; bob_client.sync_state().await?; - let (alice_account, ..) = insert_new_wallet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (bob_account, ..) = insert_new_wallet( - &mut bob_client, - AccountType::Private, - &bob_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (btc_faucet_account, _) = insert_new_fungible_faucet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (eth_faucet_account, _) = insert_new_fungible_faucet( - &mut bob_client, - AccountType::Private, - &bob_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let tx_id = mint_and_consume( - &mut alice_client, - alice_account.id(), - btc_faucet_account.id(), - NoteType::Public, - ) - .await; - wait_for_tx(&mut alice_client, tx_id).await?; - let tx_id = mint_and_consume( - &mut bob_client, - bob_account.id(), - eth_faucet_account.id(), - NoteType::Public, - ) - .await; - wait_for_tx(&mut bob_client, tx_id).await?; + let alice_account = alice_client.insert_wallet(AccountType::Private).await?; + let bob_account = bob_client.insert_wallet(AccountType::Private).await?; + + let btc_faucet_account = alice_client.insert_faucet(AccountType::Private).await?; + let eth_faucet_account = bob_client.insert_faucet(AccountType::Private).await?; + + let tx_id = alice_client + .mint_and_consume(alice_account.id(), btc_faucet_account.id(), NoteType::Public) + .await?; + alice_client.wait_for_tx(tx_id).await?; + let tx_id = bob_client + .mint_and_consume(bob_account.id(), eth_faucet_account.id(), NoteType::Public) + .await?; + bob_client.wait_for_tx(tx_id).await?; let offered_asset = FungibleAsset::new(btc_faucet_account.id(), OFFERED_AMOUNT)?; let requested_asset = FungibleAsset::new(eth_faucet_account.id(), REQUESTED_AMOUNT)?; @@ -90,7 +57,7 @@ pub async fn test_pswap_full_fill_onchain(client_config: ClientConfig) -> Result )?; let pswap_note = tx_request.expected_output_own_notes()[0].clone(); - execute_tx_and_sync(&mut alice_client, alice_account.id(), tx_request).await?; + alice_client.execute_tx_and_sync(alice_account.id(), tx_request).await?; // Subscribe bob_client to the PSWAP discovery tag so it can pick up the public note. let pswap_tag = PswapNote::create_tag(NoteType::Public, &offered_asset, &requested_asset); @@ -113,7 +80,7 @@ pub async fn test_pswap_full_fill_onchain(client_config: ClientConfig) -> Result "the consumer should not track any future notes" ); - execute_tx_and_sync(&mut bob_client, bob_account.id(), consume_request).await?; + bob_client.execute_tx_and_sync(bob_account.id(), consume_request).await?; // Alice discovers her payback through the creator-side note screening path after syncing, then // consumes it. @@ -127,7 +94,7 @@ pub async fn test_pswap_full_fill_onchain(client_config: ClientConfig) -> Result let payback_note: Note = payback_record.try_into()?; let consume_payback = TransactionRequestBuilder::new().build_consume_notes(vec![payback_note])?; - execute_tx_and_sync(&mut alice_client, alice_account.id(), consume_payback).await?; + alice_client.execute_tx_and_sync(alice_account.id(), consume_payback).await?; let alice_account_reader = alice_client.account_reader(alice_account.id()); assert_eq!( @@ -166,59 +133,27 @@ pub async fn test_pswap_partial_fill_onchain(client_config: ClientConfig) -> Res const REMAINING_OFFERED: u64 = OFFERED_AMOUNT - EXPECTED_PAYOUT; const REMAINING_REQUESTED: u64 = REQUESTED_AMOUNT - ACCOUNT_FILL; - let (mut alice_client, alice_authenticator) = client_config.clone().into_client().await?; - wait_for_node(&mut alice_client).await; - let (mut bob_client, bob_authenticator) = client_config.clone().into_client().await?; + let mut alice_client = client_config.clone().into_client().await?; + alice_client.wait_for_node().await; + let mut bob_client = client_config.clone().into_client().await?; alice_client.sync_state().await?; bob_client.sync_state().await?; - let (alice_account, ..) = insert_new_wallet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (bob_account, ..) = insert_new_wallet( - &mut bob_client, - AccountType::Private, - &bob_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (btc_faucet_account, _) = insert_new_fungible_faucet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - let (eth_faucet_account, _) = insert_new_fungible_faucet( - &mut bob_client, - AccountType::Private, - &bob_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let tx_id = mint_and_consume( - &mut alice_client, - alice_account.id(), - btc_faucet_account.id(), - NoteType::Public, - ) - .await; - wait_for_tx(&mut alice_client, tx_id).await?; - let tx_id = mint_and_consume( - &mut bob_client, - bob_account.id(), - eth_faucet_account.id(), - NoteType::Public, - ) - .await; - wait_for_tx(&mut bob_client, tx_id).await?; + let alice_account = alice_client.insert_wallet(AccountType::Private).await?; + let bob_account = bob_client.insert_wallet(AccountType::Private).await?; + + let btc_faucet_account = alice_client.insert_faucet(AccountType::Private).await?; + let eth_faucet_account = bob_client.insert_faucet(AccountType::Private).await?; + + let tx_id = alice_client + .mint_and_consume(alice_account.id(), btc_faucet_account.id(), NoteType::Public) + .await?; + alice_client.wait_for_tx(tx_id).await?; + let tx_id = bob_client + .mint_and_consume(bob_account.id(), eth_faucet_account.id(), NoteType::Public) + .await?; + bob_client.wait_for_tx(tx_id).await?; let offered_asset = FungibleAsset::new(btc_faucet_account.id(), OFFERED_AMOUNT)?; let requested_asset = FungibleAsset::new(eth_faucet_account.id(), REQUESTED_AMOUNT)?; @@ -231,7 +166,7 @@ pub async fn test_pswap_partial_fill_onchain(client_config: ClientConfig) -> Res alice_client.rng(), )?; let pswap_note = tx_request.expected_output_own_notes()[0].clone(); - execute_tx_and_sync(&mut alice_client, alice_account.id(), tx_request).await?; + alice_client.execute_tx_and_sync(alice_account.id(), tx_request).await?; let pswap_tag = PswapNote::create_tag(NoteType::Public, &offered_asset, &requested_asset); bob_client.add_note_tag(pswap_tag).await?; @@ -253,7 +188,7 @@ pub async fn test_pswap_partial_fill_onchain(client_config: ClientConfig) -> Res "the consumer should not track any future notes" ); - execute_tx_and_sync(&mut bob_client, bob_account.id(), consume_request).await?; + bob_client.execute_tx_and_sync(bob_account.id(), consume_request).await?; // Bob spent only ACCOUNT_FILL of ETH and received EXPECTED_PAYOUT of BTC (proportional, not the // full offered amount). This is the assertion that catches a wrong NOTE_ARGS layout: a wrong @@ -294,42 +229,20 @@ pub async fn test_pswap_cancel_onchain(client_config: ClientConfig) -> Result<() const OFFERED_AMOUNT: u64 = 100; const REQUESTED_AMOUNT: u64 = 50; - let (mut alice_client, alice_authenticator) = client_config.into_client().await?; - wait_for_node(&mut alice_client).await; + let mut alice_client = client_config.into_client().await?; + alice_client.wait_for_node().await; alice_client.sync_state().await?; - let (alice_account, ..) = insert_new_wallet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let (btc_faucet_account, _) = insert_new_fungible_faucet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let alice_account = alice_client.insert_wallet(AccountType::Private).await?; + + let btc_faucet_account = alice_client.insert_faucet(AccountType::Private).await?; // The requested-side faucet exists only so the FungibleAsset is well-formed. - let (eth_faucet_account, _) = insert_new_fungible_faucet( - &mut alice_client, - AccountType::Private, - &alice_authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await?; - - let tx_id = mint_and_consume( - &mut alice_client, - alice_account.id(), - btc_faucet_account.id(), - NoteType::Private, - ) - .await; - wait_for_tx(&mut alice_client, tx_id).await?; + let eth_faucet_account = alice_client.insert_faucet(AccountType::Private).await?; + + let tx_id = alice_client + .mint_and_consume(alice_account.id(), btc_faucet_account.id(), NoteType::Private) + .await?; + alice_client.wait_for_tx(tx_id).await?; let offered_asset = FungibleAsset::new(btc_faucet_account.id(), OFFERED_AMOUNT)?; let requested_asset = FungibleAsset::new(eth_faucet_account.id(), REQUESTED_AMOUNT)?; @@ -342,7 +255,7 @@ pub async fn test_pswap_cancel_onchain(client_config: ClientConfig) -> Result<() alice_client.rng(), )?; let pswap_note = create_request.expected_output_own_notes()[0].clone(); - execute_tx_and_sync(&mut alice_client, alice_account.id(), create_request).await?; + alice_client.execute_tx_and_sync(alice_account.id(), create_request).await?; let alice_account_reader = alice_client.account_reader(alice_account.id()); assert_eq!( @@ -354,7 +267,7 @@ pub async fn test_pswap_cancel_onchain(client_config: ClientConfig) -> Result<() info!(note_id = %pswap_note.id(), "Alice cancels the PSWAP"); let cancel_request = TransactionRequestBuilder::new().build_pswap_cancel(pswap_note, alice_account.id())?; - execute_tx_and_sync(&mut alice_client, alice_account.id(), cancel_request).await?; + alice_client.execute_tx_and_sync(alice_account.id(), cancel_request).await?; let alice_account_reader = alice_client.account_reader(alice_account.id()); assert_eq!( diff --git a/bin/integration-tests/src/tests/swap_transaction.rs b/bin/integration-tests/src/tests/swap_transaction.rs index 3e91143927..96e1b3f0d8 100644 --- a/bin/integration-tests/src/tests/swap_transaction.rs +++ b/bin/integration-tests/src/tests/swap_transaction.rs @@ -1,11 +1,9 @@ use anyhow::{Context, Result}; use miden_client::account::AccountType; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::note::standards::NoteSyncHint; use miden_client::note::{Note, NoteDetails, NoteFile, NoteType, SwapNote}; use miden_client::store::NoteFilter; -use miden_client::testing::common::*; use miden_client::transaction::{SwapTransactionData, TransactionRequestBuilder}; use tracing::info; @@ -17,63 +15,39 @@ use crate::ClientConfig; pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> { const OFFERED_ASSET_AMOUNT: u64 = 1; const REQUESTED_ASSET_AMOUNT: u64 = 25; - let (mut client1, authenticator_1) = client_config.clone().into_client().await?; - wait_for_node(&mut client1).await; - let (mut client2, authenticator_2) = client_config.clone().into_client().await?; + let mut client1 = client_config.clone().into_client().await?; + client1.wait_for_node().await; + let mut client2 = client_config.clone().into_client().await?; client1.sync_state().await?; client2.sync_state().await?; // Create Client 1's basic wallet (We'll call it accountA) - let (account_a, ..) = insert_new_wallet( - &mut client1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let account_a = client1.insert_wallet(AccountType::Private).await?; // Create Client 2's basic wallet (We'll call it accountB) - let (account_b, ..) = insert_new_wallet( - &mut client2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let account_b = client2.insert_wallet(AccountType::Private).await?; // Create client with faucets BTC faucet (note: it's not real BTC) - let (btc_faucet_account, _) = insert_new_fungible_faucet( - &mut client1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let btc_faucet_account = client1.insert_faucet(AccountType::Private).await?; // Create client with faucets ETH faucet (note: it's not real ETH) - let (eth_faucet_account, _) = insert_new_fungible_faucet( - &mut client2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let eth_faucet_account = client2.insert_faucet(AccountType::Private).await?; // mint 1000 BTC for accountA info!(account_id = %account_a.id(), faucet_id = %btc_faucet_account.id(), "Minting 1000 BTC for account A"); - let tx_id = - mint_and_consume(&mut client1, account_a.id(), btc_faucet_account.id(), NoteType::Public) - .await; - wait_for_tx(&mut client1, tx_id).await?; + let tx_id = client1 + .mint_and_consume(account_a.id(), btc_faucet_account.id(), NoteType::Public) + .await?; + client1.wait_for_tx(tx_id).await?; // mint 1000 ETH for accountB info!(account_id = %account_b.id(), faucet_id = %eth_faucet_account.id(), "Minting 1000 ETH for account B"); - let tx_id = - mint_and_consume(&mut client2, account_b.id(), eth_faucet_account.id(), NoteType::Public) - .await; - wait_for_tx(&mut client2, tx_id).await?; + let tx_id = client2 + .mint_and_consume(account_b.id(), eth_faucet_account.id(), NoteType::Public) + .await?; + client2.wait_for_tx(tx_id).await?; // Create ONCHAIN swap note (clientA offers 1 BTC in exchange of 25 ETH) check that account now // has 1 less BTC @@ -99,7 +73,7 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> assert_eq!(expected_output_notes.len(), 1); assert_eq!(expected_payback_note_details.len(), 1); - execute_tx_and_sync(&mut client1, account_a.id(), tx_request).await?; + client1.execute_tx_and_sync(account_a.id(), tx_request).await?; let swap_note_tag = SwapNote::create_tag( NoteType::Public, @@ -123,7 +97,7 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> .unwrap() .try_into()?; let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![note])?; - execute_tx_and_sync(&mut client2, account_b.id(), tx_request).await?; + client2.execute_tx_and_sync(account_b.id(), tx_request).await?; // sync on client 1, we should get the missing payback note details. try consuming the received // note with accountA, it should now have 25 ETH @@ -138,7 +112,7 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> .expect("payback note should be present after sync") .try_into()?; let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![note])?; - execute_tx_and_sync(&mut client1, account_a.id(), tx_request).await?; + client1.execute_tx_and_sync(account_a.id(), tx_request).await?; // At the end we should end up with // @@ -165,60 +139,36 @@ pub async fn test_swap_fully_onchain(client_config: ClientConfig) -> Result<()> pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { const OFFERED_ASSET_AMOUNT: u64 = 1; const REQUESTED_ASSET_AMOUNT: u64 = 25; - let (mut client1, authenticator_1) = client_config.clone().into_client().await?; - wait_for_node(&mut client1).await; - let (mut client2, authenticator_2) = client_config.clone().into_client().await?; + let mut client1 = client_config.clone().into_client().await?; + client1.wait_for_node().await; + let mut client2 = client_config.clone().into_client().await?; client1.sync_state().await?; client2.sync_state().await?; // Create Client 1's basic wallet (We'll call it accountA) - let (account_a, ..) = insert_new_wallet( - &mut client1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let account_a = client1.insert_wallet(AccountType::Private).await?; // Create Client 2's basic wallet (We'll call it accountB) - let (account_b, ..) = insert_new_wallet( - &mut client2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let account_b = client2.insert_wallet(AccountType::Private).await?; // Create client with faucets BTC faucet (note: it's not real BTC) - let (btc_faucet_account, _) = insert_new_fungible_faucet( - &mut client1, - AccountType::Private, - &authenticator_1, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let btc_faucet_account = client1.insert_faucet(AccountType::Private).await?; // Create client with faucets ETH faucet (note: it's not real ETH) - let (eth_faucet_account, _) = insert_new_fungible_faucet( - &mut client2, - AccountType::Private, - &authenticator_2, - RPO_FALCON_SCHEME_ID, - ) - .await?; + let eth_faucet_account = client2.insert_faucet(AccountType::Private).await?; // mint 1000 BTC for accountA info!(account_id = %account_a.id(), faucet_id = %btc_faucet_account.id(), "Minting 1000 BTC for account A"); - let tx_id = - mint_and_consume(&mut client1, account_a.id(), btc_faucet_account.id(), NoteType::Public) - .await; - wait_for_tx(&mut client1, tx_id).await?; + let tx_id = client1 + .mint_and_consume(account_a.id(), btc_faucet_account.id(), NoteType::Public) + .await?; + client1.wait_for_tx(tx_id).await?; // mint 1000 ETH for accountB info!(account_id = %account_b.id(), faucet_id = %eth_faucet_account.id(), "Minting 1000 ETH for account B"); - let tx_id = - mint_and_consume(&mut client2, account_b.id(), eth_faucet_account.id(), NoteType::Public) - .await; - wait_for_tx(&mut client2, tx_id).await?; + let tx_id = client2 + .mint_and_consume(account_b.id(), eth_faucet_account.id(), NoteType::Public) + .await?; + client2.wait_for_tx(tx_id).await?; // Create ONCHAIN swap note (clientA offers 1 BTC in exchange of 25 ETH) check that account now // has 1 less BTC @@ -244,7 +194,7 @@ pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { assert_eq!(expected_output_notes.len(), 1); assert_eq!(expected_payback_note_details.len(), 1); - execute_tx_and_sync(&mut client1, account_a.id(), tx_request).await?; + client1.execute_tx_and_sync(account_a.id(), tx_request).await?; // Export note from client 1 to client 2 let output_note = client1 @@ -277,7 +227,7 @@ pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { .unwrap() .try_into()?; let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![note])?; - execute_tx_and_sync(&mut client2, account_b.id(), tx_request).await?; + client2.execute_tx_and_sync(account_b.id(), tx_request).await?; // sync on client 1, we should get the missing payback note details. try consuming the received // note with accountA, it should now have 25 ETH @@ -292,7 +242,7 @@ pub async fn test_swap_private(client_config: ClientConfig) -> Result<()> { .expect("payback note should be present after sync") .try_into()?; let tx_request = TransactionRequestBuilder::new().build_consume_notes(vec![note])?; - execute_tx_and_sync(&mut client1, account_a.id(), tx_request).await?; + client1.execute_tx_and_sync(account_a.id(), tx_request).await?; // At the end we should end up with // diff --git a/bin/integration-tests/src/tests/transport.rs b/bin/integration-tests/src/tests/transport.rs index ed2fe43f84..98c1fb08e8 100644 --- a/bin/integration-tests/src/tests/transport.rs +++ b/bin/integration-tests/src/tests/transport.rs @@ -2,19 +2,9 @@ use anyhow::{Context, Result}; use miden_client::account::AccountType; use miden_client::address::{Address, AddressInterface, RoutingParameters}; use miden_client::asset::FungibleAsset; -use miden_client::auth::RPO_FALCON_SCHEME_ID; use miden_client::block::BlockNumber; use miden_client::note::NoteType; use miden_client::store::{InputNoteState, NoteFilter}; -use miden_client::testing::common::{ - assert_account_has_single_asset, - consume_notes, - execute_tx_and_sync, - insert_new_fungible_faucet, - insert_new_wallet, - wait_for_node, - wait_for_tx, -}; use miden_client::transaction::TransactionRequestBuilder; use crate::ClientConfig; @@ -37,32 +27,24 @@ pub async fn test_transport_note_inclusion_proof_and_consumption( let sender_config = client_config.clone(); let recipient_config = client_config; - let (mut sender, sender_keystore) = + let mut sender = sender_config.into_unsynced_client().await.context("failed to build sender")?; - let (mut recipient, recipient_keystore) = recipient_config + let mut recipient = recipient_config .into_unsynced_client() .await .context("failed to build recipient")?; - wait_for_node(&mut sender).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut sender, - AccountType::Private, - &sender_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .context("failed to insert faucet")?; - - let (recipient_account, _) = insert_new_wallet( - &mut recipient, - AccountType::Private, - &recipient_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .context("failed to insert wallet")?; + sender.wait_for_node().await; + + let faucet_account = sender + .insert_faucet(AccountType::Private) + .await + .context("failed to insert faucet")?; + + let recipient_account = recipient + .insert_wallet(AccountType::Private) + .await + .context("failed to insert wallet")?; let recipient_address = Address::new(recipient_account.id()) .with_routing_parameters(RoutingParameters::new(AddressInterface::BasicWallet)); @@ -86,7 +68,8 @@ pub async fn test_transport_note_inclusion_proof_and_consumption( .cloned() .context("expected output note missing")?; - execute_tx_and_sync(&mut sender, faucet_account.id(), tx_request) + sender + .execute_tx_and_sync(faucet_account.id(), tx_request) .await .context("mint tx failed")?; @@ -120,11 +103,12 @@ pub async fn test_transport_note_inclusion_proof_and_consumption( ); // Consume the note - let tx_id = consume_notes(&mut recipient, recipient_account.id(), &[note]).await; - wait_for_tx(&mut recipient, tx_id).await?; + let tx_id = recipient.consume_notes(recipient_account.id(), &[note]).await?; + recipient.wait_for_tx(tx_id).await?; // Verify balance - assert_account_has_single_asset(&recipient, recipient_account.id(), faucet_account.id(), 100) + recipient + .assert_account_has_single_asset(recipient_account.id(), faucet_account.id(), 100) .await; Ok(()) @@ -145,32 +129,24 @@ pub async fn test_transport_multiple_notes_different_blocks( let sender_config = client_config.clone(); let recipient_config = client_config; - let (mut sender, sender_keystore) = + let mut sender = sender_config.into_unsynced_client().await.context("failed to build sender")?; - let (mut recipient, recipient_keystore) = recipient_config + let mut recipient = recipient_config .into_unsynced_client() .await .context("failed to build recipient")?; - wait_for_node(&mut sender).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut sender, - AccountType::Private, - &sender_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .context("failed to insert faucet")?; - - let (recipient_account, _) = insert_new_wallet( - &mut recipient, - AccountType::Private, - &recipient_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .context("failed to insert wallet")?; + sender.wait_for_node().await; + + let faucet_account = sender + .insert_faucet(AccountType::Private) + .await + .context("failed to insert faucet")?; + + let recipient_account = recipient + .insert_wallet(AccountType::Private) + .await + .context("failed to insert wallet")?; let recipient_address = Address::new(recipient_account.id()) .with_routing_parameters(RoutingParameters::new(AddressInterface::BasicWallet)); @@ -198,7 +174,8 @@ pub async fn test_transport_multiple_notes_different_blocks( .last() .cloned() .context("expected output note missing")?; - execute_tx_and_sync(&mut sender, faucet_account.id(), tx_request) + sender + .execute_tx_and_sync(faucet_account.id(), tx_request) .await .context("mint tx failed")?; minted_notes.push(note); @@ -270,11 +247,12 @@ pub async fn test_transport_multiple_notes_different_blocks( ); // Consume all notes - let tx_id = consume_notes(&mut recipient, recipient_account.id(), &minted_notes).await; - wait_for_tx(&mut recipient, tx_id).await?; + let tx_id = recipient.consume_notes(recipient_account.id(), &minted_notes).await?; + recipient.wait_for_tx(tx_id).await?; // Verify total balance (10 + 20 + 30 = 60) - assert_account_has_single_asset(&recipient, recipient_account.id(), faucet_account.id(), 60) + recipient + .assert_account_has_single_asset(recipient_account.id(), faucet_account.id(), 60) .await; Ok(()) @@ -294,32 +272,24 @@ pub async fn test_transport_note_not_yet_committed(client_config: ClientConfig) let sender_config = client_config.clone(); let recipient_config = client_config; - let (mut sender, sender_keystore) = + let mut sender = sender_config.into_unsynced_client().await.context("failed to build sender")?; - let (mut recipient, recipient_keystore) = recipient_config + let mut recipient = recipient_config .into_unsynced_client() .await .context("failed to build recipient")?; - wait_for_node(&mut sender).await; - - let (faucet_account, _) = insert_new_fungible_faucet( - &mut sender, - AccountType::Private, - &sender_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .context("failed to insert faucet")?; - - let (recipient_account, _) = insert_new_wallet( - &mut recipient, - AccountType::Private, - &recipient_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .context("failed to insert wallet")?; + sender.wait_for_node().await; + + let faucet_account = sender + .insert_faucet(AccountType::Private) + .await + .context("failed to insert faucet")?; + + let recipient_account = recipient + .insert_wallet(AccountType::Private) + .await + .context("failed to insert wallet")?; let recipient_address = Address::new(recipient_account.id()) .with_routing_parameters(RoutingParameters::new(AddressInterface::BasicWallet)); @@ -372,7 +342,8 @@ pub async fn test_transport_note_not_yet_committed(client_config: ClientConfig) ); // Now execute the mint tx — note commits on chain - execute_tx_and_sync(&mut sender, faucet_account.id(), tx_request) + sender + .execute_tx_and_sync(faucet_account.id(), tx_request) .await .context("mint tx failed")?; @@ -392,10 +363,11 @@ pub async fn test_transport_note_not_yet_committed(client_config: ClientConfig) assert!(received.inclusion_proof().is_some(), "should have inclusion proof after commit"); // Consume the note - let tx_id = consume_notes(&mut recipient, recipient_account.id(), &[note]).await; - wait_for_tx(&mut recipient, tx_id).await?; + let tx_id = recipient.consume_notes(recipient_account.id(), &[note]).await?; + recipient.wait_for_tx(tx_id).await?; - assert_account_has_single_asset(&recipient, recipient_account.id(), faucet_account.id(), 100) + recipient + .assert_account_has_single_asset(recipient_account.id(), faucet_account.id(), 100) .await; Ok(()) diff --git a/bin/miden-bench/src/main.rs b/bin/miden-bench/src/main.rs index 1460e09295..968cc346c6 100644 --- a/bin/miden-bench/src/main.rs +++ b/bin/miden-bench/src/main.rs @@ -42,8 +42,9 @@ struct CliArgs { store: String, /// Path to pre-funded basic wallets to draw transaction fees from: either one `.mac` account - /// file or a directory of them. - #[arg(long, global = true, env = fee_funding::FUNDER_ACCOUNTS_ENV)] + /// file or a directory of them. Defaults to `MIDEN_FUNDER_ACCOUNTS_DIR`. A path naming no such + /// file leaves the run without funders, which is all a fee-free chain needs. + #[arg(long, global = true)] funders: Option, } @@ -258,11 +259,10 @@ async fn main() { .await .expect("Failed to create client"); - let fee_funder = fee_funding::load( - &ClientConfig::new(endpoint.clone(), RPC_TIMEOUT_MS), - args.funders.as_deref(), - ) - .expect("Failed to load the funder wallets"); + let funders = args.funders.or_else(fee_funding::funders_path_from_env); + let fee_funder = + fee_funding::load(&ClientConfig::new(endpoint.clone(), RPC_TIMEOUT_MS), funders.as_deref()) + .expect("Failed to load the funder wallets"); let mut client = TestClient::from(client).with_fee_funder(fee_funder); match args.command.startup_mode() { diff --git a/crates/rust-client/src/test_utils/common.rs b/crates/rust-client/src/test_utils/common.rs index 6fec948b04..4f6a89e283 100644 --- a/crates/rust-client/src/test_utils/common.rs +++ b/crates/rust-client/src/test_utils/common.rs @@ -12,14 +12,13 @@ use std::vec::Vec; use anyhow::{Context, Result}; use miden_protocol::account::auth::AuthSecretKey; -use miden_protocol::account::{Account, AccountComponentMetadata, AccountId}; +use miden_protocol::account::{Account, AccountId}; use miden_protocol::asset::{AssetAmount, FungibleAsset, TokenSymbol}; use miden_protocol::note::NoteType; use miden_protocol::testing::account_id::ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE; use miden_protocol::transaction::TransactionId; use miden_standards::account::auth::{Approver, AuthSingleSig}; use miden_standards::account::faucets::TokenName; -use miden_standards::code_builder::CodeBuilder; use rand::Rng; use tracing::{debug, info}; use uuid::Uuid; @@ -32,9 +31,8 @@ use crate::account::component::{ MintPolicy, TokenPolicyManager, }; -use crate::account::{AccountBuilder, AccountBuilderSchemaCommitmentExt, AccountType, StorageSlot}; -use crate::auth::AuthSchemeId; -use crate::crypto::FeltRng; +use crate::account::{AccountBuilder, AccountBuilderSchemaCommitmentExt, AccountType}; +use crate::auth::{AuthSchemeId, RPO_FALCON_SCHEME_ID}; pub use crate::keystore::{FilesystemKeyStore, Keystore}; use crate::note::{Note, NoteConsumability, P2idNote}; use crate::rpc::RpcError; @@ -78,6 +76,14 @@ impl TestClient { } } + /// Returns the keystore the client signs with, shared with it through the authenticator. + pub fn keystore(&self) -> &FilesystemKeyStore { + self.client + .authenticator() + .expect("test clients are always built with a keystore authenticator") + .as_ref() + } + /// Records funding notes, to be folded into each account's next transaction. pub(crate) fn stash_funding(&mut self, funded: impl IntoIterator) { self.pending_funding.extend(funded); @@ -169,669 +175,658 @@ impl DerefMut for TestClient { } } -// CONSTANTS +// ACCOUNT SETUP // ================================================================================================ -pub const ACCOUNT_ID_REGULAR: u128 = ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE; -/// Constant that represents the number of blocks until the p2id can be recalled. If this value is -/// too low, some tests might fail due to expected recall failures not happening. -pub const RECALL_HEIGHT_DELTA: u32 = 50; - -pub fn create_test_store_path() -> PathBuf { - let mut temp_file = temp_dir(); - temp_file.push(format!("{}.sqlite3", Uuid::new_v4())); - temp_file +/// What kind of standard components a test account is built around. +enum AccountKind { + /// A [`BasicWallet`]. + Wallet, + /// A [`FungibleFaucet`] with permissive mint/burn policies, plus a [`BasicWallet`] for its + /// `receive_asset` procedure, which `FungibleFaucet` does not export, so a P2ID note can fund + /// the faucet's own minting fees. Minting is unaffected. + Faucet, } -/// Inserts a new wallet account into the client and into the keystore. -pub async fn insert_new_wallet( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, +/// Configuration for an account inserted through [`TestClient::insert_account`]. +pub struct AccountSetup { + kind: AccountKind, + account_type: AccountType, auth_scheme: AuthSchemeId, -) -> Result<(Account, AuthSecretKey)> { - let mut init_seed = [0u8; 32]; - client.rng().fill_bytes(&mut init_seed); - - insert_new_wallet_with_seed(client, visibility, keystore, init_seed, auth_scheme).await + seed: Option<[u8; 32]>, + funded: bool, + with_basic_wallet_component: bool, + extra_components: Vec, } -/// Inserts a new wallet account built with the provided seed into the client and into the keystore. -pub async fn insert_new_wallet_with_seed( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, - init_seed: [u8; 32], - auth_scheme: AuthSchemeId, -) -> Result<(Account, AuthSecretKey)> { - let (account, key_pair) = - insert_new_wallet_with_seed_unfunded(client, visibility, keystore, init_seed, auth_scheme) - .await?; - client.fund_if_needed(&[account.id()]).await?; +impl AccountSetup { + fn new(kind: AccountKind, account_type: AccountType) -> Self { + Self { + kind, + account_type, + auth_scheme: RPO_FALCON_SCHEME_ID, + seed: None, + funded: true, + with_basic_wallet_component: true, + extra_components: Vec::new(), + } + } - Ok((account, key_pair)) -} + /// A basic wallet account. + pub fn wallet(account_type: AccountType) -> Self { + Self::new(AccountKind::Wallet, account_type) + } -/// Inserts a new wallet account without funding or deploying it. -/// -/// Callers creating several accounts at once should use this and fund them together with a single -/// [`TestClient::fund_if_needed`], which costs one funding transaction instead of one per account. -pub async fn insert_new_wallet_unfunded( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, - auth_scheme: AuthSchemeId, -) -> Result<(Account, AuthSecretKey)> { - let mut init_seed = [0u8; 32]; - client.rng().fill_bytes(&mut init_seed); + /// A fungible faucet account. + pub fn faucet(account_type: AccountType) -> Self { + Self::new(AccountKind::Faucet, account_type) + } - insert_new_wallet_with_seed_unfunded(client, visibility, keystore, init_seed, auth_scheme).await + /// Signs with `auth_scheme` instead of the default [`RPO_FALCON_SCHEME_ID`]. + #[must_use] + pub fn auth_scheme(mut self, auth_scheme: AuthSchemeId) -> Self { + self.auth_scheme = auth_scheme; + self + } + + /// Builds the account from `seed` instead of a random one, for tests that re-derive the account + /// ID. + #[must_use] + pub fn seed(mut self, seed: [u8; 32]) -> Self { + self.seed = Some(seed); + self + } + + /// Skips funding the account on insertion. + #[must_use] + pub fn unfunded(mut self) -> Self { + self.funded = false; + self + } + + /// Builds a faucet without the [`BasicWallet`] ride-along, so the account exposes only the + /// faucet interface. Has no effect on a wallet setup. + #[must_use] + pub fn without_basic_wallet_component(mut self) -> Self { + self.with_basic_wallet_component = false; + self + } + + /// Adds `component` on top of the standard ones. + #[must_use] + pub fn component(mut self, component: AccountComponent) -> Self { + self.extra_components.push(component); + self + } } -/// Inserts a new wallet account built with the provided seed, without funding or deploying it. -pub async fn insert_new_wallet_with_seed_unfunded( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, - init_seed: [u8; 32], - auth_scheme: AuthSchemeId, -) -> Result<(Account, AuthSecretKey)> { - let key_pair = match auth_scheme { - AuthSchemeId::Falcon512Poseidon2 => AuthSecretKey::new_falcon512_poseidon2(), - AuthSchemeId::EcdsaK256Keccak => AuthSecretKey::new_ecdsa_k256_keccak(), - other => panic!("unsupported auth scheme: {}", other.as_u8()), - }; - let auth_component = - AuthSingleSig::new(Approver::new(key_pair.public_key().to_commitment(), auth_scheme)); +impl TestClient { + /// Builds the account described by `setup`, adds its key to the keystore, and inserts it into + /// the client. Unless [`AccountSetup::unfunded`] was set, the account is also funded so its + /// first transaction can pay its own fee and double as its deploy. + pub async fn insert_account( + &mut self, + setup: AccountSetup, + ) -> Result<(Account, AuthSecretKey)> { + let key_pair = match setup.auth_scheme { + AuthSchemeId::Falcon512Poseidon2 => AuthSecretKey::new_falcon512_poseidon2(), + AuthSchemeId::EcdsaK256Keccak => AuthSecretKey::new_ecdsa_k256_keccak(), + other => anyhow::bail!("unsupported auth scheme: {}", other.as_u8()), + }; + let auth_component = AuthSingleSig::new(Approver::new( + key_pair.public_key().to_commitment(), + setup.auth_scheme, + )); + + let init_seed = setup.seed.unwrap_or_else(|| { + let mut seed = [0u8; 32]; + self.rng().fill_bytes(&mut seed); + seed + }); + + let mut builder = AccountBuilder::new(init_seed) + .account_type(setup.account_type) + .with_component(auth_component); + + match setup.kind { + AccountKind::Wallet => { + builder = builder.with_component(BasicWallet); + }, + AccountKind::Faucet => { + let symbol = TokenSymbol::new("TEST").expect("TEST is a valid token symbol"); + let name = TokenName::new(&symbol.to_string()) + .expect("token symbol is a valid token name"); + let max_supply = 9_999_999_u64; + let faucet = FungibleFaucet::builder() + .name(name) + .symbol(symbol) + .decimals(10) + .max_supply(AssetAmount::new(max_supply).expect("max supply is a valid amount")) + .build() + .context("failed to build the fungible faucet component")?; + + // Only mint and burn policies are registered. A transfer (send/receive) policy + // installs asset callback slots on the faucet, which forces `FungibleAsset` keys to + // carry `AssetCallbackFlag::Enabled`. Tests build assets with `FungibleAsset::new`, + // which defaults to `Disabled`, so a transfer policy makes `mint_and_send` reject + // the mint with `ERR_FUNGIBLE_MINT_NOTE_ASSET_NOT_FROM_THIS_FAUCET`. + let policy_manager = TokenPolicyManager::builder() + .active_mint_policy(MintPolicy::allow_all()) + .active_burn_policy(BurnPolicy::allow_all()) + .build(); + + builder = builder.with_component(faucet); + if setup.with_basic_wallet_component { + builder = builder.with_component(BasicWallet); + } + builder = builder.with_components(policy_manager); + }, + } - let account = AccountBuilder::new(init_seed) - .account_type(visibility) - .with_component(auth_component) - .with_component(BasicWallet) - .build_with_schema_commitment() - .unwrap(); + for component in setup.extra_components { + builder = builder.with_component(component); + } - keystore.add_key(&key_pair, account.id()).await.unwrap(); + let account = builder + .build_with_schema_commitment() + .context("failed to build the test account")?; - client.add_account(&account, false).await?; + self.keystore() + .add_key(&key_pair, account.id()) + .await + .context("failed to add the account key to the keystore")?; - info!(account_id = %account.id(), ?visibility, "Inserted new wallet"); + self.add_account(&account, false).await?; - Ok((account, key_pair)) -} + info!(account_id = %account.id(), account_type = ?setup.account_type, "Inserted account"); -/// Inserts a new fungible faucet account into the client and into the keystore. -/// -/// A [`BasicWallet`] rides along for its `receive_asset` procedure, which `FungibleFaucet` does not -/// export, so a P2ID note can fund the faucet's own minting fees. Minting is unaffected. -pub async fn insert_new_fungible_faucet( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, - auth_scheme: AuthSchemeId, -) -> Result<(Account, AuthSecretKey)> { - let (account, key_pair) = - insert_new_fungible_faucet_unfunded(client, visibility, keystore, auth_scheme).await?; - client.fund_if_needed(&[account.id()]).await?; + if setup.funded { + self.fund_if_needed(&[account.id()]).await?; + } - Ok((account, key_pair)) -} + Ok((account, key_pair)) + } -/// Inserts a new fungible faucet account without funding or deploying it. -/// -/// See [`insert_new_wallet_unfunded`] for when to prefer this. -pub async fn insert_new_fungible_faucet_unfunded( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, - auth_scheme: AuthSchemeId, -) -> Result<(Account, AuthSecretKey)> { - let key_pair = match auth_scheme { - AuthSchemeId::Falcon512Poseidon2 => AuthSecretKey::new_falcon512_poseidon2(), - AuthSchemeId::EcdsaK256Keccak => AuthSecretKey::new_ecdsa_k256_keccak(), - other => panic!("unsupported auth scheme: {}", other.as_u8()), - }; - let auth_component = - AuthSingleSig::new(Approver::new(key_pair.public_key().to_commitment(), auth_scheme)); - - // we need to use an initial seed to create the faucet account - let mut init_seed = [0u8; 32]; - client.rng().fill_bytes(&mut init_seed); - - let symbol = TokenSymbol::new("TEST").unwrap(); - let name = TokenName::new(&symbol.to_string()).expect("token symbol is a valid token name"); - let max_supply = 9_999_999_u64; - let faucet = FungibleFaucet::builder() - .name(name) - .symbol(symbol) - .decimals(10) - .max_supply(AssetAmount::new(max_supply).unwrap()) - .build() - .unwrap(); - - // Only mint/burn policies — registering transfer (send/receive) policies installs asset - // callback slots on the faucet, which forces `FungibleAsset` keys to carry - // `AssetCallbackFlag::Enabled`. Tests construct assets via `FungibleAsset::new`, which defaults - // to `Disabled`, so adding transfer policies makes `mint_and_send` reject the mint with - // `ERR_FUNGIBLE_MINT_NOTE_ASSET_NOT_FROM_THIS_FAUCET`. - let policy_manager = TokenPolicyManager::builder() - .active_mint_policy(MintPolicy::allow_all()) - .active_burn_policy(BurnPolicy::allow_all()) - .build(); - let account = AccountBuilder::new(init_seed) - .account_type(visibility) - .with_component(auth_component) - .with_component(faucet) - .with_component(BasicWallet) - .with_components(policy_manager) - .build_with_schema_commitment() - .unwrap(); - - keystore.add_key(&key_pair, account.id()).await.unwrap(); - - client.add_account(&account, false).await?; - - info!(account_id = %account.id(), ?visibility, "Inserted new fungible faucet"); - - Ok((account, key_pair)) -} + /// Inserts a new funded wallet account, signing with the default auth scheme. + pub async fn insert_wallet(&mut self, account_type: AccountType) -> Result { + let (account, _) = self.insert_account(AccountSetup::wallet(account_type)).await?; + Ok(account) + } + + /// Inserts a new funded fungible faucet account, signing with the default auth scheme. + pub async fn insert_faucet(&mut self, account_type: AccountType) -> Result { + let (account, _) = self.insert_account(AccountSetup::faucet(account_type)).await?; + Ok(account) + } -/// Executes a transaction and asserts that it fails with the expected error. -pub async fn execute_failing_tx( - client: &mut TestClient, - account_id: AccountId, - tx_request: TransactionRequest, - expected_error: ClientError, -) { - info!(account_id = %account_id, "Executing transaction (expecting failure)"); - // We compare string since we can't compare the error directly - assert_eq!( - Box::pin(client.submit_new_transaction(account_id, tx_request)) + /// Sets up a wallet account and a faucet account (in that order). + pub async fn setup_wallet_and_faucet( + &mut self, + account_type: AccountType, + ) -> Result<(Account, Account)> { + let (faucet_account, _) = self + .insert_account(AccountSetup::faucet(account_type).unfunded()) .await - .unwrap_err() - .to_string(), - expected_error.to_string() - ); -} + .context("failed to insert new fungible faucet account")?; -/// Executes a transaction and waits for it to be committed. -pub async fn execute_tx_and_sync( - client: &mut TestClient, - account_id: AccountId, - tx_request: TransactionRequest, -) -> Result<()> { - let transaction_id = Box::pin(client.submit_new_transaction(account_id, tx_request)).await?; - info!(tx_id = %transaction_id, account_id = %account_id, "Transaction submitted, waiting for commit"); - wait_for_tx(client, transaction_id).await?; - Ok(()) -} + let (basic_account, _) = self + .insert_account(AccountSetup::wallet(account_type).unfunded()) + .await + .context("failed to insert new wallet account")?; -/// Syncs the client and waits for the transaction to be committed. -pub async fn wait_for_tx(client: &mut TestClient, transaction_id: TransactionId) -> Result<()> { - // wait until tx is committed - let now = Instant::now(); - debug!(tx_id = %transaction_id, "Waiting for transaction to be committed"); - loop { - client - .sync_state() + self.fund_if_needed(&[faucet_account.id(), basic_account.id()]) .await - .with_context(|| "failed to sync client state while waiting for transaction")?; + .context("failed to fund and deploy the created accounts")?; + + Ok((basic_account, faucet_account)) + } - // Check if executed transaction got committed by the node - let tracked_transaction = client - .get_transactions(TransactionFilter::Ids(vec![transaction_id])) + /// Sets up two wallet accounts and a faucet account (in that order), on a client that has to be + /// in a clean state. + pub async fn setup_two_wallets_and_faucet( + &mut self, + account_type: AccountType, + ) -> Result<(Account, Account, Account)> { + // Ensure clean state + let account_headers = self + .get_account_headers() .await - .with_context(|| format!("failed to get transaction with ID: {transaction_id}"))? - .pop() - .with_context(|| format!("transaction with ID {transaction_id} not found"))?; + .with_context(|| "failed to get account headers")?; + anyhow::ensure!( + account_headers.is_empty(), + "Expected empty account headers for clean state" + ); - match tracked_transaction.status { - TransactionStatus::Committed { block_number, .. } => { - info!(tx_id = %transaction_id, %block_number, "Transaction committed"); - break; - }, - TransactionStatus::Pending => { - // Cooldown between polling iterations to reduce pressure on the node's rate limiter - // when many integration tests poll concurrently. - tokio::time::sleep(Duration::from_millis(500)).await; - }, - TransactionStatus::Discarded(cause) => { - anyhow::bail!("transaction was discarded with cause: {cause:?}"); - }, - } + let transactions = self + .get_transactions(TransactionFilter::All) + .await + .with_context(|| "failed to get transactions")?; + anyhow::ensure!(transactions.is_empty(), "Expected empty transactions for clean state"); - // Log wait time in a file if the env var is set. This allows us to aggregate and measure - // how long the tests are waiting for transactions to be committed. - if std::env::var("LOG_WAIT_TIMES") == Ok("true".to_string()) { - let elapsed = now.elapsed(); - let wait_times_dir = std::path::PathBuf::from("wait_times"); - std::fs::create_dir_all(&wait_times_dir) - .with_context(|| "failed to create wait_times directory")?; - - let elapsed_time_file = wait_times_dir.join(format!("wait_time_{}", Uuid::new_v4())); - let mut file = OpenOptions::new() - .create(true) - .write(true) - .truncate(true) - .open(elapsed_time_file) - .with_context(|| "failed to create elapsed time file")?; - writeln!(file, "{:?}", elapsed.as_millis()) - .with_context(|| "failed to write elapsed time to file")?; - } - } - Ok(()) -} + let input_notes = self + .get_input_notes(NoteFilter::All) + .await + .with_context(|| "failed to get input notes")?; + anyhow::ensure!(input_notes.is_empty(), "Expected empty input notes for clean state"); -/// Syncs until `amount_of_blocks` have been created onchain compared to client's sync height -pub async fn wait_for_blocks(client: &mut TestClient, amount_of_blocks: u32) -> SyncSummary { - let current_block = client.get_sync_height().await.unwrap(); - let final_block = current_block + amount_of_blocks; - debug!(current_block = %current_block, target_block = %final_block, "Waiting for blocks"); - loop { - let summary = client.sync_state().await.unwrap(); - debug!(sync_height = %summary.block_num, target_block = %final_block, "Synced"); - - if summary.block_num >= final_block { - return summary; - } + let (faucet_account, _) = self + .insert_account(AccountSetup::faucet(account_type).unfunded()) + .await + .context("failed to insert new fungible faucet account")?; + + let (first_basic_account, _) = self + .insert_account(AccountSetup::wallet(account_type).unfunded()) + .await + .context("failed to insert first basic wallet account")?; + + let (second_basic_account, _) = self + .insert_account(AccountSetup::wallet(account_type).unfunded()) + .await + .context("failed to insert second basic wallet account")?; + + self.fund_if_needed(&[ + faucet_account.id(), + first_basic_account.id(), + second_basic_account.id(), + ]) + .await + .context("failed to fund and deploy the created accounts")?; + + info!( + faucet_id = %faucet_account.id(), + wallet_1_id = %first_basic_account.id(), + wallet_2_id = %second_basic_account.id(), + "Setup complete, syncing state" + ); + self.sync_state().await.with_context(|| "failed to sync client state")?; - tokio::time::sleep(Duration::from_secs(3)).await; + Ok((first_basic_account, second_basic_account, faucet_account)) } } -/// Idles until `amount_of_blocks` have been created onchain compared to client's sync height -/// without advancing the client's sync height -pub async fn wait_for_blocks_no_sync(client: &mut TestClient, amount_of_blocks: u32) { - let current_block = client.get_sync_height().await.unwrap(); - let final_block = current_block + amount_of_blocks; - debug!(current_block = %current_block, target_block = %final_block, "Waiting for blocks (no sync)"); - loop { - let (latest_block, _) = - client.test_rpc_api().get_block_header_by_number(None, false).await.unwrap(); - debug!( - chain_tip = %latest_block.block_num(), - target_block = %final_block, - "Waiting for blocks (no sync)" +// TRANSACTION HELPERS +// ================================================================================================ + +impl TestClient { + /// Executes a transaction and asserts that it fails with the expected error. + pub async fn execute_failing_tx( + &mut self, + account_id: AccountId, + tx_request: TransactionRequest, + expected_error: ClientError, + ) { + info!(account_id = %account_id, "Executing transaction (expecting failure)"); + // We compare string since we can't compare the error directly + assert_eq!( + self.submit_new_transaction(account_id, tx_request) + .await + .unwrap_err() + .to_string(), + expected_error.to_string() ); + } + + /// Executes a transaction and waits for it to be committed. + pub async fn execute_tx_and_sync( + &mut self, + account_id: AccountId, + tx_request: TransactionRequest, + ) -> Result<()> { + let transaction_id = self.submit_new_transaction(account_id, tx_request).await?; + info!(tx_id = %transaction_id, account_id = %account_id, "Transaction submitted, waiting for commit"); + self.wait_for_tx(transaction_id).await?; + Ok(()) + } - if latest_block.block_num() >= final_block { - return; + /// Syncs the client and waits for the transaction to be committed. + pub async fn wait_for_tx(&mut self, transaction_id: TransactionId) -> Result<()> { + // wait until tx is committed + let now = Instant::now(); + debug!(tx_id = %transaction_id, "Waiting for transaction to be committed"); + loop { + self.sync_state() + .await + .with_context(|| "failed to sync client state while waiting for transaction")?; + + // Check if executed transaction got committed by the node + let tracked_transaction = self + .get_transactions(TransactionFilter::Ids(vec![transaction_id])) + .await + .with_context(|| format!("failed to get transaction with ID: {transaction_id}"))? + .pop() + .with_context(|| format!("transaction with ID {transaction_id} not found"))?; + + match tracked_transaction.status { + TransactionStatus::Committed { block_number, .. } => { + info!(tx_id = %transaction_id, %block_number, "Transaction committed"); + break; + }, + TransactionStatus::Pending => { + // Cooldown between polling iterations to reduce pressure on the node's rate + // limiter when many integration tests poll concurrently. + tokio::time::sleep(Duration::from_millis(500)).await; + }, + TransactionStatus::Discarded(cause) => { + anyhow::bail!("transaction was discarded with cause: {cause:?}"); + }, + } + + // Log wait time in a file if the env var is set This allows us to aggregate and measure + // how long the tests are waiting for transactions to be committed + if std::env::var("LOG_WAIT_TIMES") == Ok("true".to_string()) { + let elapsed = now.elapsed(); + let wait_times_dir = std::path::PathBuf::from("wait_times"); + std::fs::create_dir_all(&wait_times_dir) + .with_context(|| "failed to create wait_times directory")?; + + let elapsed_time_file = + wait_times_dir.join(format!("wait_time_{}", Uuid::new_v4())); + let mut file = OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(elapsed_time_file) + .with_context(|| "failed to create elapsed time file")?; + writeln!(file, "{:?}", elapsed.as_millis()) + .with_context(|| "failed to write elapsed time to file")?; + } } + Ok(()) + } - tokio::time::sleep(Duration::from_secs(3)).await; + /// Syncs until `amount_of_blocks` have been created onchain compared to client's sync height. + pub async fn wait_for_blocks(&mut self, amount_of_blocks: u32) -> Result { + let current_block = self.get_sync_height().await?; + let final_block = current_block + amount_of_blocks; + debug!(current_block = %current_block, target_block = %final_block, "Waiting for blocks"); + loop { + let summary = self.sync_state().await?; + debug!(sync_height = %summary.block_num, target_block = %final_block, "Synced"); + + if summary.block_num >= final_block { + return Ok(summary); + } + + tokio::time::sleep(Duration::from_secs(3)).await; + } } -} -/// Syncs repeatedly until the given account has at least one consumable note, or until `max_blocks` -/// have elapsed since the call. Returns the list of consumable notes once found. -/// -/// This is useful when waiting for a network transaction to produce an output note (e.g., a P2ID -/// note created by a faucet after consuming a CLAIM note), where the exact number of blocks needed -/// is unpredictable. -/// -/// # Panics -/// -/// Panics if `max_blocks` elapse without any consumable notes appearing. -pub async fn wait_for_consumable_notes( - client: &mut TestClient, - account_id: AccountId, - max_blocks: u32, -) -> Vec<(InputNoteRecord, Vec)> { - let start_block = client.get_sync_height().await.unwrap(); - let deadline_block = start_block + max_blocks; - debug!( - %account_id, - %start_block, - %deadline_block, - "Waiting for consumable notes" - ); - - loop { - client.sync_state().await.unwrap(); - let notes = client.get_consumable_notes(Some(account_id)).await.unwrap(); - if !notes.is_empty() { - let current_block = client.get_sync_height().await.unwrap(); + /// Idles until `amount_of_blocks` have been created onchain compared to client's sync height + /// without advancing the client's sync height. + pub async fn wait_for_blocks_no_sync(&mut self, amount_of_blocks: u32) -> Result<()> { + let current_block = self.get_sync_height().await?; + let final_block = current_block + amount_of_blocks; + debug!(current_block = %current_block, target_block = %final_block, "Waiting for blocks (no sync)"); + loop { + let (latest_block, _) = + self.test_rpc_api().get_block_header_by_number(None, false).await?; debug!( - %account_id, - count = notes.len(), - %current_block, - "Found consumable notes" + chain_tip = %latest_block.block_num(), + target_block = %final_block, + "Waiting for blocks (no sync)" ); - return notes; - } - let current_block = client.get_sync_height().await.unwrap(); - assert!( - current_block < deadline_block, - "account {account_id} has no consumable notes after waiting {max_blocks} blocks \ - (from block {start_block} to {current_block})" - ); + if latest_block.block_num() >= final_block { + return Ok(()); + } + + tokio::time::sleep(Duration::from_secs(3)).await; + } + } + /// Syncs repeatedly until the given account has at least one consumable note, or until + /// `max_blocks` have elapsed since the call. Returns the list of consumable notes once found. + pub async fn wait_for_consumable_notes( + &mut self, + account_id: AccountId, + max_blocks: u32, + ) -> Result)>> { + let start_block = self.get_sync_height().await?; + let deadline_block = start_block + max_blocks; debug!( %account_id, - %current_block, + %start_block, %deadline_block, - "No consumable notes yet, waiting..." + "Waiting for consumable notes" ); - std::thread::sleep(Duration::from_secs(3)); - } -} -/// Waits for node to be running. -/// -/// # Panics -/// -/// This function will panic if it does `NUMBER_OF_NODE_ATTEMPTS` unsuccessful checks or if we -/// receive an error other than a connection related error. -pub async fn wait_for_node(client: &mut TestClient) { - const NODE_TIME_BETWEEN_ATTEMPTS: u64 = 2; - const NUMBER_OF_NODE_ATTEMPTS: u64 = 60; - info!( - "Waiting for node to be up (checking every {NODE_TIME_BETWEEN_ATTEMPTS}s, max {NUMBER_OF_NODE_ATTEMPTS} tries)" - ); - for _try_number in 0..NUMBER_OF_NODE_ATTEMPTS { - match client.sync_state().await { - Err(ClientError::RpcError( - RpcError::ConnectionError(_) | RpcError::RequestError { .. }, - )) => { - tokio::time::sleep(Duration::from_secs(NODE_TIME_BETWEEN_ATTEMPTS)).await; - }, - Err(other_error) => { - panic!("Unexpected error: {other_error}"); - }, - _ => return, + loop { + self.sync_state().await?; + let notes = self.get_consumable_notes(Some(account_id)).await?; + if !notes.is_empty() { + let current_block = self.get_sync_height().await?; + debug!( + %account_id, + count = notes.len(), + %current_block, + "Found consumable notes" + ); + return Ok(notes); + } + + let current_block = self.get_sync_height().await?; + assert!( + current_block < deadline_block, + "account {account_id} has no consumable notes after waiting {max_blocks} blocks \ + (from block {start_block} to {current_block})" + ); + + debug!( + %account_id, + %current_block, + %deadline_block, + "No consumable notes yet, waiting..." + ); + std::thread::sleep(Duration::from_secs(3)); } } - panic!("Unable to connect to node"); -} - -pub const MINT_AMOUNT: u64 = 1000; -pub const TRANSFER_AMOUNT: u64 = 59; - -/// Sets up a basic client and returns two basic accounts and a faucet account (in that order). -pub async fn setup_two_wallets_and_faucet( - client: &mut TestClient, - account_visibility: AccountType, - keystore: &FilesystemKeyStore, - auth_scheme: AuthSchemeId, -) -> Result<(Account, Account, Account)> { - // Ensure clean state - let account_headers = client - .get_account_headers() - .await - .with_context(|| "failed to get account headers")?; - anyhow::ensure!(account_headers.is_empty(), "Expected empty account headers for clean state"); + /// Waits for node to be running. + pub async fn wait_for_node(&mut self) { + const NODE_TIME_BETWEEN_ATTEMPTS: u64 = 2; + const NUMBER_OF_NODE_ATTEMPTS: u64 = 60; + info!( + "Waiting for node to be up (checking every {NODE_TIME_BETWEEN_ATTEMPTS}s, max {NUMBER_OF_NODE_ATTEMPTS} tries)" + ); + for _try_number in 0..NUMBER_OF_NODE_ATTEMPTS { + match self.sync_state().await { + Err(ClientError::RpcError( + RpcError::ConnectionError(_) | RpcError::RequestError { .. }, + )) => { + tokio::time::sleep(Duration::from_secs(NODE_TIME_BETWEEN_ATTEMPTS)).await; + }, + Err(other_error) => { + panic!("Unexpected error: {other_error}"); + }, + _ => return, + } + } - let transactions = client - .get_transactions(TransactionFilter::All) - .await - .with_context(|| "failed to get transactions")?; - anyhow::ensure!(transactions.is_empty(), "Expected empty transactions for clean state"); + panic!("Unable to connect to node"); + } - let input_notes = client - .get_input_notes(NoteFilter::All) - .await - .with_context(|| "failed to get input notes")?; - anyhow::ensure!(input_notes.is_empty(), "Expected empty input notes for clean state"); + /// Mints a note from `faucet_account_id` for `basic_account_id` and returns the executed + /// transaction ID and the note with [`MINT_AMOUNT`] units of the corresponding fungible asset. + pub async fn mint_note( + &mut self, + basic_account_id: AccountId, + faucet_account_id: AccountId, + note_type: NoteType, + ) -> Result<(TransactionId, Note)> { + // Create a Mint Tx for MINT_AMOUNT units of our fungible asset + let fungible_asset = FungibleAsset::new(faucet_account_id, MINT_AMOUNT)?; + info!(faucet_id = %faucet_account_id, target_id = %basic_account_id, amount = MINT_AMOUNT, "Minting asset"); + let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( + fungible_asset, + basic_account_id, + note_type, + self.rng(), + )?; + let tx_id = self + .submit_new_transaction(fungible_asset.faucet_id(), tx_request.clone()) + .await?; - // Create faucet account - let (faucet_account, _) = - insert_new_fungible_faucet_unfunded(client, account_visibility, keystore, auth_scheme) - .await - .with_context(|| "failed to insert new fungible faucet account")?; + let note = tx_request + .expected_output_own_notes() + .pop() + .context("the mint request should produce one output note")?; + info!(tx_id = %tx_id, note_id = %note.id(), "Mint transaction submitted"); + Ok((tx_id, note)) + } - // Create regular accounts - let (first_basic_account, ..) = - insert_new_wallet_unfunded(client, account_visibility, keystore, auth_scheme) - .await - .with_context(|| "failed to insert first basic wallet account")?; + /// Executes a transaction that consumes the provided notes and returns the transaction ID. This + /// assumes the notes contain assets. + pub async fn consume_notes( + &mut self, + account_id: AccountId, + input_notes: &[Note], + ) -> Result { + let note_ids: Vec<_> = input_notes.iter().map(|n| n.id().to_string()).collect(); + info!(account_id = %account_id, note_ids = %note_ids.join(", "), "Consuming notes"); + let tx_request = + TransactionRequestBuilder::new().build_consume_notes(input_notes.to_vec())?; + let tx_id = self.submit_new_transaction(account_id, tx_request).await?; + info!(tx_id = %tx_id, "Consume transaction submitted"); + Ok(tx_id) + } - let (second_basic_account, ..) = - insert_new_wallet_unfunded(client, account_visibility, keystore, auth_scheme) - .await - .with_context(|| "failed to insert second basic wallet account")?; + /// Executes a transaction and consumes the resulting unauthenticated notes immediately without + /// waiting for the first transaction to be committed. + pub async fn execute_tx_and_consume_output_notes( + &mut self, + tx_request: TransactionRequest, + executor: AccountId, + consumer: AccountId, + ) -> Result { + let output_notes = tx_request + .expected_output_own_notes() + .into_iter() + .map(|note| (note, None::)) + .collect::)>>(); + + self.submit_new_transaction(executor, tx_request).await?; + + let tx_request = TransactionRequestBuilder::new().input_notes(output_notes).build()?; + Ok(self.submit_new_transaction(consumer, tx_request).await?) + } - // All three at once, so one funding transaction covers the set. - client - .fund_if_needed(&[faucet_account.id(), first_basic_account.id(), second_basic_account.id()]) - .await - .with_context(|| "failed to fund and deploy the created accounts")?; + /// Mints assets for the target account and consumes them immediately without waiting for the + /// first transaction to be committed. + pub async fn mint_and_consume( + &mut self, + basic_account_id: AccountId, + faucet_account_id: AccountId, + note_type: NoteType, + ) -> Result { + info!( + faucet_id = %faucet_account_id, + target_id = %basic_account_id, + amount = MINT_AMOUNT, + "Minting and consuming asset" + ); + let tx_request = TransactionRequestBuilder::new().build_mint_fungible_asset( + FungibleAsset::new(faucet_account_id, MINT_AMOUNT)?, + basic_account_id, + note_type, + self.rng(), + )?; - info!( - faucet_id = %faucet_account.id(), - wallet_1_id = %first_basic_account.id(), - wallet_2_id = %second_basic_account.id(), - "Setup complete, syncing state" - ); - client.sync_state().await.with_context(|| "failed to sync client state")?; + let tx_id = self + .execute_tx_and_consume_output_notes(tx_request, faucet_account_id, basic_account_id) + .await?; + info!(tx_id = %tx_id, "Mint-and-consume transaction submitted"); + Ok(tx_id) + } - Ok((first_basic_account, second_basic_account, faucet_account)) + /// Creates a transaction request that mints assets for each `target_id` account. + pub fn mint_multiple_fungible_asset( + &mut self, + asset: FungibleAsset, + target_id: &[AccountId], + note_type: NoteType, + ) -> Result { + let rng = self.rng(); + let notes = target_id + .iter() + .map(|account_id| { + Ok(P2idNote::builder() + .sender(asset.faucet_id()) + .target(*account_id) + .asset(asset) + .note_type(note_type) + .generate_serial_number(rng) + .build() + .context("note creation failed")? + .into()) + }) + .collect::>>()?; + + Ok(TransactionRequestBuilder::new().own_output_notes(notes).build()?) + } } -/// Sets up a basic client and returns a basic account and a faucet account. -pub async fn setup_wallet_and_faucet( - client: &mut TestClient, - account_visibility: AccountType, - keystore: &FilesystemKeyStore, - auth_scheme: AuthSchemeId, -) -> Result<(Account, Account)> { - let (faucet_account, _) = - insert_new_fungible_faucet_unfunded(client, account_visibility, keystore, auth_scheme) - .await - .with_context(|| "failed to insert new fungible faucet account")?; +// ASSERTION HELPERS +// ================================================================================================ - let (basic_account, ..) = - insert_new_wallet_unfunded(client, account_visibility, keystore, auth_scheme) +impl TestClient { + /// Asserts that the account has a single asset with the expected amount. + pub async fn assert_account_has_single_asset( + &self, + account_id: AccountId, + faucet_id: AccountId, + expected_amount: u64, + ) { + let balance = self + .account_reader(account_id) + .get_balance(faucet_id) .await - .with_context(|| "failed to insert new wallet account")?; - - // Both at once, so one funding transaction covers the pair. - client - .fund_if_needed(&[faucet_account.id(), basic_account.id()]) - .await - .with_context(|| "failed to fund and deploy the created accounts")?; - - Ok((basic_account, faucet_account)) -} + .expect("Account should have the asset"); + assert_eq!(balance, AssetAmount::new(expected_amount).unwrap()); + } -/// Mints a note from `faucet_account_id` for `basic_account_id` and returns the executed -/// transaction ID and the note with [`MINT_AMOUNT`] units of the corresponding fungible asset. -pub async fn mint_note( - client: &mut TestClient, - basic_account_id: AccountId, - faucet_account_id: AccountId, - note_type: NoteType, -) -> (TransactionId, Note) { - // Create a Mint Tx for MINT_AMOUNT units of our fungible asset - let fungible_asset = FungibleAsset::new(faucet_account_id, MINT_AMOUNT).unwrap(); - info!(faucet_id = %faucet_account_id, target_id = %basic_account_id, amount = MINT_AMOUNT, "Minting asset"); - let tx_request = TransactionRequestBuilder::new() - .build_mint_fungible_asset(fungible_asset, basic_account_id, note_type, client.rng()) - .unwrap(); - let tx_id = - Box::pin(client.submit_new_transaction(fungible_asset.faucet_id(), tx_request.clone())) - .await + /// Tries to consume the note and asserts that the expected error is returned. + pub async fn assert_note_cannot_be_consumed_twice( + &mut self, + consuming_account_id: AccountId, + note_to_consume: Note, + ) { + // Check that we can't consume the P2ID note again + info!(note_id = %note_to_consume.id(), account_id = %consuming_account_id, "Attempting double-consume (expecting failure)"); + + // Double-spend error expected to be received since we are consuming the same note + let tx_request = TransactionRequestBuilder::new() + .build_consume_notes(vec![note_to_consume.clone()]) .unwrap(); - let note = tx_request.expected_output_own_notes().pop().unwrap(); - info!(tx_id = %tx_id, note_id = %note.id(), "Mint transaction submitted"); - (tx_id, note) -} - -/// Executes a transaction that consumes the provided notes and returns the transaction ID. This -/// assumes the notes contain assets. -pub async fn consume_notes( - client: &mut TestClient, - account_id: AccountId, - input_notes: &[Note], -) -> TransactionId { - let note_ids: Vec<_> = input_notes.iter().map(|n| n.id().to_string()).collect(); - info!(account_id = %account_id, note_ids = %note_ids.join(", "), "Consuming notes"); - let tx_request = TransactionRequestBuilder::new() - .build_consume_notes(input_notes.to_vec()) - .unwrap(); - let tx_id = Box::pin(client.submit_new_transaction(account_id, tx_request)).await.unwrap(); - info!(tx_id = %tx_id, "Consume transaction submitted"); - tx_id + match self.submit_new_transaction(consuming_account_id, tx_request).await { + Err(ClientError::TransactionRequestError( + TransactionRequestError::InputNoteAlreadyConsumed(_), + )) => {}, + Ok(_) => panic!("Double-spend error: Note should not be consumable!"), + err => { + panic!("Unexpected error {:?} for note ID: {}", err, note_to_consume.id().to_hex()) + }, + } + } } -/// Asserts that the account has a single asset with the expected amount. -pub async fn assert_account_has_single_asset( - client: &TestClient, - account_id: AccountId, - faucet_id: AccountId, - expected_amount: u64, -) { - let balance = client - .account_reader(account_id) - .get_balance(faucet_id) - .await - .expect("Account should have the asset"); - assert_eq!(balance, AssetAmount::new(expected_amount).unwrap()); -} +// CONSTANTS +// ================================================================================================ -/// Tries to consume the note and asserts that the expected error is returned. -pub async fn assert_note_cannot_be_consumed_twice( - client: &mut TestClient, - consuming_account_id: AccountId, - note_to_consume: Note, -) { - // Check that we can't consume the P2ID note again - info!(note_id = %note_to_consume.id(), account_id = %consuming_account_id, "Attempting double-consume (expecting failure)"); - - // Double-spend error expected to be received since we are consuming the same note - let tx_request = TransactionRequestBuilder::new() - .build_consume_notes(vec![note_to_consume.clone()]) - .unwrap(); - - match Box::pin(client.submit_new_transaction(consuming_account_id, tx_request)).await { - Err(ClientError::TransactionRequestError( - TransactionRequestError::InputNoteAlreadyConsumed(_), - )) => {}, - Ok(_) => panic!("Double-spend error: Note should not be consumable!"), - err => panic!("Unexpected error {:?} for note ID: {}", err, note_to_consume.id().to_hex()), - } -} +pub const ACCOUNT_ID_REGULAR: u128 = ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE; -/// Creates a transaction request that mints assets for each `target_id` account. -pub fn mint_multiple_fungible_asset( - asset: FungibleAsset, - target_id: &[AccountId], - note_type: NoteType, - rng: &mut impl FeltRng, -) -> TransactionRequest { - let notes = target_id - .iter() - .map(|account_id| { - P2idNote::builder() - .sender(asset.faucet_id()) - .target(*account_id) - .asset(asset) - .note_type(note_type) - .generate_serial_number(rng) - .build() - .expect("note creation failed") - .into() - }) - .collect::>(); - - TransactionRequestBuilder::new().own_output_notes(notes).build().unwrap() -} +/// Constant that represents the number of blocks until the p2id can be recalled. If this value is +/// too low, some tests might fail due to expected recall failures not happening. +pub const RECALL_HEIGHT_DELTA: u32 = 50; -/// Executes a transaction and consumes the resulting unauthenticated notes immediately without -/// waiting for the first transaction to be committed. -pub async fn execute_tx_and_consume_output_notes( - tx_request: TransactionRequest, - client: &mut TestClient, - executor: AccountId, - consumer: AccountId, -) -> TransactionId { - let output_notes = tx_request - .expected_output_own_notes() - .into_iter() - .map(|note| (note, None::)) - .collect::)>>(); - - Box::pin(client.submit_new_transaction(executor, tx_request)).await.unwrap(); - - let tx_request = TransactionRequestBuilder::new().input_notes(output_notes).build().unwrap(); - Box::pin(client.submit_new_transaction(consumer, tx_request)).await.unwrap() -} +pub const MINT_AMOUNT: u64 = 1000; +pub const TRANSFER_AMOUNT: u64 = 59; -/// Mints assets for the target account and consumes them immediately without waiting for the first -/// transaction to be committed. -pub async fn mint_and_consume( - client: &mut TestClient, - basic_account_id: AccountId, - faucet_account_id: AccountId, - note_type: NoteType, -) -> TransactionId { - info!( - faucet_id = %faucet_account_id, - target_id = %basic_account_id, - amount = MINT_AMOUNT, - "Minting and consuming asset" - ); - let tx_request = TransactionRequestBuilder::new() - .build_mint_fungible_asset( - FungibleAsset::new(faucet_account_id, MINT_AMOUNT).unwrap(), - basic_account_id, - note_type, - client.rng(), - ) - .unwrap(); - - let tx_id = Box::pin(execute_tx_and_consume_output_notes( - tx_request, - client, - faucet_account_id, - basic_account_id, - )) - .await; - info!(tx_id = %tx_id, "Mint-and-consume transaction submitted"); - tx_id -} +// UTILITIES +// ================================================================================================ -/// Creates and inserts an account with custom code as a component into the client. -pub async fn insert_account_with_custom_component( - client: &mut TestClient, - custom_code: &str, - storage_slots: Vec, - visibility: AccountType, - keystore: &FilesystemKeyStore, -) -> Result<(Account, AuthSecretKey)> { - let component_code = CodeBuilder::default() - .compile_component_code("custom::component", custom_code) - .map_err(|err| ClientError::TransactionRequestError(err.into()))?; - let custom_component = AccountComponent::new( - component_code, - storage_slots, - AccountComponentMetadata::new("miden::testing::custom_component"), - ) - .map_err(ClientError::AccountError)?; - - let mut init_seed = [0u8; 32]; - client.rng().fill_bytes(&mut init_seed); - - let key_pair = AuthSecretKey::new_falcon512_poseidon2_with_rng(client.rng()); - let pub_key = key_pair.public_key(); - - let account = AccountBuilder::new(init_seed) - .account_type(visibility) - .with_component(AuthSingleSig::new(Approver::new( - pub_key.to_commitment(), - AuthSchemeId::Falcon512Poseidon2, - ))) - .with_component(BasicWallet) - .with_component(custom_component) - .build_with_schema_commitment() - .map_err(ClientError::AccountError)?; - - keystore.add_key(&key_pair, account.id()).await.unwrap(); - client.add_account(&account, false).await?; - - client.fund_if_needed(&[account.id()]).await?; - - Ok((account, key_pair)) +pub fn create_test_store_path() -> PathBuf { + let mut temp_file = temp_dir(); + temp_file.push(format!("{}.sqlite3", Uuid::new_v4())); + temp_file } diff --git a/crates/rust-client/src/test_utils/fee.rs b/crates/rust-client/src/test_utils/fee.rs index e810654f3a..b06daff7e1 100644 --- a/crates/rust-client/src/test_utils/fee.rs +++ b/crates/rust-client/src/test_utils/fee.rs @@ -11,7 +11,7 @@ use miden_protocol::Felt; use miden_protocol::account::AccountId; use miden_protocol::block::BlockNumber; -use super::common::{TestClient, wait_for_tx}; +use super::common::TestClient; use crate::note::Note; use crate::transaction::{TransactionId, TransactionRequestBuilder}; @@ -135,7 +135,7 @@ impl TestClient { /// deploys and funding notes in its own sync. async fn wait_for_deploys(&mut self, tx_ids: &[(AccountId, TransactionId)]) -> Result<()> { for (account_id, tx_id) in tx_ids.iter().copied() { - wait_for_tx(self, tx_id).await.with_context(|| { + self.wait_for_tx(tx_id).await.with_context(|| { format!("the deploy transaction of account {account_id} never committed") })?; } diff --git a/crates/testing/miden-client-tests/Cargo.toml b/crates/testing/miden-client-tests/Cargo.toml index 2d33807245..b49f6ec6dc 100644 --- a/crates/testing/miden-client-tests/Cargo.toml +++ b/crates/testing/miden-client-tests/Cargo.toml @@ -6,6 +6,7 @@ rust-version.workspace = true version.workspace = true [dev-dependencies] +anyhow = { workspace = true } miden-client = { features = ["dap", "std", "testing"], workspace = true } miden-client-sqlite-store = { workspace = true } miden-debug = { workspace = true } diff --git a/crates/testing/miden-client-tests/src/tests.rs b/crates/testing/miden-client-tests/src/tests.rs index 9cad8f9c9e..8202785f4d 100644 --- a/crates/testing/miden-client-tests/src/tests.rs +++ b/crates/testing/miden-client-tests/src/tests.rs @@ -10,13 +10,7 @@ use miden_client::ClientError; use miden_client::account::{Address, AddressInterface}; use miden_client::address::RoutingParameters; use miden_client::assembly::CodeBuilder; -use miden_client::auth::{ - AuthSchemeId, - AuthSecretKey, - AuthSingleSig, - PublicKeyCommitment, - RPO_FALCON_SCHEME_ID, -}; +use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig, PublicKeyCommitment}; use miden_client::builder::ClientBuilder; use miden_client::keystore::{FilesystemKeyStore, Keystore}; use miden_client::note::{BlockNumber, NetworkAccountTarget, NoteExecutionHint}; @@ -37,19 +31,12 @@ use miden_client::store::{ use miden_client::sync::{NoteTagRecord, NoteTagSource}; use miden_client::testing::common::{ ACCOUNT_ID_REGULAR, + AccountSetup, MINT_AMOUNT, RECALL_HEIGHT_DELTA, TRANSFER_AMOUNT, TestClient, - assert_account_has_single_asset, - assert_note_cannot_be_consumed_twice, - consume_notes, create_test_store_path, - execute_failing_tx, - mint_and_consume, - mint_note, - setup_two_wallets_and_faucet, - setup_wallet_and_faucet, }; use miden_client::testing::mock::{MockClient, MockRpcApi}; use miden_client::transaction::{ @@ -159,9 +146,9 @@ const OVERSIZE_THRESHOLD: usize = 5; #[tokio::test] async fn input_notes_round_trip() { // generate test client with a random store name - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; - insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + client.insert_wallet(AccountType::Private).await.unwrap(); // generate test data let available_notes = rpc_api.get_public_available_notes(); @@ -197,7 +184,7 @@ async fn input_notes_round_trip() { #[tokio::test] async fn get_input_note() { // generate test client with a random store name - let (mut client, rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Get note from mocked RPC backend since any note works here let original_note = rpc_api.get_available_notes()[0].note().unwrap().clone(); @@ -224,19 +211,15 @@ async fn get_input_note() { } type InsertAccountFuture<'client> = - Pin> + 'client>>; + Pin> + 'client>>; async fn assert_wallet_insertion(insert_fn: F) where - F: for<'client> FnOnce( - &'client mut TestClient, - AccountType, - &'client FilesystemKeyStore, - ) -> InsertAccountFuture<'client>, + F: for<'client> FnOnce(&'client mut TestClient, AccountType) -> InsertAccountFuture<'client>, { - let (mut client, _rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; - let account = insert_fn(&mut client, AccountType::Private, &keystore) + let account = insert_fn(&mut client, AccountType::Private) .await .expect("account insertion should succeed"); @@ -259,15 +242,11 @@ where async fn assert_faucet_insertion(insert_fn: F) where - F: for<'client> FnOnce( - &'client mut TestClient, - AccountType, - &'client FilesystemKeyStore, - ) -> InsertAccountFuture<'client>, + F: for<'client> FnOnce(&'client mut TestClient, AccountType) -> InsertAccountFuture<'client>, { - let (mut client, _rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; - let account = insert_fn(&mut client, AccountType::Private, &keystore) + let account = insert_fn(&mut client, AccountType::Private) .await .expect("account insertion should succeed"); @@ -290,32 +269,26 @@ where #[tokio::test] async fn insert_basic_account() { - assert_wallet_insertion(|client, visibility, keystore| { - Box::pin(insert_new_wallet(client, visibility, keystore)) - }) - .await; + assert_wallet_insertion(|client, visibility| Box::pin(client.insert_wallet(visibility))).await; } #[tokio::test] async fn insert_ecdsa_account() { - assert_wallet_insertion(|client, visibility, keystore| { - Box::pin(insert_new_ecdsa_wallet(client, visibility, keystore)) + assert_wallet_insertion(|client, visibility| { + Box::pin(insert_new_ecdsa_wallet(client, visibility)) }) .await; } #[tokio::test] async fn insert_faucet_account() { - assert_faucet_insertion(|client, visibility, keystore| { - Box::pin(insert_new_fungible_faucet(client, visibility, keystore)) - }) - .await; + assert_faucet_insertion(|client, visibility| Box::pin(client.insert_faucet(visibility))).await; } #[tokio::test] async fn insert_ecdsa_faucet_account() { - assert_faucet_insertion(|client, visibility, keystore| { - Box::pin(insert_new_ecdsa_fungible_faucet(client, visibility, keystore)) + assert_faucet_insertion(|client, visibility| { + Box::pin(insert_new_ecdsa_fungible_faucet(client, visibility)) }) .await; } @@ -323,7 +296,7 @@ async fn insert_ecdsa_faucet_account() { #[tokio::test] async fn insert_same_account_twice_fails() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, @@ -340,7 +313,7 @@ async fn insert_same_account_twice_fails() { #[tokio::test] async fn account_code() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_REGULAR_PRIVATE_ACCOUNT_UPDATABLE_CODE, @@ -365,7 +338,7 @@ async fn account_code() { #[tokio::test] async fn get_account_by_id() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_REGULAR_PUBLIC_ACCOUNT_UPDATABLE_CODE, @@ -392,7 +365,7 @@ async fn get_account_by_id() { #[tokio::test] async fn sync_state() { // generate test client with a random store name - let (mut client, rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Import first mockchain note as expected let expected_notes = rpc_api @@ -437,13 +410,13 @@ async fn sync_state() { #[tokio::test] async fn sync_state_mmr() { - let (builder, rpc_api, keystore) = Box::pin(create_test_client_builder()).await; + let (builder, rpc_api) = Box::pin(create_test_client_builder()).await; let mut client = TestClient::from(builder.irrelevant_block_prune_interval(None).build().await.unwrap()); client.ensure_genesis_in_place().await.unwrap(); // Import note and create wallet so that synced notes do not get discarded (due to being // irrelevant) - insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + client.insert_wallet(AccountType::Private).await.unwrap(); // Import only public notes let notes = rpc_api @@ -527,11 +500,11 @@ async fn sync_state_mmr() { /// still have its header and MMR path authenticated before it is omitted from storage. #[tokio::test] async fn sync_state_rejects_tampered_path_for_same_sync_consumed_note() { - let (builder, rpc_api, keystore) = Box::pin(create_test_client_builder()).await; + let (builder, rpc_api) = Box::pin(create_test_client_builder()).await; let mut client = TestClient::from(builder.irrelevant_block_prune_interval(None).build().await.unwrap()); client.ensure_genesis_in_place().await.unwrap(); - insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + client.insert_wallet(AccountType::Private).await.unwrap(); let notes = rpc_api .get_public_available_notes() @@ -562,13 +535,13 @@ async fn sync_state_rejects_tampered_path_for_same_sync_consumed_note() { #[tokio::test] async fn sync_state_mmr_with_in_memory_cache() { - let (builder, rpc_api, keystore) = Box::pin(create_test_client_builder()).await; + let (builder, rpc_api) = Box::pin(create_test_client_builder()).await; let mut client = TestClient::from(builder.cache_partial_mmr_in_memory(true).build().await.unwrap()); client.ensure_genesis_in_place().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + client.insert_wallet(AccountType::Private).await.unwrap(); // First sync populates the cache. client.sync_state().await.unwrap(); @@ -591,12 +564,12 @@ async fn sync_state_mmr_with_in_memory_cache() { /// store-backed MMR rather than the stale cache. #[tokio::test] async fn stale_cached_partial_mmr_is_rebuilt_from_store() { - let (builder, rpc_api, keystore) = Box::pin(create_test_client_builder()).await; + let (builder, rpc_api) = Box::pin(create_test_client_builder()).await; let mut client = TestClient::from(builder.cache_partial_mmr_in_memory(true).build().await.unwrap()); client.ensure_genesis_in_place().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + client.insert_wallet(AccountType::Private).await.unwrap(); // Import the mock chain's public notes so a block becomes tracked after sync. let notes: Vec = rpc_api @@ -683,7 +656,7 @@ async fn sync_persists_auth_nodes_for_skipped_blocks() { } // Set up the mock chain (blocks 0-5, notes in blocks 1 and 4) - let (_client, rpc_api, _) = Box::pin(create_test_client()).await; + let (_client, rpc_api) = Box::pin(create_test_client()).await; // Build a PartialMmr starting from an empty forest with the genesis block tracked. Tracking // genesis is critical: it means the MMR must produce authentication nodes for genesis whenever @@ -760,7 +733,7 @@ async fn sync_state_no_redundant_get_account_calls() { } // Set up the mock chain (blocks 0-5, account modified in blocks 1, 4, 5) - let (_client, rpc_api, _) = Box::pin(create_test_client()).await; + let (_client, rpc_api) = Box::pin(create_test_client()).await; // Find the public account ID from the mock chain's proven blocks let account_id = { @@ -810,7 +783,7 @@ async fn sync_state_no_redundant_get_account_calls() { #[tokio::test] async fn sync_state_tags() { // generate test client with a random store name - let (mut client, rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Import first mockchain note as expected let expected_notes = rpc_api.get_available_notes(); @@ -840,7 +813,7 @@ async fn sync_state_tags() { #[tokio::test] async fn get_latest_block_header_tracks_sync_height() { - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; client.sync_state().await.unwrap(); @@ -855,7 +828,7 @@ async fn get_latest_block_header_tracks_sync_height() { #[tokio::test] async fn tags() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; // Assert that the store gets created with the tag 0 (used for notes consumable by any account) assert!(client.get_note_tags().await.unwrap().is_empty()); @@ -892,12 +865,10 @@ async fn tags() { #[tokio::test] async fn mint_transaction() { // generate test client with a random store name - let (mut client, _rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; // Faucet account generation - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); @@ -923,7 +894,7 @@ async fn mint_transaction() { #[tokio::test] async fn import_note_validation() { // generate test client - let (mut client, rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // generate deterministic test data let available_notes = rpc_api.get_available_notes(); @@ -997,13 +968,11 @@ async fn import_note_validation() { #[tokio::test] async fn transaction_request_expiration() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; + let (mut client, _) = Box::pin(create_test_client()).await; client.sync_state().await.unwrap(); let current_height = client.get_sync_height().await.unwrap(); - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let transaction_request = TransactionRequestBuilder::new() .expiration_delta(5) @@ -1028,15 +997,13 @@ async fn transaction_request_expiration() { #[tokio::test] async fn import_processing_note_returns_error() { // generate test client with a random store name - let (mut client, _rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; client.sync_state().await.unwrap(); - let account = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + let account = client.insert_wallet(AccountType::Private).await.unwrap(); // Faucet account generation - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); // Test submitting a mint transaction let transaction_request = TransactionRequestBuilder::new() @@ -1081,13 +1048,16 @@ async fn import_processing_note_returns_error() { // Re-enable once the standards send-notes script handles zero-asset notes. #[tokio::test] async fn note_without_asset() { - let (mut client, _rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) + // A faucet with no wallet component, so the zero-asset note below goes through the faucet + // interface instead of being accepted by a wallet component's send path. + let (faucet, _) = client + .insert_account(AccountSetup::faucet(AccountType::Private).without_basic_wallet_component()) .await .unwrap(); - let wallet = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + let wallet = client.insert_wallet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); @@ -1168,21 +1138,15 @@ async fn note_without_asset() { #[tokio::test] async fn swap_note_with_zero_asset() { - let (mut client, _rpc_api, keystore) = Box::pin(create_test_client()).await; - - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; - let wallet = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); // A swap exchanges the offered asset for the requested one, and filling it emits a P2ID payback // carrying the requested asset, so neither side may be zero. - let other_faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let other_faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let zero_asset = Asset::Fungible(FungibleAsset::new(faucet.id(), 0).unwrap()); let some_asset = Asset::Fungible(FungibleAsset::new(other_faucet.id(), 100).unwrap()); @@ -1240,10 +1204,10 @@ async fn swap_note_with_zero_asset() { #[tokio::test] async fn execute_program() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; + let (mut client, _) = Box::pin(create_test_client()).await; let _ = client.sync_state().await.unwrap(); - let wallet = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + let wallet = client.insert_wallet(AccountType::Private).await.unwrap(); let code = " use miden::core::sys @@ -1279,11 +1243,9 @@ async fn execute_program() { #[tokio::test] async fn real_note_roundtrip() { - let (mut client, mock_rpc_api, keystore) = Box::pin(create_test_client()).await; - let wallet = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; + let wallet = client.insert_wallet(AccountType::Private).await.unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -1330,12 +1292,9 @@ async fn real_note_roundtrip() { #[tokio::test] async fn added_notes() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; - let faucet_account_header = - insert_new_fungible_faucet(&mut client, AccountType::Private, &authenticator) - .await - .unwrap(); + let faucet_account_header = client.insert_faucet(AccountType::Private).await.unwrap(); // Mint some asset for an account not tracked by the client. It should not be stored as an input // note afterwards since it is not being tracked by the client @@ -1363,28 +1322,26 @@ async fn added_notes() { #[tokio::test] async fn p2id_transfer() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - assert_account_has_single_asset(&client, from_account_id, faucet_account_id, MINT_AMOUNT).await; + client + .assert_account_has_single_asset(from_account_id, faucet_account_id, MINT_AMOUNT) + .await; // Do a transfer from first account to second account let asset = FungibleAsset::new(faucet_account_id, TRANSFER_AMOUNT).unwrap(); @@ -1469,12 +1426,9 @@ async fn p2id_transfer() { .unwrap(); assert_eq!(to_balance, AssetAmount::new(TRANSFER_AMOUNT).unwrap()); - assert_note_cannot_be_consumed_twice( - &mut client, - to_account_id, - notes[0].clone().try_into().unwrap(), - ) - .await; + client + .assert_note_cannot_be_consumed_twice(to_account_id, notes[0].clone().try_into().unwrap()) + .await; } #[tokio::test] @@ -1811,24 +1765,20 @@ async fn irrelevant_block_pruning_disabled_when_interval_is_none() { #[tokio::test] async fn p2id_transfer_failing_not_enough_balance() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -1846,42 +1796,37 @@ async fn p2id_transfer_failing_not_enough_balance() { client.rng(), ) .unwrap(); - execute_failing_tx( - &mut client, - from_account_id, - tx_request, - ClientError::AssetError( - miden_protocol::errors::AssetError::FungibleAssetAmountNotSufficient { - minuend: MINT_AMOUNT, - subtrahend: MINT_AMOUNT + 1, - }, - ), - ) - .await; + client + .execute_failing_tx( + from_account_id, + tx_request, + ClientError::AssetError( + miden_protocol::errors::AssetError::FungibleAssetAmountNotSufficient { + minuend: MINT_AMOUNT, + subtrahend: MINT_AMOUNT + 1, + }, + ), + ) + .await; } #[tokio::test] #[allow(clippy::too_many_lines)] async fn p2ide_transfer_consumed_by_target() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - let note = mint_note(&mut client, from_account_id, faucet_account_id, NoteType::Private) + let note = client + .mint_note(from_account_id, faucet_account_id, NoteType::Private) .await + .unwrap() .1; mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -1892,11 +1837,16 @@ async fn p2ide_transfer_consumed_by_target() { InputNoteState::Committed { .. } )); - consume_notes(&mut client, from_account_id, core::slice::from_ref(¬e)).await; + client + .consume_notes(from_account_id, core::slice::from_ref(¬e)) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - assert_account_has_single_asset(&client, from_account_id, faucet_account_id, MINT_AMOUNT).await; + client + .assert_account_has_single_asset(from_account_id, faucet_account_id, MINT_AMOUNT) + .await; // Check that the note is consumed by the target account let input_note = client.get_input_note(note.id()).await.unwrap().unwrap(); @@ -1986,29 +1936,25 @@ async fn p2ide_transfer_consumed_by_target() { (to_account_balance + AssetAmount::new(TRANSFER_AMOUNT).unwrap()).unwrap() ); - assert_note_cannot_be_consumed_twice(&mut client, to_account_id, note).await; + client.assert_note_cannot_be_consumed_twice(to_account_id, note).await; } #[tokio::test] async fn p2ide_transfer_consumed_by_sender() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2098,34 +2044,27 @@ async fn p2ide_transfer_consumed_by_sender() { assert_eq!(to_balance, AssetAmount::ZERO); // Check that the target can't consume the note anymore - assert_note_cannot_be_consumed_twice( - &mut client, - to_account_id, - notes[0].clone().try_into().unwrap(), - ) - .await; + client + .assert_note_cannot_be_consumed_twice(to_account_id, notes[0].clone().try_into().unwrap()) + .await; } #[tokio::test] async fn p2ide_timelocked() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // First Mint necessary token - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Public).await; + client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Public) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2196,17 +2135,10 @@ async fn p2ide_timelocked() { #[tokio::test] async fn get_consumable_notes() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); @@ -2216,8 +2148,10 @@ async fn get_consumable_notes() { assert!(Box::pin(client.get_consumable_notes(None)).await.unwrap().is_empty()); // First Mint necessary token - let note = mint_note(&mut client, from_account_id, faucet_account_id, NoteType::Private) + let note = client + .mint_note(from_account_id, faucet_account_id, NoteType::Private) .await + .unwrap() .1; mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2237,7 +2171,7 @@ async fn get_consumable_notes() { .is_empty() ); - consume_notes(&mut client, from_account_id, &[note]).await; + client.consume_notes(from_account_id, &[note]).await.unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2367,16 +2301,10 @@ async fn note_screening_reports_only_the_account_bound_by_the_note() { const NOTE_COUNT: usize = 3; - let (mut client, _mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, _mock_rpc_api) = Box::pin(create_test_client()).await; - let (first_wallet, _second_wallet, faucet) = setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (first_wallet, _second_wallet, faucet) = + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let target = first_wallet.id(); let faucet_id = faucet.id(); @@ -2441,16 +2369,10 @@ async fn note_screening_reports_only_the_account_bound_by_the_note() { async fn execution_input_cache_matches_uncached_reads() { use miden_client::testing::{ClientDataStore, DataStore}; - let (mut client, _mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, _mock_rpc_api) = Box::pin(create_test_client()).await; - let (first_wallet, second_wallet, _faucet) = setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (first_wallet, second_wallet, _faucet) = + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let first = first_wallet.id(); let second = second_wallet.id(); @@ -2481,16 +2403,10 @@ async fn execution_input_cache_matches_uncached_reads() { #[tokio::test] async fn get_output_notes() { - let (mut client, mock_rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let _ = client.sync_state().await.unwrap(); - let (first_regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (first_regular_account, faucet_account_header) = + client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let faucet_account_id = faucet_account_header.id(); @@ -2500,8 +2416,10 @@ async fn get_output_notes() { assert!(client.get_output_notes(NoteFilter::All).await.unwrap().is_empty()); // First Mint necessary token - let note = mint_note(&mut client, from_account_id, faucet_account_id, NoteType::Private) + let note = client + .mint_note(from_account_id, faucet_account_id, NoteType::Private) .await + .unwrap() .1; mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2510,7 +2428,7 @@ async fn get_output_notes() { assert!(client.get_output_notes(NoteFilter::Consumed).await.unwrap().is_empty()); assert!(!client.get_output_notes(NoteFilter::All).await.unwrap().is_empty()); - consume_notes(&mut client, from_account_id, &[note]).await; + client.consume_notes(from_account_id, &[note]).await.unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2551,7 +2469,7 @@ async fn get_output_notes() { #[tokio::test] #[allow(clippy::too_many_lines)] async fn account_rollback() { - let (builder, mock_rpc_api, authenticator) = Box::pin(create_test_client_builder()).await; + let (builder, mock_rpc_api) = Box::pin(create_test_client_builder()).await; let mut client = TestClient::from(builder.tx_discard_delta(Some(TX_DISCARD_DELTA)).build().await.unwrap()); @@ -2559,24 +2477,22 @@ async fn account_rollback() { client.sync_state().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - let (regular_account, faucet_account_header) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (regular_account, faucet_account_header) = + client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let account_id = regular_account.id(); let faucet_account_id = faucet_account_header.id(); // Mint a note - let note = mint_note(&mut client, account_id, faucet_account_id, NoteType::Private).await.1; + let note = client + .mint_note(account_id, faucet_account_id, NoteType::Private) + .await + .unwrap() + .1; mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - consume_notes(&mut client, account_id, &[note]).await; + client.consume_notes(account_id, &[note]).await.unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2720,21 +2636,23 @@ async fn account_rollback() { #[tokio::test] async fn subsequent_discarded_transactions() { - let (mut client, mock_rpc_api, keystore) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; let (regular_account, faucet_account_header) = - setup_wallet_and_faucet(&mut client, AccountType::Public, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + client.setup_wallet_and_faucet(AccountType::Public).await.unwrap(); let account_id = regular_account.id(); let faucet_account_id = faucet_account_header.id(); - let note = mint_note(&mut client, account_id, faucet_account_id, NoteType::Private).await.1; + let note = client + .mint_note(account_id, faucet_account_id, NoteType::Private) + .await + .unwrap() + .1; mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - consume_notes(&mut client, account_id, &[note]).await; + client.consume_notes(account_id, &[note]).await.unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -2822,11 +2740,9 @@ async fn subsequent_discarded_transactions() { #[tokio::test] async fn missing_recipient_digest() { - let (mut client, _, keystore) = create_test_client().await; + let (mut client, _) = create_test_client().await; - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let dummy_recipient = NoteRecipient::new( Word::default(), @@ -2857,21 +2773,15 @@ async fn missing_recipient_digest() { #[tokio::test] async fn input_note_checks() { - let (mut client, mock_rpc_api, authenticator) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; - let (wallet, faucet) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let mut mint_notes = vec![]; for _ in 0..5 { - mint_notes.push(mint_note(&mut client, wallet.id(), faucet.id(), NoteType::Public).await.1); + mint_notes + .push(client.mint_note(wallet.id(), faucet.id(), NoteType::Public).await.unwrap().1); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); } @@ -2942,20 +2852,16 @@ async fn swap_chain_test() { // 6. Finally, it asserts that the last wallet now owns the asset originally held by the first // wallet, verifying that the whole swap chain was successful. - let (mut client, mock_rpc_api, keystore) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; // Generate a few account pairs with a fungible asset that can be used for swaps. let mut account_pairs = vec![]; for _ in 0..3 { - let (wallet, faucet) = setup_wallet_and_faucet( - &mut client, - AccountType::Private, - &keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); - mint_and_consume(&mut client, wallet.id(), faucet.id(), NoteType::Private).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + client + .mint_and_consume(wallet.id(), faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -3021,21 +2927,21 @@ async fn swap_chain_test() { #[tokio::test] async fn swap_public_payback_test() { - let (mut client, mock_rpc_api, keystore) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; - let (wallet_a, faucet_a) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); - mint_and_consume(&mut client, wallet_a.id(), faucet_a.id(), NoteType::Private).await; + let (wallet_a, faucet_a) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + client + .mint_and_consume(wallet_a.id(), faucet_a.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - let (wallet_b, faucet_b) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); - mint_and_consume(&mut client, wallet_b.id(), faucet_b.id(), NoteType::Private).await; + let (wallet_b, faucet_b) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + client + .mint_and_consume(wallet_b.id(), faucet_b.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -3094,26 +3000,26 @@ async fn swap_public_payback_test() { /// from sync operations and never receiving their inclusion proofs. #[tokio::test] async fn partial_output_note_receives_inclusion_proof_after_sync() { - let (mut client, mock_rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; client.sync_state().await.unwrap(); // Set up two wallet-faucet pairs for the swap scenario. - let (wallet_a, faucet_a) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (wallet_a, faucet_a) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); - let (wallet_b, faucet_b) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (wallet_b, faucet_b) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); // Mint and consume tokens so each wallet holds assets for the swap. - mint_and_consume(&mut client, wallet_a.id(), faucet_a.id(), NoteType::Private).await; + client + .mint_and_consume(wallet_a.id(), faucet_a.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - mint_and_consume(&mut client, wallet_b.id(), faucet_b.id(), NoteType::Private).await; + client + .mint_and_consume(wallet_b.id(), faucet_b.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -3207,25 +3113,27 @@ async fn pswap_fill_test( #[case] expected_payout: u64, #[case] expected_remainder: Option<(u64, u64)>, ) { - let (mut client, mock_rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; // Setup Alice's wallet and the ETH faucet (offered asset). let (alice_wallet, eth_faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); // Setup Bob's wallet and the USD faucet (requested asset). let (bob_wallet, usd_faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); - mint_and_consume(&mut client, alice_wallet.id(), eth_faucet.id(), NoteType::Private).await; + client + .mint_and_consume(alice_wallet.id(), eth_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); - mint_and_consume(&mut client, bob_wallet.id(), usd_faucet.id(), NoteType::Private).await; + client + .mint_and_consume(bob_wallet.id(), usd_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -3328,19 +3236,18 @@ async fn pswap_cancel_test() { // 1. Alice creates a PSWAP note (balance decreases). // 2. Alice cancels the PSWAP note (balance restored). - let (mut client, mock_rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; let (alice_wallet, eth_faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let (_bob_wallet, usd_faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); - mint_and_consume(&mut client, alice_wallet.id(), eth_faucet.id(), NoteType::Private).await; + client + .mint_and_consume(alice_wallet.id(), eth_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -3403,7 +3310,7 @@ async fn pswap_cancel_test() { // same chain while keeping its own store and keystore. This is what lets the PSWAP lineage test // model Alice and Bob as two genuinely separate clients (as they are in production), rather than // two accounts colocated on one store. -async fn create_pswap_test_client(mock_rpc_api: &MockRpcApi) -> (TestClient, FilesystemKeyStore) { +async fn create_pswap_test_client(mock_rpc_api: &MockRpcApi) -> TestClient { let mut seed_rng = rand::rng(); let coin_seed: [u64; 4] = seed_rng.random(); let rng = RandomCoin::new(coin_seed.map(|v| Felt::new_unchecked(v >> 1)).into()); @@ -3422,7 +3329,7 @@ async fn create_pswap_test_client(mock_rpc_api: &MockRpcApi) -> (TestClient, Fil client.ensure_genesis_in_place().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - (TestClient::from(client), keystore) + TestClient::from(client) } /// Two-client mock-chain test: Alice creates a PSWAP, Bob partial-fills, Alice reclaims the @@ -3437,33 +3344,26 @@ async fn create_pswap_test_client(mock_rpc_api: &MockRpcApi) -> (TestClient, Fil async fn pswap_chain_tracking_test(#[case] note_type: NoteType) { // One shared chain, two independent clients. let mock_rpc_api = MockRpcApi::new(Box::pin(create_prebuilt_mock_chain()).await); - let (mut alice_client, alice_keystore) = create_pswap_test_client(&mock_rpc_api).await; - let (mut bob_client, bob_keystore) = create_pswap_test_client(&mock_rpc_api).await; - - let (alice_wallet, btc_faucet) = setup_wallet_and_faucet( - &mut alice_client, - AccountType::Private, - &alice_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let mut alice_client = create_pswap_test_client(&mock_rpc_api).await; + let mut bob_client = create_pswap_test_client(&mock_rpc_api).await; - let (bob_wallet, eth_faucet) = setup_wallet_and_faucet( - &mut bob_client, - AccountType::Private, - &bob_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (alice_wallet, btc_faucet) = + alice_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); - mint_and_consume(&mut alice_client, alice_wallet.id(), btc_faucet.id(), NoteType::Private) - .await; + let (bob_wallet, eth_faucet) = + bob_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + + alice_client + .mint_and_consume(alice_wallet.id(), btc_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); - mint_and_consume(&mut bob_client, bob_wallet.id(), eth_faucet.id(), NoteType::Private).await; + bob_client + .mint_and_consume(bob_wallet.id(), eth_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); bob_client.sync_state().await.unwrap(); @@ -3578,7 +3478,7 @@ async fn pswap_chain_tracking_test(#[case] note_type: NoteType) { let payback_notes: Vec = consumable.iter().map(|(record, _)| record.try_into().unwrap()).collect(); assert_eq!(payback_notes.len(), 1, "Alice should hold one ETH payback note"); - consume_notes(&mut alice_client, alice_wallet.id(), &payback_notes).await; + alice_client.consume_notes(alice_wallet.id(), &payback_notes).await.unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); @@ -3614,31 +3514,24 @@ async fn pswap_chain_tracking_test(#[case] note_type: NoteType) { #[tokio::test] async fn pswap_full_fill_chain_tracking_test(#[case] note_type: NoteType) { let mock_rpc_api = MockRpcApi::new(Box::pin(create_prebuilt_mock_chain()).await); - let (mut alice_client, alice_keystore) = create_pswap_test_client(&mock_rpc_api).await; - let (mut bob_client, bob_keystore) = create_pswap_test_client(&mock_rpc_api).await; - - let (alice_wallet, btc_faucet) = setup_wallet_and_faucet( - &mut alice_client, - AccountType::Private, - &alice_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); - let (bob_wallet, eth_faucet) = setup_wallet_and_faucet( - &mut bob_client, - AccountType::Private, - &bob_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let mut alice_client = create_pswap_test_client(&mock_rpc_api).await; + let mut bob_client = create_pswap_test_client(&mock_rpc_api).await; - mint_and_consume(&mut alice_client, alice_wallet.id(), btc_faucet.id(), NoteType::Private) - .await; + let (alice_wallet, btc_faucet) = + alice_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + let (bob_wallet, eth_faucet) = + bob_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + + alice_client + .mint_and_consume(alice_wallet.id(), btc_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); - mint_and_consume(&mut bob_client, bob_wallet.id(), eth_faucet.id(), NoteType::Private).await; + bob_client + .mint_and_consume(bob_wallet.id(), eth_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); bob_client.sync_state().await.unwrap(); @@ -3706,7 +3599,7 @@ async fn pswap_full_fill_chain_tracking_test(#[case] note_type: NoteType) { let payback_notes: Vec = consumable.iter().map(|(record, _)| record.try_into().unwrap()).collect(); assert_eq!(payback_notes.len(), 1, "Alice should hold one ETH payback note"); - consume_notes(&mut alice_client, alice_wallet.id(), &payback_notes).await; + alice_client.consume_notes(alice_wallet.id(), &payback_notes).await.unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); @@ -3741,31 +3634,24 @@ async fn pswap_full_fill_chain_tracking_test(#[case] note_type: NoteType) { async fn pswap_multi_round_chain_tracking_test() { let note_type = NoteType::Public; let mock_rpc_api = MockRpcApi::new(Box::pin(create_prebuilt_mock_chain()).await); - let (mut alice_client, alice_keystore) = create_pswap_test_client(&mock_rpc_api).await; - let (mut bob_client, bob_keystore) = create_pswap_test_client(&mock_rpc_api).await; - - let (alice_wallet, btc_faucet) = setup_wallet_and_faucet( - &mut alice_client, - AccountType::Private, - &alice_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); - let (bob_wallet, eth_faucet) = setup_wallet_and_faucet( - &mut bob_client, - AccountType::Private, - &bob_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let mut alice_client = create_pswap_test_client(&mock_rpc_api).await; + let mut bob_client = create_pswap_test_client(&mock_rpc_api).await; - mint_and_consume(&mut alice_client, alice_wallet.id(), btc_faucet.id(), NoteType::Private) - .await; + let (alice_wallet, btc_faucet) = + alice_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + let (bob_wallet, eth_faucet) = + bob_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + + alice_client + .mint_and_consume(alice_wallet.id(), btc_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); - mint_and_consume(&mut bob_client, bob_wallet.id(), eth_faucet.id(), NoteType::Private).await; + bob_client + .mint_and_consume(bob_wallet.id(), eth_faucet.id(), NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); bob_client.sync_state().await.unwrap(); @@ -3871,7 +3757,7 @@ async fn pswap_multi_round_chain_tracking_test() { let payback_notes: Vec = consumable.iter().map(|(record, _)| record.try_into().unwrap()).collect(); assert_eq!(payback_notes.len(), 2, "Alice should hold two ETH paybacks (one per round)"); - consume_notes(&mut alice_client, alice_wallet.id(), &payback_notes).await; + alice_client.consume_notes(alice_wallet.id(), &payback_notes).await.unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); @@ -3914,27 +3800,18 @@ async fn pswap_multi_round_chain_tracking_test() { #[tokio::test] async fn pswap_asset_pair_tag_isolated_per_order() { let mock_rpc_api = MockRpcApi::new(Box::pin(create_prebuilt_mock_chain()).await); - let (mut alice_client, alice_keystore) = create_pswap_test_client(&mock_rpc_api).await; + let mut alice_client = create_pswap_test_client(&mock_rpc_api).await; - let (alice_wallet, btc_faucet) = setup_wallet_and_faucet( - &mut alice_client, - AccountType::Private, - &alice_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (alice_wallet, btc_faucet) = + alice_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); // Second faucet only — its `_throwaway_wallet` is unused; we just need the ETH faucet id. - let (_throwaway_wallet, eth_faucet) = setup_wallet_and_faucet( - &mut alice_client, - AccountType::Private, - &alice_keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (_throwaway_wallet, eth_faucet) = + alice_client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); - mint_and_consume(&mut alice_client, alice_wallet.id(), btc_faucet.id(), NoteType::Public).await; + alice_client + .mint_and_consume(alice_wallet.id(), btc_faucet.id(), NoteType::Public) + .await + .unwrap(); mock_rpc_api.prove_block(); alice_client.sync_state().await.unwrap(); @@ -4009,7 +3886,7 @@ async fn pswap_asset_pair_tag_isolated_per_order() { #[tokio::test] async fn empty_storage_map() { - let (mut client, _, keystore) = create_test_client().await; + let (mut client, _) = create_test_client().await; let storage_map = StorageMap::new(); @@ -4049,7 +3926,7 @@ async fn empty_storage_map() { let account_id = account.id(); - keystore.add_key(&key_pair, account_id).await.unwrap(); + client.keystore().add_key(&key_pair, account_id).await.unwrap(); client.add_account(&account, false).await.unwrap(); @@ -4104,7 +3981,7 @@ const BUMP_MAP_CODE: &str = r#" #[allow(clippy::too_many_lines)] #[tokio::test] async fn storage_and_vault_proofs() { - let (mut client, mock_rpc_api, keystore) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; // Create an account that will accept assets (basic wallet) but also that has a storage map that // can be updated. @@ -4164,7 +4041,7 @@ async fn storage_and_vault_proofs() { .build_with_schema_commitment() .unwrap(); - keystore.add_key(&key_pair, account.id()).await.unwrap(); + client.keystore().add_key(&key_pair, account.id()).await.unwrap(); client.add_account(&account, false).await.unwrap(); @@ -4172,14 +4049,14 @@ async fn storage_and_vault_proofs() { // Add assets and modify storage map multiple times for _ in 0..5 { - let faucet_account = - insert_new_fungible_faucet(&mut client, AccountType::Public, &keystore) - .await - .unwrap(); + let faucet_account = client.insert_faucet(AccountType::Public).await.unwrap(); let faucet_account_id = faucet_account.id(); - mint_and_consume(&mut client, account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -4246,7 +4123,7 @@ async fn storage_and_vault_proofs() { #[tokio::test] async fn account_addresses_basic_wallet() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, @@ -4271,7 +4148,7 @@ async fn account_addresses_basic_wallet() { #[tokio::test] async fn account_addresses_non_basic_wallet() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock_non_fungible_faucet(ACCOUNT_ID_PUBLIC_NON_FUNGIBLE_FAUCET); @@ -4289,7 +4166,7 @@ async fn account_addresses_non_basic_wallet() { #[tokio::test] async fn account_add_address_after_creation() { // generate test client with a random store name - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET_2, @@ -4396,22 +4273,16 @@ async fn import_watched_account_by_id_rejects_already_tracked_native_account() { // Re-enable once the standards send-notes script handles zero-asset notes. #[tokio::test] async fn consume_note_with_custom_script() { - let (mut client, mock_rpc_api, keystore) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; - let (sender_account, receiver_account, faucet_account) = setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &keystore, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let (sender_account, receiver_account, faucet_account) = + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let sender_id = sender_account.id(); let receiver_id = receiver_account.id(); let faucet_id = faucet_account.id(); - mint_and_consume(&mut client, sender_id, faucet_id, NoteType::Private).await; + client.mint_and_consume(sender_id, faucet_id, NoteType::Private).await.unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -4957,13 +4828,13 @@ async fn prepare_offline_bootstrap_inserts_mock_chain_genesis() { // HELPERS // ================================================================================================ -pub async fn create_test_client() -> (TestClient, MockRpcApi, FilesystemKeyStore) { - let (builder, rpc_api, keystore) = Box::pin(create_test_client_builder()).await; +pub async fn create_test_client() -> (TestClient, MockRpcApi) { + let (builder, rpc_api) = Box::pin(create_test_client_builder()).await; let mut client = TestClient::from(builder.build().await.unwrap()); client.ensure_genesis_in_place().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - (client, rpc_api, keystore) + (client, rpc_api) } /// Gives a mock-backed client the transaction encryption key that submission seals against. @@ -4986,8 +4857,7 @@ pub async fn seed_mock_transaction_encryption_key(client: &mut MockClient (ClientBuilder, MockRpcApi, FilesystemKeyStore) { +pub async fn create_test_client_builder() -> (ClientBuilder, MockRpcApi) { let mut rng = rand::rng(); let coin_seed: [u64; 4] = rng.random(); @@ -5003,10 +4873,10 @@ pub async fn create_test_client_builder() .rpc(arc_rpc_api) .rng(Box::new(rng)) .sqlite_store(create_test_store_path()) - .authenticator(Arc::new(keystore.clone())) + .authenticator(Arc::new(keystore)) .tx_discard_delta(None); - (builder, rpc_api, keystore) + (builder, rpc_api) } pub async fn create_prebuilt_mock_chain() -> MockChain { @@ -5094,39 +4964,10 @@ pub async fn create_prebuilt_mock_chain() -> MockChain { mock_chain } -async fn insert_new_wallet( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, -) -> Result { - let key_pair = AuthSecretKey::new_falcon512_poseidon2_with_rng(client.rng()); - let pub_key = key_pair.public_key(); - - let mut init_seed = [0u8; 32]; - client.rng().fill_bytes(&mut init_seed); - - let account = AccountBuilder::new(init_seed) - .account_type(visibility) - .with_component(AuthSingleSig::new(Approver::new( - pub_key.to_commitment(), - AuthSchemeId::Falcon512Poseidon2, - ))) - .with_component(BasicWallet) - .build_with_schema_commitment() - .unwrap(); - - keystore.add_key(&key_pair, account.id()).await.unwrap(); - - client.add_account(&account, false).await?; - - Ok(account) -} - async fn insert_new_ecdsa_wallet( client: &mut TestClient, visibility: AccountType, - keystore: &FilesystemKeyStore, -) -> Result { +) -> anyhow::Result { let init_seed = [0u8; 32]; let mut rng = StdRng::from_seed(init_seed); @@ -5143,64 +4984,17 @@ async fn insert_new_ecdsa_wallet( .build_with_schema_commitment() .unwrap(); - keystore.add_key(&key_pair, account.id()).await.unwrap(); + client.keystore().add_key(&key_pair, account.id()).await.unwrap(); client.add_account(&account, false).await?; Ok(account) } -async fn insert_new_fungible_faucet( - client: &mut TestClient, - visibility: AccountType, - keystore: &FilesystemKeyStore, -) -> Result { - let key_pair = AuthSecretKey::new_falcon512_poseidon2_with_rng(client.rng()); - let pub_key = key_pair.public_key(); - - // we need to use an initial seed to create the wallet account - let mut init_seed = [0u8; 32]; - client.rng().fill_bytes(&mut init_seed); - - let symbol = TokenSymbol::new("TEST").unwrap(); - let name = TokenName::new(&symbol.to_string()).expect("token symbol is a valid token name"); - let max_supply = 9_999_999_u64; - let faucet = FungibleFaucet::builder() - .name(name) - .symbol(symbol) - .decimals(10) - .max_supply(AssetAmount::new(max_supply).unwrap()) - .build() - .unwrap(); - // Only mint/burn policies — see test_utils/common.rs::insert_new_fungible_faucet for the reason - // transfer policies are intentionally omitted. - let policy_manager = TokenPolicyManager::builder() - .active_mint_policy(MintPolicy::allow_all()) - .active_burn_policy(BurnPolicy::allow_all()) - .build(); - - let account = AccountBuilder::new(init_seed) - .account_type(visibility) - .with_component(AuthSingleSig::new(Approver::new( - pub_key.to_commitment(), - AuthSchemeId::Falcon512Poseidon2, - ))) - .with_component(faucet) - .with_components(policy_manager) - .build_with_schema_commitment() - .unwrap(); - - keystore.add_key(&key_pair, account.id()).await.unwrap(); - - client.add_account(&account, false).await?; - Ok(account) -} - async fn insert_new_ecdsa_fungible_faucet( client: &mut TestClient, visibility: AccountType, - keystore: &FilesystemKeyStore, -) -> Result { +) -> anyhow::Result { let init_seed = [0u8; 32]; let mut rng = StdRng::from_seed(init_seed); @@ -5221,8 +5015,8 @@ async fn insert_new_ecdsa_fungible_faucet( .max_supply(AssetAmount::new(max_supply).unwrap()) .build() .unwrap(); - // Only mint/burn policies — see test_utils/common.rs::insert_new_fungible_faucet for the reason - // transfer policies are intentionally omitted. + // Only mint/burn policies, transfer policies are intentionally omitted for the reason described + // in test_utils/common.rs where the faucet setup is built. let policy_manager = TokenPolicyManager::builder() .active_mint_policy(MintPolicy::allow_all()) .active_burn_policy(BurnPolicy::allow_all()) @@ -5239,7 +5033,7 @@ async fn insert_new_ecdsa_fungible_faucet( .build_with_schema_commitment() .unwrap(); - keystore.add_key(&key_pair, account.id()).await.unwrap(); + client.keystore().add_key(&key_pair, account.id()).await.unwrap(); client.add_account(&account, false).await?; Ok(account) @@ -5248,7 +5042,7 @@ async fn insert_new_ecdsa_fungible_faucet( #[allow(clippy::too_many_lines)] #[tokio::test] async fn storage_and_vault_proofs_ecdsa() { - let (mut client, mock_rpc_api, keystore) = create_test_client().await; + let (mut client, mock_rpc_api) = create_test_client().await; // Create an account that will accept assets (basic wallet) but also that has a storage map that // can be updated. @@ -5311,7 +5105,7 @@ async fn storage_and_vault_proofs_ecdsa() { .build_with_schema_commitment() .unwrap(); - keystore.add_key(&key_pair, account.id()).await.unwrap(); + client.keystore().add_key(&key_pair, account.id()).await.unwrap(); client.add_account(&account, false).await.unwrap(); @@ -5319,14 +5113,16 @@ async fn storage_and_vault_proofs_ecdsa() { // Add assets and modify storage map multiple times for _ in 0..5 { - let faucet_account = - insert_new_ecdsa_fungible_faucet(&mut client, AccountType::Public, &keystore) - .await - .unwrap(); + let faucet_account = insert_new_ecdsa_fungible_faucet(&mut client, AccountType::Public) + .await + .unwrap(); let faucet_account_id = faucet_account.id(); - mint_and_consume(&mut client, account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); mock_rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -5392,7 +5188,7 @@ async fn storage_and_vault_proofs_ecdsa() { #[tokio::test] async fn execute_transaction_fails_for_watched_account() { - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; // Build a faucet locally and insert it directly as watched via the store. Bypasses the public // `add_account`/`import_watched_account_by_id` paths so we don't need a mock RPC round-trip. diff --git a/crates/testing/miden-client-tests/src/tests/batch.rs b/crates/testing/miden-client-tests/src/tests/batch.rs index 7c86a97670..7a8a3f8df3 100644 --- a/crates/testing/miden-client-tests/src/tests/batch.rs +++ b/crates/testing/miden-client-tests/src/tests/batch.rs @@ -5,22 +5,13 @@ use miden_client::ClientError; use miden_client::account::{AccountBuilderSchemaCommitmentExt, AccountType}; use miden_client::assembly::CodeBuilder; use miden_client::asset::{Asset, AssetAmount, FungibleAsset}; -use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig, RPO_FALCON_SCHEME_ID}; +use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig}; use miden_client::builder::ClientBuilder; use miden_client::keystore::{FilesystemKeyStore, Keystore}; use miden_client::note::{NoteType, NoteUpdateTracker}; use miden_client::rpc::NodeRpcClient; use miden_client::store::{StoreError, TransactionFilter}; -use miden_client::testing::common::{ - MINT_AMOUNT, - TRANSFER_AMOUNT, - create_test_store_path, - insert_new_fungible_faucet, - insert_new_wallet, - mint_and_consume, - mint_note, - setup_two_wallets_and_faucet, -}; +use miden_client::testing::common::{MINT_AMOUNT, TRANSFER_AMOUNT, create_test_store_path}; use miden_client::testing::mock::MockRpcApi; use miden_client::transaction::{ BatchBuilderError, @@ -55,7 +46,7 @@ use crate::tests::{create_test_client, seed_mock_transaction_encryption_key}; /// enough to exercise the trait wiring. #[tokio::test] async fn submit_proven_batch_returns_chain_tip() { - let (_client, rpc_api, _keystore) = Box::pin(create_test_client()).await; + let (_client, rpc_api) = Box::pin(create_test_client()).await; // Pick the first account recorded in the prebuilt mock chain. let account_id = rpc_api @@ -102,7 +93,7 @@ async fn submit_proven_batch_returns_chain_tip() { /// local store. #[tokio::test] async fn batch_builder_submits_two_txs_on_one_account() { - let (mut client, rpc_api, _keystore) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Pick the first tracked account in the mock chain (same pattern as the existing test above). let account_id = rpc_api @@ -273,17 +264,10 @@ async fn apply_transaction_batch_rolls_back_on_mid_batch_failure() { /// against in-batch (`2 * MINT_AMOUNT`). #[tokio::test] async fn batch_builder_push_succeeds_when_balance_depends_on_prior_push() { - let (mut client, rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let to_account_id = second_regular_account.id(); @@ -291,13 +275,18 @@ async fn batch_builder_push_succeeds_when_balance_depends_on_prior_push() { // Pre-batch: give A `MINT_AMOUNT` (also gets A on-chain so its first batch-tx delta is partial, // not full-state). - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); // Mint a second note worth `MINT_AMOUNT` for A — left UNCONSUMED, so push 1 can claim it. - let (_mint_tx_id, second_note) = - mint_note(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + let (_mint_tx_id, second_note) = client + .mint_note(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -431,7 +420,7 @@ fn batch_bump_map_request() -> TransactionRequestBuilder { #[allow(clippy::too_many_lines)] #[tokio::test] async fn batch_builder_serves_witnesses_for_state_untouched_by_prior_push() { - let (mut client, rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // The executing account: a wallet that also owns a storage map. let map_component = batch_bump_map_component(); @@ -454,34 +443,17 @@ async fn batch_builder_serves_witnesses_for_state_untouched_by_prior_push() { .unwrap(); let from_id = from_account.id(); - authenticator.add_key(&key_pair, from_id).await.unwrap(); + client.keystore().add_key(&key_pair, from_id).await.unwrap(); client.add_account(&from_account, false).await.unwrap(); - let (to_account, _) = - insert_new_wallet(&mut client, AccountType::Private, &authenticator, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let to_account = client.insert_wallet(AccountType::Private).await.unwrap(); let to_id = to_account.id(); - let (consumed_faucet, _) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let consumed_faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let consumed_faucet_id = consumed_faucet.id(); // A second, independent faucet whose balance `from` holds but never touches in push 1. - let (held_faucet, _) = insert_new_fungible_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + let held_faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let held_faucet_id = held_faucet.id(); client.sync_state().await.unwrap(); @@ -489,13 +461,16 @@ async fn batch_builder_serves_witnesses_for_state_untouched_by_prior_push() { // 0, so batch pushes run against committed partial state instead of the full-state new-account // path). The balance is part of the committed vault but is NOT touched by the first in-batch // transaction. - mint_and_consume(&mut client, from_id, held_faucet_id, NoteType::Private).await; + client + .mint_and_consume(from_id, held_faucet_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); // Mint a note from the consumed faucet for `from`, left UNCONSUMED so push 1 can claim it. let (_mint_tx_id, consumed_note) = - mint_note(&mut client, from_id, consumed_faucet_id, NoteType::Private).await; + client.mint_note(from_id, consumed_faucet_id, NoteType::Private).await.unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -536,7 +511,7 @@ async fn batch_builder_serves_witnesses_for_state_untouched_by_prior_push() { /// Verify that submitting an empty batch (no pushes) returns `BatchBuilderError::Empty`. #[tokio::test] async fn batch_builder_empty_submit_returns_empty_error() { - let (mut client, rpc_api, _keystore) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Pick the first tracked account in the mock chain. let _account_id = rpc_api @@ -567,29 +542,27 @@ async fn batch_builder_empty_submit_returns_empty_error() { /// leaves the batch intact so it still submits the transaction pushed before it. #[tokio::test] async fn batch_builder_push_rejects_duplicate_input_note() { - let (mut client, rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, _second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let from_account_id = first_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // Get the account on-chain so its first batch-tx delta is partial, not full-state. - mint_and_consume(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); // Mint a single note for `from_account` — left UNCONSUMED. - let (_mint_tx_id, note) = - mint_note(&mut client, from_account_id, faucet_account_id, NoteType::Private).await; + let (_mint_tx_id, note) = client + .mint_note(from_account_id, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -694,7 +667,7 @@ async fn batch_builder_submits_txs_across_multiple_accounts() { /// with `ClientError::AccountDataNotFound`. #[tokio::test] async fn batch_builder_push_for_unknown_account_returns_error() { - let (mut client, rpc_api, _keystore) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Pick an account that EXISTS on the mock chain but is NOT registered with the client store (we // never call `client.add_account` for it). @@ -730,17 +703,10 @@ async fn batch_builder_push_for_unknown_account_returns_error() { /// `TransactionRequest::expected_output_own_notes` before pushing. #[tokio::test] async fn batch_builder_cross_account_note_flow() { - let (mut client, rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let account_id_a = first_regular_account.id(); let account_id_b = second_regular_account.id(); @@ -748,10 +714,16 @@ async fn batch_builder_cross_account_note_flow() { // Pre-batch: get both A and B on-chain (each with MINT_AMOUNT) so their first batch-tx deltas // are partial, not full-state — the batch apply path requires partial deltas. - mint_and_consume(&mut client, account_id_a, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(account_id_a, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); - mint_and_consume(&mut client, account_id_b, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(account_id_b, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); @@ -819,31 +791,29 @@ async fn batch_builder_cross_account_note_flow() { /// `DuplicateInputNote(note_id)`. #[tokio::test] async fn batch_builder_dedup_rejects_duplicate_input_note_across_accounts() { - let (mut client, rpc_api, authenticator) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; let (first_regular_account, second_regular_account, faucet_account_header) = - setup_two_wallets_and_faucet( - &mut client, - AccountType::Private, - &authenticator, - RPO_FALCON_SCHEME_ID, - ) - .await - .unwrap(); + client.setup_two_wallets_and_faucet(AccountType::Private).await.unwrap(); let account_id_a = first_regular_account.id(); let account_id_b = second_regular_account.id(); let faucet_account_id = faucet_account_header.id(); // Get account A on-chain so its first batch-tx delta is partial, not full-state. - mint_and_consume(&mut client, account_id_a, faucet_account_id, NoteType::Private).await; + client + .mint_and_consume(account_id_a, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); // Mint a single shared note (created with A's recipient, but we'll try to feed the same note to // both pushes). - let (_mint_tx_id, note) = - mint_note(&mut client, account_id_a, faucet_account_id, NoteType::Private).await; + let (_mint_tx_id, note) = client + .mint_note(account_id_a, faucet_account_id, NoteType::Private) + .await + .unwrap(); rpc_api.prove_block(); client.sync_state().await.unwrap(); diff --git a/crates/testing/miden-client-tests/src/tests/store.rs b/crates/testing/miden-client-tests/src/tests/store.rs index d3439bc6d5..ba57b4ace7 100644 --- a/crates/testing/miden-client-tests/src/tests/store.rs +++ b/crates/testing/miden-client-tests/src/tests/store.rs @@ -32,7 +32,7 @@ use miden_standards::account::wallets::BasicWallet; use miden_standards::testing::mock_account::MockAccountExt; use rand::Rng; -use crate::tests::{create_test_client, insert_new_fungible_faucet, insert_new_wallet}; +use crate::tests::create_test_client; fn create_account_data(account_id: u128) -> AccountFile { let account = Account::mock( @@ -83,7 +83,7 @@ pub fn create_ecdsa_initial_accounts_data() -> Vec { #[tokio::test] pub async fn try_add_account() { // generate test client - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, @@ -108,7 +108,7 @@ pub async fn try_add_account() { #[tokio::test] pub async fn try_add_ecdsa_account() { // generate test client - let (mut client, _rpc_api, _) = Box::pin(create_test_client()).await; + let (mut client, _rpc_api) = Box::pin(create_test_client()).await; let account = Account::mock( ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET, @@ -195,12 +195,10 @@ async fn load_ecdsa_accounts_test() { /// 5. Account state must be intact at nonce 2 #[tokio::test] async fn prune_account_history_with_pending_transaction() { - let (mut client, mock_rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; - let wallet = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let wallet = client.insert_wallet(AccountType::Private).await.unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let faucet_id = faucet.id(); mock_rpc_api.prove_block(); @@ -289,10 +287,7 @@ const SLOTS_COMPONENT_MASM: &str = r#" /// Builds a custom account with three value slots (A, B, C) and MASM procedures to modify slots A /// and B individually. Returns the account and its ID. -async fn build_three_slot_account( - client: &mut crate::tests::TestClient, - keystore: &miden_client::keystore::FilesystemKeyStore, -) -> AccountId { +async fn build_three_slot_account(client: &mut crate::tests::TestClient) -> AccountId { let a_name = StorageSlotName::new(SLOT_A_NAME).unwrap(); let b_name = StorageSlotName::new(SLOT_B_NAME).unwrap(); let c_name = StorageSlotName::new(SLOT_C_NAME).unwrap(); @@ -339,7 +334,7 @@ async fn build_three_slot_account( .unwrap(); let account_id = account.id(); - keystore.add_key(&key_pair, account_id).await.unwrap(); + client.keystore().add_key(&key_pair, account_id).await.unwrap(); client.add_account(&account, false).await.unwrap(); account_id @@ -377,9 +372,9 @@ fn compile_slot_tx_script( /// pruning cannot lose it. #[tokio::test] async fn prune_preserves_unmodified_storage_slots() { - let (mut client, mock_rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, mock_rpc_api) = Box::pin(create_test_client()).await; - let account_id = build_three_slot_account(&mut client, &keystore).await; + let account_id = build_three_slot_account(&mut client).await; let source_manager = client.source_manager(); let tx_script_set_a = compile_slot_tx_script("set_a_to_10", source_manager.clone()); diff --git a/crates/testing/miden-client-tests/src/tests/transaction.rs b/crates/testing/miden-client-tests/src/tests/transaction.rs index e27da35e4d..68c120353e 100644 --- a/crates/testing/miden-client-tests/src/tests/transaction.rs +++ b/crates/testing/miden-client-tests/src/tests/transaction.rs @@ -5,7 +5,7 @@ use std::net::TcpListener; use std::time::Duration; use miden_client::assembly::CodeBuilder; -use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig, RPO_FALCON_SCHEME_ID}; +use miden_client::auth::{AuthSchemeId, AuthSecretKey, AuthSingleSig}; use miden_client::keystore::Keystore; use miden_client::note::{Note, P2idNote}; use miden_client::rpc::{GrpcError, RpcEndpoint, RpcError}; @@ -49,15 +49,12 @@ use miden_standards::account::auth::Approver; use miden_standards::account::wallets::BasicWallet; use super::PaymentNoteDescription; -use crate::tests::{create_test_client, setup_wallet_and_faucet}; +use crate::tests::create_test_client; #[tokio::test] async fn dap_transaction_execution_records_replay_data() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; - let (wallet, _) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, _) = Box::pin(create_test_client()).await; + let (wallet, _) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let listener = TcpListener::bind("127.0.0.1:0").unwrap(); let listen_addr = listener.local_addr().unwrap(); @@ -110,7 +107,7 @@ async fn dap_transaction_execution_records_replay_data() { #[tokio::test] async fn transaction_creates_two_notes() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; + let (mut client, _) = Box::pin(create_test_client()).await; let asset_1: Asset = FungibleAsset::new(ACCOUNT_ID_PRIVATE_FUNGIBLE_FAUCET.try_into().unwrap(), 123) .unwrap() @@ -133,7 +130,7 @@ async fn transaction_creates_two_notes() { .build_existing() .unwrap(); - keystore.add_key(&secret_key, account.id()).await.unwrap(); + client.keystore().add_key(&secret_key, account.id()).await.unwrap(); client.add_account(&account, false).await.unwrap(); client.sync_state().await.unwrap(); @@ -165,11 +162,8 @@ async fn transaction_creates_two_notes() { #[tokio::test] async fn transaction_error_reports_source_line() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; - let (wallet, _) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, _) = Box::pin(create_test_client()).await; + let (wallet, _) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let failing_script = client .code_builder() @@ -206,11 +200,8 @@ async fn transaction_error_reports_source_line() { /// unchanged — no orphaned input notes and no orphaned output note scripts. #[tokio::test] async fn execute_transaction_failure_leaves_store_unchanged() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, _) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); // A note targeting the wallet that is not tracked by the store. Passing it as a request input // note is what would trigger an input-note write during preparation. @@ -331,15 +322,9 @@ impl TransactionProver for SwapProver { /// requested transaction had gone through. #[tokio::test] async fn submit_rejects_proven_transaction_unrelated_to_the_request() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet_a) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); - let (_, faucet_b) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, _) = Box::pin(create_test_client()).await; + let (wallet, faucet_a) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); + let (_, faucet_b) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); // Transaction B: a mint from a different faucet, executed and proven on its own. This is what // the rogue prover hands back regardless of what it is asked to prove. @@ -426,11 +411,8 @@ async fn submit_rejects_proven_transaction_unrelated_to_the_request() { /// be retried with a different (local) prover. #[tokio::test] async fn prover_fallback_pattern_allows_retry_with_different_prover() { - let (mut client, _, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, _) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); let fungible_asset = FungibleAsset::new(faucet.id(), 100).unwrap(); @@ -466,7 +448,7 @@ async fn prover_fallback_pattern_allows_retry_with_different_prover() { /// account is not specified in the `TransactionRequestBuilder`. #[tokio::test] async fn lazy_foreign_account_loading() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; // Setup: Create and deploy a public foreign account with a storage map. let map_key: Word = @@ -515,7 +497,7 @@ async fn lazy_foreign_account_loading() { .unwrap(); let foreign_account_id = foreign_account.id(); - keystore.add_key(&secret_key, foreign_account_id).await.unwrap(); + client.keystore().add_key(&secret_key, foreign_account_id).await.unwrap(); client.add_account(&foreign_account, false).await.unwrap(); // Deploy the foreign account (sets nonce from 0 to 1). @@ -529,9 +511,7 @@ async fn lazy_foreign_account_loading() { client.sync_state().await.unwrap(); // Setup: Create a local wallet to execute the FPI transaction. - let local_wallet = super::insert_new_wallet(&mut client, AccountType::Public, &keystore) - .await - .unwrap(); + let local_wallet = client.insert_wallet(AccountType::Public).await.unwrap(); // Execute FPI transaction WITHOUT specifying foreign account. @@ -587,11 +567,8 @@ async fn lazy_foreign_account_loading() { #[tokio::test] async fn chain_anchor_pins_execution_to_an_older_reference_block() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, rpc_api) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); let transaction_request = TransactionRequestBuilder::new() @@ -644,11 +621,8 @@ async fn chain_anchor_pins_execution_to_an_older_reference_block() { #[tokio::test] async fn chain_anchor_for_request_tracks_consumed_note_blocks() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, rpc_api) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); // Mint a note for the wallet and let it commit on chain. @@ -723,11 +697,8 @@ async fn chain_anchor_for_request_tracks_consumed_note_blocks() { #[tokio::test] async fn chain_anchor_execution_ignoring_invalid_input_notes() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, rpc_api) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); // Mint a note for the wallet and let it commit on chain. @@ -770,11 +741,8 @@ async fn chain_anchor_execution_ignoring_invalid_input_notes() { #[tokio::test] async fn chain_anchor_untracked_note_block_fails_with_typed_error() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, rpc_api) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); let mint_request = TransactionRequestBuilder::new() @@ -830,11 +798,8 @@ async fn chain_anchor_untracked_note_block_fails_with_typed_error() { /// transaction. #[tokio::test] async fn chain_anchor_execution_rejects_an_already_expired_transaction() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, rpc_api) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); // The shortest expiry the builder accepts, so a handful of blocks is enough to pass it. @@ -904,11 +869,8 @@ async fn chain_anchor_execution_rejects_an_already_expired_transaction() { /// authenticate it. Consuming a note created in that very block exercises this. #[tokio::test] async fn chain_anchor_for_request_handles_a_note_created_in_the_reference_block() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; - let (wallet, faucet) = - setup_wallet_and_faucet(&mut client, AccountType::Private, &keystore, RPO_FALCON_SCHEME_ID) - .await - .unwrap(); + let (mut client, rpc_api) = Box::pin(create_test_client()).await; + let (wallet, faucet) = client.setup_wallet_and_faucet(AccountType::Private).await.unwrap(); client.sync_state().await.unwrap(); let mint_request = TransactionRequestBuilder::new() @@ -955,7 +917,7 @@ async fn chain_anchor_for_request_handles_a_note_created_in_the_reference_block( /// `rpc::errors`. #[tokio::test] async fn indeterminate_submission_is_retryable_with_the_attached_payload() { - let (mut client, rpc_api, keystore) = Box::pin(create_test_client()).await; + let (mut client, rpc_api) = Box::pin(create_test_client()).await; let secret_key = AuthSecretKey::new_falcon512_poseidon2(); let account = AccountBuilder::new(Default::default()) @@ -966,7 +928,7 @@ async fn indeterminate_submission_is_retryable_with_the_attached_payload() { ))) .build_existing() .unwrap(); - keystore.add_key(&secret_key, account.id()).await.unwrap(); + client.keystore().add_key(&secret_key, account.id()).await.unwrap(); client.add_account(&account, false).await.unwrap(); client.sync_state().await.unwrap(); diff --git a/crates/testing/miden-client-tests/src/tests/transport.rs b/crates/testing/miden-client-tests/src/tests/transport.rs index fbc7d552df..31ee8dc95e 100644 --- a/crates/testing/miden-client-tests/src/tests/transport.rs +++ b/crates/testing/miden-client-tests/src/tests/transport.rs @@ -43,12 +43,7 @@ use miden_standards::testing::note::NoteBuilder; use miden_testing::{Auth, MockChainBuilder, MockTransactionInput}; use rand::RngExt; -use crate::tests::{ - create_test_client_builder, - insert_new_fungible_faucet, - insert_new_wallet, - seed_mock_transaction_encryption_key, -}; +use crate::tests::{create_test_client_builder, seed_mock_transaction_encryption_key}; #[tokio::test] async fn transport_basic() { @@ -873,13 +868,11 @@ async fn fetch_private_notes_without_floor_falls_back_to_lookback_window() { #[tokio::test] async fn transport_delivery_of_processing_note_does_not_wedge_sync_state() { let mock_node = Arc::new(RwLock::new(MockNoteTransportNode::new())); - let (mut client, keystore) = Box::pin(create_test_client_transport(mock_node.clone())).await; + let mut client = Box::pin(create_test_client_transport(mock_node.clone())).await; client.sync_state().await.unwrap(); - let account = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); - let faucet = insert_new_fungible_faucet(&mut client, AccountType::Private, &keystore) - .await - .unwrap(); + let account = client.insert_wallet(AccountType::Private).await.unwrap(); + let faucet = client.insert_faucet(AccountType::Private).await.unwrap(); let mint_request = TransactionRequestBuilder::new() .build_mint_fungible_asset( @@ -1057,8 +1050,8 @@ fn dummy_asset() -> Asset { pub async fn create_test_client_transport( mock_node: Arc>, -) -> (TestClient, FilesystemKeyStore) { - let (builder, _, keystore) = create_test_client_builder().await; +) -> TestClient { + let (builder, _) = create_test_client_builder().await; let transport_client = MockNoteTransportApi::new(mock_node); let builder_w_transport = builder.note_transport(Arc::new(transport_client)); @@ -1066,32 +1059,32 @@ pub async fn create_test_client_transport( client.ensure_genesis_in_place().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - (client, keystore) + client } pub async fn create_test_user_transport( mock_node: Arc>, ) -> (TestClient, Account) { - let (mut client, keystore) = Box::pin(create_test_client_transport(mock_node.clone())).await; - let account = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + let mut client = Box::pin(create_test_client_transport(mock_node.clone())).await; + let account = client.insert_wallet(AccountType::Private).await.unwrap(); (client, account) } pub async fn create_test_client_with_transport( transport: Arc, -) -> (TestClient, FilesystemKeyStore) { - let (builder, _, keystore) = create_test_client_builder().await; +) -> TestClient { + let (builder, _) = create_test_client_builder().await; let mut client = TestClient::from(builder.note_transport(transport).build().await.unwrap()); client.ensure_genesis_in_place().await.unwrap(); seed_mock_transaction_encryption_key(&mut client).await; - (client, keystore) + client } pub async fn create_test_user_with_transport( transport: Arc, ) -> (TestClient, Account) { - let (mut client, keystore) = Box::pin(create_test_client_with_transport(transport)).await; - let account = insert_new_wallet(&mut client, AccountType::Private, &keystore).await.unwrap(); + let mut client = Box::pin(create_test_client_with_transport(transport)).await; + let account = client.insert_wallet(AccountType::Private).await.unwrap(); (client, account) }