From 675e845237d95b863e8c1bd60a95a41c76140c7c Mon Sep 17 00:00:00 2001 From: Pravdyvy Date: Fri, 10 Jul 2026 16:21:03 +0300 Subject: [PATCH] fix(wallet_ffi): wallet_ffi fix --- .../src/bin/run_hello_world.rs | 4 +- .../src/bin/run_hello_world_private.rs | 2 +- .../bin/run_hello_world_through_tail_call.rs | 4 +- ...n_hello_world_through_tail_call_private.rs | 2 +- .../bin/run_hello_world_with_authorization.rs | 9 +- ...uthorization_through_tail_call_with_pda.rs | 4 +- .../bin/run_hello_world_with_move_function.rs | 6 +- integration_tests/tests/bridge.rs | 2 +- integration_tests/tests/private_pda.rs | 14 +- integration_tests/tests/program_deployment.rs | 5 +- integration_tests/tests/wallet_ffi.rs | 6 +- lez/wallet-ffi/src/account.rs | 4 +- lez/wallet-ffi/src/bridge.rs | 4 +- lez/wallet-ffi/src/generic_transaction.rs | 4 +- lez/wallet-ffi/src/pinata.rs | 12 +- lez/wallet-ffi/src/program_deployment.rs | 15 +- lez/wallet-ffi/src/sync.rs | 6 +- lez/wallet-ffi/src/transfer.rs | 32 +-- lez/wallet-ffi/src/vault.rs | 10 +- lez/wallet-ffi/src/wallet.rs | 32 ++- lez/wallet-ffi/wallet_ffi.h | 10 +- lez/wallet/src/lib.rs | 4 + lez/wallet/src/multi_client.rs | 263 +++++++++++++----- test_fixtures/src/config.rs | 10 +- test_fixtures/src/lib.rs | 9 +- test_fixtures/src/setup.rs | 5 +- 26 files changed, 323 insertions(+), 155 deletions(-) diff --git a/examples/program_deployment/src/bin/run_hello_world.rs b/examples/program_deployment/src/bin/run_hello_world.rs index 3f2223a1..a43bd7f1 100644 --- a/examples/program_deployment/src/bin/run_hello_world.rs +++ b/examples/program_deployment/src/bin/run_hello_world.rs @@ -27,7 +27,7 @@ use wallet::WalletCore; #[tokio::main] async fn main() { // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let wallet_core = WalletCore::from_env().await.unwrap(); // Parse arguments // First argument is the path to the program binary @@ -59,7 +59,7 @@ async fn main() { // Submit the transaction let _response = wallet_core - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); diff --git a/examples/program_deployment/src/bin/run_hello_world_private.rs b/examples/program_deployment/src/bin/run_hello_world_private.rs index f6202433..3b7ca404 100644 --- a/examples/program_deployment/src/bin/run_hello_world_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_private.rs @@ -23,7 +23,7 @@ use wallet::{AccountIdentity, WalletCore}; #[tokio::main] async fn main() { // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let mut wallet_core = WalletCore::from_env().await.unwrap(); // Parse arguments // First argument is the path to the program binary diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs index 6ebba70f..18620220 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call.rs @@ -27,7 +27,7 @@ use wallet::WalletCore; #[tokio::main] async fn main() { // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let wallet_core = WalletCore::from_env().await.unwrap(); // Parse arguments // First argument is the path to the program binary @@ -55,7 +55,7 @@ async fn main() { // Submit the transaction let _response = wallet_core - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); diff --git a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs index d35e6521..5429d6f3 100644 --- a/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs +++ b/examples/program_deployment/src/bin/run_hello_world_through_tail_call_private.rs @@ -26,7 +26,7 @@ use wallet::{AccountIdentity, WalletCore}; #[tokio::main] async fn main() { // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let mut wallet_core = WalletCore::from_env().await.unwrap(); // Parse arguments // First argument is the path to the simple_tail_call program binary diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs index 0d257db2..e1f0d7d0 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization.rs @@ -29,7 +29,7 @@ use wallet::WalletCore; #[tokio::main] async fn main() { // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let mut wallet_core = WalletCore::from_env().await.unwrap(); // Parse arguments // First argument is the path to the program binary @@ -52,7 +52,8 @@ async fn main() { .storage() .key_chain() .pub_account_signing_key(account_id) - .expect("Input account should be a self owned public account"); + .expect("Input account should be a self owned public account") + .clone(); // Define the desired greeting in ASCII let greeting: Vec = vec![72, 111, 108, 97, 32, 109, 117, 110, 100, 111, 33]; @@ -63,7 +64,7 @@ async fn main() { .get_accounts_nonces(vec![account_id]) .await .expect("Node should be reachable to query account data"); - let signing_keys = [signing_key]; + let signing_keys = [&signing_key]; let message = Message::try_new(program.id(), vec![account_id], nonces, greeting).unwrap(); // Pass the signing key to sign the message. This will be used by the node // to flag the pre_state as `is_authorized` when executing the program @@ -72,7 +73,7 @@ async fn main() { // Submit the transaction let _response = wallet_core - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs index 70688cfd..9139189e 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_authorization_through_tail_call_with_pda.rs @@ -35,7 +35,7 @@ const PDA_SEED: PdaSeed = PdaSeed::new([37; 32]); #[tokio::main] async fn main() { // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let wallet_core = WalletCore::from_env().await.unwrap(); // Parse arguments // First argument is the path to the program binary @@ -57,7 +57,7 @@ async fn main() { // Submit the transaction let _response = wallet_core - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); diff --git a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs index a77fe2e6..99961b30 100644 --- a/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs +++ b/examples/program_deployment/src/bin/run_hello_world_with_move_function.rs @@ -66,7 +66,7 @@ async fn main() { let program = Program::new(bytecode.into()).unwrap(); // Initialize wallet - let wallet_core = WalletCore::from_env().unwrap(); + let mut wallet_core = WalletCore::from_env().await.unwrap(); match cli.command { Command::WritePublic { @@ -88,7 +88,7 @@ async fn main() { // Submit the transaction let _response = wallet_core - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); @@ -127,7 +127,7 @@ async fn main() { // Submit the transaction let _response = wallet_core - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::Public(tx)) .await .unwrap(); diff --git a/integration_tests/tests/bridge.rs b/integration_tests/tests/bridge.rs index 9c241ebb..5f5b268f 100644 --- a/integration_tests/tests/bridge.rs +++ b/integration_tests/tests/bridge.rs @@ -440,7 +440,7 @@ async fn bedrock_deposit_claim_and_withdraw_round_trip_succeeds() -> anyhow::Res // Now claim funds from vault back to recipient let nonces = ctx - .wallet() + .wallet_mut() .get_accounts_nonces(vec![recipient_id]) .await .context("Failed to get nonce for vault claim")?; diff --git a/integration_tests/tests/private_pda.rs b/integration_tests/tests/private_pda.rs index 0c67049f..0d74fdfe 100644 --- a/integration_tests/tests/private_pda.rs +++ b/integration_tests/tests/private_pda.rs @@ -37,7 +37,7 @@ use wallet::{AccountIdentity, WalletCore}; reason = "test helper — grouping args would obscure intent" )] async fn fund_private_pda( - wallet: &WalletCore, + wallet: &mut WalletCore, sender: AccountId, npk: NullifierPublicKey, vpk: ViewingPublicKey, @@ -91,7 +91,7 @@ async fn fund_private_pda( let tx = PrivacyPreservingTransaction::new(message, witness_set); wallet - .sequencer_client + .leader_owned() .send_transaction(LeeTransaction::PrivacyPreserving(tx)) .await .map_err(|e| anyhow::anyhow!("send transaction failed: {e}"))?; @@ -107,7 +107,7 @@ async fn fund_private_pda( reason = "test helper — grouping args would obscure intent" )] async fn spend_private_pda( - wallet: &WalletCore, + wallet: &mut WalletCore, pda_account_id: AccountId, recipient_npk: NullifierPublicKey, recipient_vpk: ViewingPublicKey, @@ -180,7 +180,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { info!("Sending to alice_pda_0 (identifier=0)"); fund_private_pda( - ctx.wallet(), + ctx.wallet_mut(), sender_0, alice_npk, alice_vpk.clone(), @@ -194,7 +194,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { info!("Sending to alice_pda_1 (identifier=1)"); fund_private_pda( - ctx.wallet(), + ctx.wallet_mut(), sender_1, alice_npk, alice_vpk.clone(), @@ -262,7 +262,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { info!("Alice spending from alice_pda_0"); spend_private_pda( - ctx.wallet(), + ctx.wallet_mut(), alice_pda_0_id, recipient_npk_0, recipient_vpk_0, @@ -275,7 +275,7 @@ async fn private_pda_family_members_receive_and_spend() -> Result<()> { info!("Alice spending from alice_pda_1"); spend_private_pda( - ctx.wallet(), + ctx.wallet_mut(), alice_pda_1_id, recipient_npk_1, recipient_vpk_1, diff --git a/integration_tests/tests/program_deployment.rs b/integration_tests/tests/program_deployment.rs index c92daeb3..e2d9294d 100644 --- a/integration_tests/tests/program_deployment.rs +++ b/integration_tests/tests/program_deployment.rs @@ -31,7 +31,10 @@ async fn deploy_and_execute_program() -> Result<()> { let account_id = new_account(&mut ctx, false, None).await?; - let nonces = ctx.wallet().get_accounts_nonces(vec![account_id]).await?; + let nonces = ctx + .wallet_mut() + .get_accounts_nonces(vec![account_id]) + .await?; let private_key = ctx .wallet() .get_account_public_signing_key(account_id) diff --git a/integration_tests/tests/wallet_ffi.rs b/integration_tests/tests/wallet_ffi.rs index 321c874d..16172e96 100644 --- a/integration_tests/tests/wallet_ffi.rs +++ b/integration_tests/tests/wallet_ffi.rs @@ -1794,7 +1794,7 @@ fn test_wallet_ffi_transfer_generic_private() -> Result<()> { #[test] fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> { - let ctx = BlockingTestContext::new()?; + let mut ctx = BlockingTestContext::new()?; let home = tempfile::tempdir()?; let FfiCreateWalletOutput { wallet: wallet_ffi_handle, @@ -1808,7 +1808,7 @@ fn test_wallet_ffi_vault_balance_and_claim_public() -> Result<()> { // Fund the owner's vault, simulating an L1 bridge deposit. ctx.block_on(|ctx| async move { - Vault(ctx.wallet()) + Vault(ctx.wallet_mut()) .send_transfer(sender, owner, amount) .await }) @@ -1894,7 +1894,7 @@ fn test_wallet_ffi_vault_balance_and_claim_private() -> Result<()> { // Fund the owner's vault. Real deposits always land via a public transfer (the bridge // program crediting the vault PDA), regardless of whether the owner is private. ctx.block_on(|ctx| async move { - Vault(ctx.wallet()) + Vault(ctx.wallet_mut()) .send_transfer(sender, owner, amount) .await }) diff --git a/lez/wallet-ffi/src/account.rs b/lez/wallet-ffi/src/account.rs index fdbfabc1..61047a66 100644 --- a/lez/wallet-ffi/src/account.rs +++ b/lez/wallet-ffi/src/account.rs @@ -323,7 +323,7 @@ pub unsafe extern "C" fn wallet_ffi_get_balance( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -389,7 +389,7 @@ pub unsafe extern "C" fn wallet_ffi_get_account_public( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); diff --git a/lez/wallet-ffi/src/bridge.rs b/lez/wallet-ffi/src/bridge.rs index fca71b1c..70cc9383 100644 --- a/lez/wallet-ffi/src/bridge.rs +++ b/lez/wallet-ffi/src/bridge.rs @@ -55,7 +55,7 @@ pub unsafe extern "C" fn wallet_ffi_bridge_withdraw( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -66,7 +66,7 @@ pub unsafe extern "C" fn wallet_ffi_bridge_withdraw( let from_id = AccountId::new(unsafe { (*from).data }); let bedrock_account_pk = unsafe { (*bedrock_account_pk).data }; - let bridge = Bridge(&wallet); + let mut bridge = Bridge(&mut wallet); match block_on(bridge.send_withdraw(from_id, amount, bedrock_account_pk)) { Ok(tx_hash) => { diff --git a/lez/wallet-ffi/src/generic_transaction.rs b/lez/wallet-ffi/src/generic_transaction.rs index 7be6ddaf..3e1873c2 100644 --- a/lez/wallet-ffi/src/generic_transaction.rs +++ b/lez/wallet-ffi/src/generic_transaction.rs @@ -237,7 +237,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_public_transaction( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -329,7 +329,7 @@ pub unsafe extern "C" fn wallet_ffi_send_generic_private_transaction( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); diff --git a/lez/wallet-ffi/src/pinata.rs b/lez/wallet-ffi/src/pinata.rs index b1fdb27a..37861657 100644 --- a/lez/wallet-ffi/src/pinata.rs +++ b/lez/wallet-ffi/src/pinata.rs @@ -60,7 +60,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -72,7 +72,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata( let winner_id = AccountId::new(unsafe { (*winner_account_id).data }); let solution = u128::from_le_bytes(unsafe { *solution }); - let pinata = Pinata(&wallet); + let mut pinata = Pinata(&mut wallet); match block_on(pinata.claim(pinata_id, winner_id, solution)) { Ok(tx_hash) => { @@ -155,7 +155,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_already_initializ return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -174,7 +174,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_already_initializ }; let proof: MembershipProof = (winner_proof_index, siblings); - let pinata = Pinata(&wallet); + let mut pinata = Pinata(&mut wallet); match block_on( pinata @@ -250,7 +250,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_not_initialized( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -262,7 +262,7 @@ pub unsafe extern "C" fn wallet_ffi_claim_pinata_private_owned_not_initialized( let winner_id = AccountId::new(unsafe { (*winner_account_id).data }); let solution = u128::from_le_bytes(unsafe { *solution }); - let pinata = Pinata(&wallet); + let mut pinata = Pinata(&mut wallet); match block_on(pinata.claim_private_owned_account(pinata_id, winner_id, solution)) { Ok((tx_hash, _shared_key)) => { diff --git a/lez/wallet-ffi/src/program_deployment.rs b/lez/wallet-ffi/src/program_deployment.rs index 2086fa5c..8d924682 100644 --- a/lez/wallet-ffi/src/program_deployment.rs +++ b/lez/wallet-ffi/src/program_deployment.rs @@ -1,9 +1,5 @@ use std::{ffi::CString, ptr, slice}; -use common::transaction::LeeTransaction; -use lee::ProgramDeploymentTransaction; -use sequencer_service_rpc::RpcClient as _; - use crate::{ block_on, error::{print_error, WalletFfiError}, @@ -50,7 +46,7 @@ pub unsafe extern "C" fn wallet_ffi_program_deployment( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -60,14 +56,7 @@ pub unsafe extern "C" fn wallet_ffi_program_deployment( let elf = unsafe { slice::from_raw_parts(elf_data, elf_size) }.to_vec(); - let message = lee::program_deployment_transaction::Message::new(elf); - let transaction = ProgramDeploymentTransaction::new(message); - - match block_on( - wallet - .sequencer_client - .send_transaction(LeeTransaction::ProgramDeployment(transaction)), - ) { + match block_on(wallet.send_program_deployment_transaction(elf)) { Ok(tx_hash) => { let tx_hash = CString::new(tx_hash.to_string()) .map_or(ptr::null_mut(), std::ffi::CString::into_raw); diff --git a/lez/wallet-ffi/src/sync.rs b/lez/wallet-ffi/src/sync.rs index 5f7a4413..7682d1be 100644 --- a/lez/wallet-ffi/src/sync.rs +++ b/lez/wallet-ffi/src/sync.rs @@ -1,7 +1,5 @@ //! Block synchronization functions. -use sequencer_service_rpc::RpcClient as _; - use crate::{ block_on, error::{print_error, WalletFfiError}, @@ -128,7 +126,7 @@ pub unsafe extern "C" fn wallet_ffi_get_current_block_height( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -136,7 +134,7 @@ pub unsafe extern "C" fn wallet_ffi_get_current_block_height( } }; - match block_on(wallet.sequencer_client.get_last_block_id()) { + match block_on(wallet.get_last_block_id()) { Ok(last_block_id) => { unsafe { *out_block_height = last_block_id; diff --git a/lez/wallet-ffi/src/transfer.rs b/lez/wallet-ffi/src/transfer.rs index 1fcd3133..33386752 100644 --- a/lez/wallet-ffi/src/transfer.rs +++ b/lez/wallet-ffi/src/transfer.rs @@ -72,7 +72,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -84,7 +84,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_public( let to_id = AccountId::new(unsafe { (*to).data }); let amount = u128::from_le_bytes(unsafe { *amount }); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.send_public_transfer( AccountIdentity::Public(from_id), @@ -164,7 +164,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -188,7 +188,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded( CliAccountMention::KeyPath, ); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.send_shielded_transfer_to_outer_account( from_mention.into_public_identity(from_id), @@ -262,7 +262,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_deshielded( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -273,7 +273,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_deshielded( let from_id = AccountId::new(unsafe { (*from).data }); let to_id = AccountId::new(unsafe { (*to).data }); let amount = u128::from_le_bytes(unsafe { *amount }); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.send_deshielded_transfer(from_id, to_id, amount)) { Ok((tx_hash, _shared_key)) => { @@ -348,7 +348,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -367,7 +367,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private( }; let to_identifier = u128::from_le_bytes(unsafe { (*to_identifier).data }); let amount = u128::from_le_bytes(unsafe { *amount }); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.send_private_transfer_to_outer_account( from_id, @@ -445,7 +445,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -461,7 +461,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_shielded_owned( CliAccountMention::KeyPath, ); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.send_shielded_transfer( from_mention.into_public_identity(from_id), @@ -536,7 +536,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private_owned( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -547,7 +547,7 @@ pub unsafe extern "C" fn wallet_ffi_transfer_private_owned( let from_id = AccountId::new(unsafe { (*from).data }); let to_id = AccountId::new(unsafe { (*to).data }); let amount = u128::from_le_bytes(unsafe { *amount }); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.send_private_transfer_to_owned_account(from_id, to_id, amount)) { Ok((tx_hash, _shared_keys)) => { @@ -608,7 +608,7 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -618,7 +618,7 @@ pub unsafe extern "C" fn wallet_ffi_register_public_account( let account_id = AccountId::new(unsafe { (*account_id).data }); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.register_account(AccountIdentity::Public(account_id))) { Ok(tx_hash) => { @@ -679,7 +679,7 @@ pub unsafe extern "C" fn wallet_ffi_register_private_account( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -688,7 +688,7 @@ pub unsafe extern "C" fn wallet_ffi_register_private_account( }; let account_id = AccountId::new(unsafe { (*account_id).data }); - let transfer = NativeTokenTransfer(&wallet); + let mut transfer = NativeTokenTransfer(&mut wallet); match block_on(transfer.register_account_private(account_id)) { Ok((tx_hash, _secret)) => { diff --git a/lez/wallet-ffi/src/vault.rs b/lez/wallet-ffi/src/vault.rs index 6db1fa66..73a24599 100644 --- a/lez/wallet-ffi/src/vault.rs +++ b/lez/wallet-ffi/src/vault.rs @@ -48,7 +48,7 @@ pub unsafe extern "C" fn wallet_ffi_get_vault_balance( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -113,7 +113,7 @@ pub unsafe extern "C" fn wallet_ffi_vault_claim( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -124,7 +124,7 @@ pub unsafe extern "C" fn wallet_ffi_vault_claim( let owner_id = AccountId::new(unsafe { (*owner).data }); let amount = u128::from_le_bytes(unsafe { *amount }); - match block_on(Vault(&wallet).send_claim(owner_id, amount)) { + match block_on(Vault(&mut wallet).send_claim(owner_id, amount)) { Ok(tx_hash) => { let tx_hash = CString::new(tx_hash.to_string()) .map_or(ptr::null_mut(), std::ffi::CString::into_raw); @@ -185,7 +185,7 @@ pub unsafe extern "C" fn wallet_ffi_vault_claim_private( return WalletFfiError::NullPointer; } - let wallet = match wrapper.core.lock() { + let mut wallet = match wrapper.core.lock() { Ok(w) => w, Err(e) => { print_error(format!("Failed to lock wallet: {e}")); @@ -196,7 +196,7 @@ pub unsafe extern "C" fn wallet_ffi_vault_claim_private( let owner_id = AccountId::new(unsafe { (*owner).data }); let amount = u128::from_le_bytes(unsafe { *amount }); - match block_on(Vault(&wallet).send_claim_private_owner(owner_id, amount)) { + match block_on(Vault(&mut wallet).send_claim_private_owner(owner_id, amount)) { Ok((tx_hash, _shared_key)) => { let tx_hash = CString::new(tx_hash.to_string()) .map_or(ptr::null_mut(), std::ffi::CString::into_raw); diff --git a/lez/wallet-ffi/src/wallet.rs b/lez/wallet-ffi/src/wallet.rs index b19aaae5..c6c58987 100644 --- a/lez/wallet-ffi/src/wallet.rs +++ b/lez/wallet-ffi/src/wallet.rs @@ -86,6 +86,7 @@ fn c_str_to_path(ptr: *const c_char, name: &str) -> Result Result FfiCreateWalletOutput { let Ok(config_path) = c_str_to_path(config_path, "config_path") else { @@ -112,7 +114,17 @@ pub unsafe extern "C" fn wallet_ffi_create_new( return FfiCreateWalletOutput::default(); }; - match WalletCore::new_init_storage(config_path, storage_path, None, &password) { + let Ok(metrics_path) = c_str_to_path(metrics_path, "metrics_path") else { + return FfiCreateWalletOutput::default(); + }; + + match block_on(WalletCore::new_init_storage( + config_path, + storage_path, + metrics_path, + None, + &password, + )) { Ok((core, mnemonic)) => { let wrapper = Box::new(WalletWrapper { core: Mutex::new(core), @@ -142,8 +154,9 @@ pub unsafe extern "C" fn wallet_ffi_create_new( /// This loads a wallet that was previously created with `wallet_ffi_create_new()`. /// /// # Parameters +/// - `handle` - Valid wallet handle /// - `config_path`: Path to the wallet configuration file (JSON) -/// - `storage_path`: Path where wallet data is stored +/// - `metrics_path`: Path to the wallet metrics file (JSON) /// /// # Returns /// - Opaque wallet handle on success @@ -151,10 +164,12 @@ pub unsafe extern "C" fn wallet_ffi_create_new( /// /// # Safety /// All string parameters must be valid null-terminated UTF-8 strings. +/// `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`. #[no_mangle] pub unsafe extern "C" fn wallet_ffi_open( config_path: *const c_char, storage_path: *const c_char, + metrics_path: *const c_char, ) -> *mut WalletHandle { let Ok(config_path) = c_str_to_path(config_path, "config_path") else { return ptr::null_mut(); @@ -164,7 +179,16 @@ pub unsafe extern "C" fn wallet_ffi_open( return ptr::null_mut(); }; - match WalletCore::new_update_chain(config_path, storage_path, None) { + let Ok(metrics_path) = c_str_to_path(metrics_path, "metrics_path") else { + return ptr::null_mut(); + }; + + match block_on(WalletCore::new_update_chain( + config_path, + storage_path, + metrics_path, + None, + )) { Ok(core) => { let wrapper = Box::new(WalletWrapper { core: Mutex::new(core), @@ -334,7 +358,7 @@ pub unsafe extern "C" fn wallet_ffi_get_sequencer_addr(handle: *mut WalletHandle } }; - let addr = wallet.config().sequencer_addr.clone().to_string(); + let addr = wallet.leader_url().to_string(); match std::ffi::CString::new(addr) { Ok(s) => s.into_raw(), diff --git a/lez/wallet-ffi/wallet_ffi.h b/lez/wallet-ffi/wallet_ffi.h index 8f15a888..e977e946 100644 --- a/lez/wallet-ffi/wallet_ffi.h +++ b/lez/wallet-ffi/wallet_ffi.h @@ -1564,6 +1564,7 @@ enum WalletFfiError wallet_ffi_vault_claim_private(struct WalletHandle *handle, * # Parameters * - `config_path`: Path to the wallet configuration file (JSON) * - `storage_path`: Path where wallet data will be stored + * - `metrics_path`: Path to the wallet metrics file (JSON) * - `password`: Password for encrypting the wallet seed * * # Returns @@ -1575,6 +1576,7 @@ enum WalletFfiError wallet_ffi_vault_claim_private(struct WalletHandle *handle, */ struct FfiCreateWalletOutput wallet_ffi_create_new(const char *config_path, const char *storage_path, + const char *metrics_path, const char *password); /** @@ -1583,8 +1585,9 @@ struct FfiCreateWalletOutput wallet_ffi_create_new(const char *config_path, * This loads a wallet that was previously created with `wallet_ffi_create_new()`. * * # Parameters + * - `handle` - Valid wallet handle * - `config_path`: Path to the wallet configuration file (JSON) - * - `storage_path`: Path where wallet data is stored + * - `metrics_path`: Path to the wallet metrics file (JSON) * * # Returns * - Opaque wallet handle on success @@ -1592,8 +1595,11 @@ struct FfiCreateWalletOutput wallet_ffi_create_new(const char *config_path, * * # Safety * All string parameters must be valid null-terminated UTF-8 strings. + * `handle` must be a valid wallet handle from `wallet_ffi_create_new` or `wallet_ffi_open`. */ -struct WalletHandle *wallet_ffi_open(const char *config_path, const char *storage_path); +struct WalletHandle *wallet_ffi_open(const char *config_path, + const char *storage_path, + const char *metrics_path); /** * Destroy a wallet handle and free its resources. diff --git a/lez/wallet/src/lib.rs b/lez/wallet/src/lib.rs index bd265eed..d673af06 100644 --- a/lez/wallet/src/lib.rs +++ b/lez/wallet/src/lib.rs @@ -211,6 +211,10 @@ impl WalletCore { self.multi_sequencer_client.leader.clone() } + pub fn leader_url(&self) -> Url { + self.multi_sequencer_client.leader_url.clone() + } + /// Get storage. #[must_use] pub const fn storage(&self) -> &Storage { diff --git a/lez/wallet/src/multi_client.rs b/lez/wallet/src/multi_client.rs index 534f7fb1..aa42c6e8 100644 --- a/lez/wallet/src/multi_client.rs +++ b/lez/wallet/src/multi_client.rs @@ -158,10 +158,9 @@ pub async fn callibration(client: SequencerClient) -> Metrics { // Precision loss if fine there let sample_size = latencies.len(); let latency_avg = (latencies.iter().fold(0, |acc, x| acc + x) as f32) / (sample_size as f32); - let latency_var = (latencies.iter().fold(0f32, |acc, x| { + let latency_var = latencies.iter().fold(0f32, |acc, x| { acc + ((*x as f32) - latency_avg) * ((*x as f32) - latency_avg) - }) / (sample_size as f32)) - .sqrt(); + }) / (sample_size as f32); Metrics { latency_avg, @@ -216,32 +215,16 @@ pub fn choose_leader( }) .collect(); - // Conservative assumption: least amount of errors is the best - let min_err_addr = client_vec.iter().fold(client_vec[0], |acc, x| { - let old_err_count = metrics.get(acc).unwrap().errors; - let new_err_count = metrics.get(*x).unwrap().errors; - if new_err_count < old_err_count { - *x - } else { - acc - } + // Get the lowest quartile in error distribution + client_vec.sort_by(|a, b| { + metrics + .get(*a) + .unwrap() + .errors + .cmp(&metrics.get(*b).unwrap().errors) }); - let min_err_count = metrics.get(min_err_addr).unwrap().errors; - - // Sort out all latest clients - client_vec = client_vec - .iter() - .filter_map(|x| { - let err_count = metrics.get(*x).unwrap().errors; - - if err_count == min_err_count { - Some(*x) - } else { - None - } - }) - .collect(); + client_vec = client_vec[..(client_vec.len() / 4)].to_vec(); // Choose clients with least latency and variance let min_lat_var_addr = client_vec.iter().fold(client_vec[0], |acc, x| { @@ -250,10 +233,11 @@ pub fn choose_leader( let new = metrics.get(*x).unwrap(); let (new_lat, new_var) = (new.latency_avg, new.latency_var); - // Client is better if it is strongly linearly better - if ((new_lat - new_var) > (old_lat - old_var)) - && ((new_lat + new_var) > (old_lat + old_var)) - { + let new_std = new_var.sqrt(); + let old_std = old_var.sqrt(); + + // Client is better if its averabe is better and variance does not make it worse + if (new_lat < old_lat) && ((new_lat + new_std) < (old_lat + old_std)) { *x } else { acc @@ -283,32 +267,41 @@ struct CumulativeUpdates { pub failure_count: u64, pub latest_block_id: Option, pub cumulative_latency: f32, + pub cumulative_latency_squares: f32, pub additional_sample_size: usize, } fn cumulative_updates(metric_updates: &[MetricsUpdate]) -> CumulativeUpdates { - let (failure_count, latest_block_id, cumulative_latency) = - metric_updates.iter().fold((0u64, None, 0f32), |acc, x| { - let MetricsUpdate { - latency, - new_latest_block_id, - is_failed, - } = x; - ( - if *is_failed { acc.0 + 1 } else { acc.0 }, - match (acc.1, new_latest_block_id) { - (None, None) => None, - (None, Some(val)) | (Some(val), None) => Some(val), - (Some(val_old), Some(val_new)) => Some(std::cmp::max(val_old, val_new)), - }, - if !*is_failed { acc.2 + latency } else { acc.2 }, - ) - }); + let (failure_count, latest_block_id, cumulative_latency, cumulative_latency_squares) = + metric_updates + .iter() + .fold((0u64, None, 0f32, 0_f32), |acc, x| { + let MetricsUpdate { + latency, + new_latest_block_id, + is_failed, + } = x; + ( + if *is_failed { acc.0 + 1 } else { acc.0 }, + match (acc.1, new_latest_block_id) { + (None, None) => None, + (None, Some(val)) | (Some(val), None) => Some(val), + (Some(val_old), Some(val_new)) => Some(std::cmp::max(val_old, val_new)), + }, + if !*is_failed { acc.2 + latency } else { acc.2 }, + if !*is_failed { + acc.3 + latency * latency + } else { + acc.3 + }, + ) + }); CumulativeUpdates { failure_count, latest_block_id: latest_block_id.copied(), cumulative_latency, + cumulative_latency_squares, additional_sample_size: metric_updates.len() - (failure_count as usize), } } @@ -319,19 +312,24 @@ fn cumulative_avg( orig_size_f: f32, mod_size_f: f32, ) -> f32 { - (latency_avg_old * orig_size_f + cumulative_latency) / mod_size_f + (latency_avg_old * orig_size_f + cumulative_latency) / (orig_size_f + mod_size_f) } fn cumulative_var( latency_avg_old: f32, latency_avg_new: f32, latency_var: f32, + cumulative_latency: f32, + cumulative_latency_squares: f32, orig_size_f: f32, mod_size_f: f32, ) -> f32 { - (latency_avg_old - latency_avg_new) - * ((3f32 * latency_avg_old + latency_avg_new) * orig_size_f / mod_size_f) - + (latency_var * latency_var) * orig_size_f / mod_size_f + (latency_var * orig_size_f + + (latency_avg_new - latency_avg_old) * (latency_avg_new - latency_avg_old) * orig_size_f + + cumulative_latency_squares + + mod_size_f * (latency_avg_new * latency_avg_new) + - 2_f32 * cumulative_latency * latency_avg_new) + / (orig_size_f + mod_size_f) } pub fn update_metrics( @@ -341,12 +339,13 @@ pub fn update_metrics( ) -> Result<(), anyhow::Error> { let leader_metric = metrics .get_mut(leader_url) - .ok_or(anyhow::anyhow!("Leader URL is in present in metrics"))?; + .ok_or(anyhow::anyhow!("Leader URL is not present in metrics"))?; let CumulativeUpdates { failure_count, latest_block_id, cumulative_latency, + cumulative_latency_squares, additional_sample_size, } = cumulative_updates(metric_updates); @@ -356,22 +355,25 @@ pub fn update_metrics( } let orig_size_f = leader_metric.sample_size as f32; - let mod_size_f = (leader_metric.sample_size + additional_sample_size) as f32; + let mod_size_f = additional_sample_size as f32; let latency_avg_old = leader_metric.latency_avg; let latency_avg_new = cumulative_avg(latency_avg_old, cumulative_latency, orig_size_f, mod_size_f); - let latency_disp_new = cumulative_var( + let latency_var_new = cumulative_var( latency_avg_old, latency_avg_new, leader_metric.latency_var, + cumulative_latency, + cumulative_latency_squares, orig_size_f, mod_size_f, ); leader_metric.latency_avg = latency_avg_new; - leader_metric.latency_var = latency_disp_new.sqrt(); + leader_metric.latency_var = latency_var_new; + leader_metric.sample_size += additional_sample_size; Ok(()) } @@ -389,7 +391,14 @@ pub fn save_metrics_at_path_with_updates( #[cfg(test)] mod tests { - use crate::multi_client::{MetricsUpdate, cumulative_avg, cumulative_updates}; + use std::collections::HashMap; + + use url::Url; + + use crate::multi_client::{ + CumulativeUpdates, Metrics, MetricsUpdate, cumulative_avg, cumulative_updates, + cumulative_var, update_metrics, + }; #[test] fn cumulative_updates_test() { @@ -411,25 +420,36 @@ mod tests { }, ]; - let cumulative_updates = cumulative_updates(&metrics_updates_vec); + let CumulativeUpdates { + failure_count, + latest_block_id, + cumulative_latency, + cumulative_latency_squares, + additional_sample_size, + } = cumulative_updates(&metrics_updates_vec); let epsilon = 0.01_f32; - assert_eq!(cumulative_updates.additional_sample_size, 2); - assert_eq!(cumulative_updates.failure_count, 1); - assert_eq!(cumulative_updates.latest_block_id, Some(16)); - assert!((cumulative_updates.cumulative_latency - 215_f32).abs() < epsilon); + let sum_squared_manual = 100_f32 * 100_f32 + 115_f32 * 115_f32; + + assert_eq!(additional_sample_size, 2); + assert_eq!(failure_count, 1); + assert_eq!(latest_block_id, Some(16)); + assert!((cumulative_latency - 215_f32).abs() < epsilon); + assert!((cumulative_latency_squares - sum_squared_manual).abs() < epsilon); } #[test] fn cumulative_avg_test() { - let mut sample = vec![100_f32; 20]; + let mut sample = vec![100_f32; 40]; let old_sample_size_f = sample.len() as f32; let old_avg = sample.iter().sum::() / old_sample_size_f; - let new_samples = vec![101_f32, 110_f32, 112_f32, 97_f32, 78_f32]; - let mod_sample_size_f = new_samples.len() as f32 + old_sample_size_f; + let new_samples = vec![ + 101_f32, 110_f32, 112_f32, 97_f32, 78_f32, 25_f32, 75_f32, 189_f32, 120_f32, 50_f32, + ]; + let mod_sample_size_f = new_samples.len() as f32; let cumulative = new_samples.iter().sum(); sample.extend_from_slice(&new_samples); @@ -442,4 +462,117 @@ mod tests { assert!((new_avg_1 - new_avg_2).abs() < epsilon); } + + #[test] + fn cumulative_var_test() { + let mut sample = vec![100_f32; 40]; + + let old_sample_size_f = sample.len() as f32; + let old_avg = sample.iter().sum::() / old_sample_size_f; + + let old_var = sample + .iter() + .fold(0_f32, |acc, x| acc + (x - old_avg) * (x - old_avg)) + / old_sample_size_f; + + let new_samples = vec![ + 101_f32, 110_f32, 112_f32, 97_f32, 78_f32, 25_f32, 75_f32, 189_f32, 120_f32, 50_f32, + ]; + let mod_sample_size_f = new_samples.len() as f32; + let cumulative = new_samples.iter().sum(); + let cumulative_squares = new_samples.iter().fold(0_f32, |acc, x| acc + (*x) * (*x)); + + let new_avg = cumulative_avg(old_avg, cumulative, old_sample_size_f, mod_sample_size_f); + + sample.extend_from_slice(&new_samples); + let new_var_1 = sample + .iter() + .fold(0_f32, |acc, x| acc + (x - new_avg) * (x - new_avg)) + / (sample.len() as f32); + + let new_var_2 = cumulative_var( + old_avg, + new_avg, + old_var, + cumulative, + cumulative_squares, + old_sample_size_f, + mod_sample_size_f, + ); + + let epsilon = 0.01_f32; + + assert!((new_var_1 - new_var_2).abs() < epsilon); + } + + #[test] + fn metric_updates_correctness() { + let metrics_updates_vec = vec![ + MetricsUpdate { + latency: 100_f32, + new_latest_block_id: Some(105), + is_failed: false, + }, + MetricsUpdate { + latency: 115_f32, + new_latest_block_id: Some(106), + is_failed: false, + }, + MetricsUpdate { + latency: 50_f32, + new_latest_block_id: None, + is_failed: true, + }, + ]; + + let addr_leader = Url::parse("https://127.0.0.1:3040").unwrap(); + + let leader_metrics = Metrics { + latency_avg: 100_f32, + latency_var: 25_f32, + sample_size: 10, + latest_block_id: 100, + errors: 5, + }; + + let cumulative_latency = 100_f32 + 115_f32; + let cumulative_latency_squares = 100_f32 * 100_f32 + 115_f32 * 115_f32; + + let avg_manual = cumulative_avg( + leader_metrics.latency_avg, + cumulative_latency, + 10_f32, + 2_f32, + ); + let var_manual = cumulative_var( + leader_metrics.latency_avg, + avg_manual, + leader_metrics.latency_var, + cumulative_latency, + cumulative_latency_squares, + 10_f32, + 2_f32, + ); + + let mut metric_map = HashMap::new(); + metric_map.insert(addr_leader.clone(), leader_metrics); + + update_metrics(&mut metric_map, &addr_leader, &metrics_updates_vec).unwrap(); + + let Metrics { + latency_avg, + latency_var, + sample_size, + latest_block_id, + errors, + } = metric_map.get(&addr_leader).unwrap(); + + let epsilon = 0.01_f32; + + assert_eq!(*errors, 6); + assert_eq!(*latest_block_id, 106); + assert_eq!(*sample_size, 12); + assert!((*latency_avg - avg_manual).abs() < epsilon); + assert!((*latency_var - var_manual).abs() < epsilon); + } } diff --git a/test_fixtures/src/config.rs b/test_fixtures/src/config.rs index 92ed6a18..970985b5 100644 --- a/test_fixtures/src/config.rs +++ b/test_fixtures/src/config.rs @@ -8,7 +8,7 @@ use lee::{AccountId, PrivateKey, PublicKey}; use lee_core::Identifier; use sequencer_core::config::{BedrockConfig, GenesisAction, SequencerConfig}; use url::Url; -use wallet::config::WalletConfig; +use wallet::config::{SequencerConnectionData, WalletConfig}; pub const INITIAL_PUBLIC_BALANCES_FOR_WALLET: [u128; 2] = [10_000, 20_000]; pub const INITIAL_PRIVATE_BALANCES_FOR_WALLET: [u128; 2] = [10_000, 20_000]; @@ -157,13 +157,15 @@ pub fn genesis_from_accounts( pub fn wallet_config(sequencer_addr: SocketAddr) -> Result { Ok(WalletConfig { - sequencer_addr: addr_to_url(UrlProtocol::Http, sequencer_addr) - .context("Failed to convert sequencer addr to URL")?, + sequencers_conn_data: vec![SequencerConnectionData { + sequencer_addr: addr_to_url(UrlProtocol::Http, sequencer_addr) + .context("Failed to convert sequencer addr to URL")?, + basic_auth: None, + }], seq_poll_timeout: Duration::from_secs(30), seq_tx_poll_max_blocks: 15, seq_poll_max_retries: 10, seq_block_poll_max_amount: 100, - basic_auth: None, }) } diff --git a/test_fixtures/src/lib.rs b/test_fixtures/src/lib.rs index e57e2f74..5423e007 100644 --- a/test_fixtures/src/lib.rs +++ b/test_fixtures/src/lib.rs @@ -365,6 +365,7 @@ impl TestContextBuilder { &initial_private_accounts, wallet_config_overrides, ) + .await .context("Failed to setup wallet")?; setup_public_accounts_with_initial_supply(&mut wallet, &initial_public_accounts) @@ -420,15 +421,19 @@ impl BlockingTestContext { self.ctx.as_ref().expect("TestContext is set") } + pub fn ctx_mut(&mut self) -> &mut TestContext { + self.ctx.as_mut().expect("TestContext is set") + } + pub const fn runtime(&self) -> &tokio::runtime::Runtime { &self.runtime } - pub fn block_on<'ctx, F>(&'ctx self, f: impl FnOnce(&'ctx TestContext) -> F) -> F::Output + pub fn block_on<'ctx, F>(&'ctx mut self, f: impl FnOnce(&'ctx TestContext) -> F) -> F::Output where F: std::future::Future + 'ctx, { - let future = f(self.ctx()); + let future = f(self.ctx_mut()); self.runtime.block_on(future) } diff --git a/test_fixtures/src/setup.rs b/test_fixtures/src/setup.rs index f7d194e3..4f3bc1db 100644 --- a/test_fixtures/src/setup.rs +++ b/test_fixtures/src/setup.rs @@ -133,7 +133,7 @@ pub async fn setup_sequencer( Ok((sequencer_handle, temp_sequencer_dir)) } -pub fn setup_wallet( +pub async fn setup_wallet( sequencer_addr: SocketAddr, initial_public_accounts: &[(PrivateKey, u128)], initial_private_accounts: &[InitialPrivateAccountForWallet], @@ -151,14 +151,17 @@ pub fn setup_wallet( .context("Failed to write wallet config in temp dir")?; let storage_path = temp_wallet_dir.path().join("storage.json"); + let metrics_path = temp_wallet_dir.path().join("metrics.json"); let wallet_password = "test_pass".to_owned(); let (mut wallet, _mnemonic) = WalletCore::new_init_storage( config_path, storage_path, + metrics_path, Some(config_overrides), &wallet_password, ) + .await .context("Failed to init wallet")?; for (private_key, _balance) in initial_public_accounts {