diff --git a/Cargo.lock b/Cargo.lock index ff9c402fa7..5ec547445f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9652,6 +9652,7 @@ dependencies = [ "consensus", "crypto", "ctor", + "derive_more", "hex", "itertools 0.14.0", "lazy_static", @@ -10006,6 +10007,7 @@ dependencies = [ "bip39", "common", "crypto", + "derive_more", "hex", "itertools 0.14.0", "logging", diff --git a/node-gui/Cargo.toml b/node-gui/Cargo.toml index 261a702d98..77c630848b 100644 --- a/node-gui/Cargo.toml +++ b/node-gui/Cargo.toml @@ -5,7 +5,11 @@ license.workspace = true version.workspace = true edition.workspace = true rust-version.workspace = true -authors = ["Samer Afach ", "Ben Marsh ", "Enrico Rubboli "] +authors = [ + "Samer Afach ", + "Ben Marsh ", + "Enrico Rubboli ", +] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -23,7 +27,7 @@ utils = { path = "../utils" } wallet = { path = "../wallet" } wallet-controller = { path = "../wallet/wallet-controller" } wallet-types = { path = "../wallet/types" } -wallet-cli-commands = { path = "../wallet/wallet-cli-commands"} +wallet-cli-commands = { path = "../wallet/wallet-cli-commands" } wallet-storage = { path = "../wallet/storage" } anyhow.workspace = true @@ -42,5 +46,16 @@ tokio.workspace = true winres = "0.1" [features] -trezor = ["wallet-controller/trezor", "wallet-types/trezor", "wallet-cli-commands/trezor", "node-gui-backend/trezor"] -default = ["trezor"] +trezor = [ + "wallet-controller/trezor", + "wallet-types/trezor", + "wallet-cli-commands/trezor", + "node-gui-backend/trezor", +] +ledger = [ + "wallet-controller/ledger", + "wallet-types/ledger", + "wallet-cli-commands/ledger", + "node-gui-backend/ledger", +] +default = ["trezor", "ledger"] diff --git a/node-gui/backend/Cargo.toml b/node-gui/backend/Cargo.toml index 0d27d83476..77dfa3c99e 100644 --- a/node-gui/backend/Cargo.toml +++ b/node-gui/backend/Cargo.toml @@ -5,7 +5,11 @@ license.workspace = true version.workspace = true edition.workspace = true rust-version.workspace = true -authors = ["Samer Afach ", "Ben Marsh ", "Enrico Rubboli "] +authors = [ + "Samer Afach ", + "Ben Marsh ", + "Enrico Rubboli ", +] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -24,9 +28,9 @@ utils = { path = "../../utils" } wallet = { path = "../../wallet" } wallet-controller = { path = "../../wallet/wallet-controller" } wallet-types = { path = "../../wallet/types" } -wallet-rpc-lib = { path = "../../wallet/wallet-rpc-lib"} -wallet-rpc-client = { path = "../../wallet/wallet-rpc-client"} -wallet-cli-commands = { path = "../../wallet/wallet-cli-commands"} +wallet-rpc-lib = { path = "../../wallet/wallet-rpc-lib" } +wallet-rpc-client = { path = "../../wallet/wallet-rpc-client" } +wallet-cli-commands = { path = "../../wallet/wallet-cli-commands" } anyhow.workspace = true chrono.workspace = true @@ -45,4 +49,19 @@ test-utils = { path = "../../test-utils" } rstest.workspace = true [features] -trezor = ["wallet/trezor", "wallet-controller/trezor", "wallet-types/trezor", "wallet-rpc-lib/trezor", "wallet-rpc-client/trezor", "wallet-cli-commands/trezor"] +trezor = [ + "wallet/trezor", + "wallet-controller/trezor", + "wallet-types/trezor", + "wallet-rpc-lib/trezor", + "wallet-rpc-client/trezor", + "wallet-cli-commands/trezor", +] +ledger = [ + "wallet/ledger", + "wallet-controller/ledger", + "wallet-types/ledger", + "wallet-rpc-lib/ledger", + "wallet-rpc-client/ledger", + "wallet-cli-commands/ledger", +] diff --git a/node-gui/src/main_window/main_widget/tabs/wallet/mod.rs b/node-gui/src/main_window/main_widget/tabs/wallet/mod.rs index ff73d1152f..1938050926 100644 --- a/node-gui/src/main_window/main_widget/tabs/wallet/mod.rs +++ b/node-gui/src/main_window/main_widget/tabs/wallet/mod.rs @@ -471,6 +471,7 @@ impl Tab for WalletTab { Some(wallet_info) => match wallet_info.extra_info { wallet_controller::types::WalletExtraInfo::SoftwareWallet => "Software wallet", wallet_controller::types::WalletExtraInfo::TrezorWallet { .. } => "Trezor wallet", + wallet_controller::types::WalletExtraInfo::LedgerWallet { .. } => "Ledger wallet", }, None => "No wallet", }; diff --git a/node-gui/src/main_window/main_widget/tabs/wallet/status_bar.rs b/node-gui/src/main_window/main_widget/tabs/wallet/status_bar.rs index d94fe3c5aa..fabca6abe1 100644 --- a/node-gui/src/main_window/main_widget/tabs/wallet/status_bar.rs +++ b/node-gui/src/main_window/main_widget/tabs/wallet/status_bar.rs @@ -13,6 +13,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#[cfg(any(feature = "trezor", feature = "ledger"))] +use iced::widget::{rich_text, span}; use iced::{ font, widget::{container, row, Container}, @@ -31,7 +33,7 @@ const HORIZONTAL_PADDING: f32 = 10.; pub fn estimate_status_bar_height(wallet_info: &WalletExtraInfo) -> f32 { match wallet_info { WalletExtraInfo::SoftwareWallet => 0., - WalletExtraInfo::TrezorWallet { .. } => { + WalletExtraInfo::TrezorWallet { .. } | WalletExtraInfo::LedgerWallet { .. } => { TEXT_SIZE + 2. * VERTICAL_PADDING // For some reason, the status bar gets a bit of additional height. + 4. @@ -55,8 +57,6 @@ pub fn view_status_bar(wallet_info: &WalletExtraInfo) -> Option { - use iced::widget::{rich_text, span}; - row![ rich_text([span("Device name: ").font(bold_font), span(device_name.clone())]) .size(TEXT_SIZE), @@ -67,6 +67,11 @@ pub fn view_status_bar(wallet_info: &WalletExtraInfo) -> Option { + row![rich_text([span("App version: ").font(bold_font), span(app_version.clone())]) + .size(TEXT_SIZE),] + } }; let status_bar = Container::new( diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 4db867ffe4..5b94332adc 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -32,6 +32,7 @@ bip39 = { workspace = true, default-features = false, features = [ "std", "zeroize", ] } +derive_more.workspace = true hex.workspace = true itertools.workspace = true parity-scale-codec.workspace = true diff --git a/wallet/src/key_chain/master_key_chain/mod.rs b/wallet/src/key_chain/master_key_chain/mod.rs index a93eb60b92..86c973d191 100644 --- a/wallet/src/key_chain/master_key_chain/mod.rs +++ b/wallet/src/key_chain/master_key_chain/mod.rs @@ -22,7 +22,7 @@ use crypto::vrf::ExtendedVRFPrivateKey; use std::sync::Arc; use wallet_storage::{ StoreTxRwUnlocked, WalletStorageReadLocked, WalletStorageReadUnlocked, - WalletStorageWriteUnlocked, + WalletStorageWriteLocked, WalletStorageWriteUnlocked, }; use wallet_types::seed_phrase::{SerializableSeedPhrase, StoreSeedPhrase}; @@ -131,7 +131,7 @@ impl MasterKeyChain { pub fn create_account_key_chain( &self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut (impl WalletStorageWriteLocked + WalletStorageReadUnlocked), account_index: U31, lookahead_size: u32, ) -> KeyChainResult { diff --git a/wallet/src/signer/ledger_signer/ledger_messages.rs b/wallet/src/signer/ledger_signer/ledger_messages.rs index 00dd968eac..801a9e262f 100644 --- a/wallet/src/signer/ledger_signer/ledger_messages.rs +++ b/wallet/src/signer/ledger_signer/ledger_messages.rs @@ -30,6 +30,7 @@ use crypto::key::{ }; use serialization::{Decode, DecodeAll, Encode}; use utils::ensure; +use wallet_types::hw_data::LedgerFullInfo; use ledger_lib::Exchange; use mintlayer_ledger_messages::{ @@ -37,7 +38,7 @@ use mintlayer_ledger_messages::{ Bip32Path as LedgerBip32Path, CoinType, InputAdditionalInfoReq, Ins, OutputValue as LOutputValue, P1SignTx, PubKeyP1, PublicKeyReq, SignMessageReq, SignTxReq, TxInput as LTxInput, TxInputReq, TxMetadataReq, TxOutput as LTxOutput, TxOutputReq, APDU_CLASS, - H256 as LH256, P1_APP_NAME, P1_SIGN_NEXT, P1_SIGN_START, P2_DONE, P2_SIGN_MORE, + H256 as LH256, P1_APP_NAME, P1_GET_VERSION, P1_SIGN_NEXT, P1_SIGN_START, P2_DONE, P2_SIGN_MORE, }; const MAX_ADPU_LEN: usize = (u8::MAX - 5) as usize; // 4 bytes for the header + 1 for len @@ -136,11 +137,15 @@ pub async fn sign_challenge( pub async fn get_app_name(ledger: &mut L) -> Result, ledger_lib::Error> { let msg_buf = [APDU_CLASS, Ins::APP_NAME, P1_APP_NAME, P2_DONE]; - ledger.exchange(&msg_buf, Duration::from_millis(100)).await + ledger.exchange(&msg_buf, Duration::from_millis(500)).await } -#[allow(dead_code)] -pub async fn check_current_app(ledger: &mut L) -> SignerResult<()> { +async fn get_app_version(ledger: &mut L) -> Result, ledger_lib::Error> { + let msg_buf = [APDU_CLASS, Ins::GET_VERSION, P1_GET_VERSION, P2_DONE]; + ledger.exchange(&msg_buf, Duration::from_millis(500)).await +} + +pub async fn check_current_app(ledger: &mut L) -> SignerResult { let resp = get_app_name(ledger) .await .map_err(|err| LedgerError::DeviceError(err.to_string()))?; @@ -152,7 +157,20 @@ pub async fn check_current_app(ledger: &mut L) -> SignerResult<()> LedgerError::DifferentActiveApp(name) ); - Ok(()) + let resp = get_app_version(ledger) + .await + .map_err(|err| LedgerError::DeviceError(err.to_string()))?; + let ver = ok_response(resp)?; + let app_version = match ver.as_slice() { + [major, minor, patch] => common::primitives::semver::SemVer { + major: *major, + minor: *minor, + patch: *patch as u16, + }, + _ => return Err(SignerError::LedgerError(LedgerError::InvalidResponse)), + }; + + Ok(LedgerFullInfo { app_version }) } pub async fn get_extended_public_key( diff --git a/wallet/src/signer/ledger_signer/mod.rs b/wallet/src/signer/ledger_signer/mod.rs index 599127099a..2920f16ea7 100644 --- a/wallet/src/signer/ledger_signer/mod.rs +++ b/wallet/src/signer/ledger_signer/mod.rs @@ -18,7 +18,7 @@ mod ledger_messages; use std::{collections::BTreeMap, sync::Arc}; use crate::{ - key_chain::{make_account_path, AccountKeyChains, FoundPubKey}, + key_chain::{make_account_path, AccountKeyChainImplHardware, AccountKeyChains, FoundPubKey}, signer::{ ledger_signer::ledger_messages::{ check_current_app, get_app_name, get_extended_public_key, sign_challenge, sign_tx, @@ -26,8 +26,9 @@ use crate::{ LedgerSignature, }, utils::{is_htlc_utxo, produce_uniparty_signature_for_input}, - Signer, SignerError, SignerResult, + Signer, SignerError, SignerProvider, SignerResult, }, + Account, WalletResult, }; use common::{ chain::{ @@ -64,11 +65,15 @@ use crypto::key::{ }; use serialization::Encode; use utils::ensure; -use wallet_storage::{WalletStorageReadLocked, WalletStorageReadUnlocked}; +use wallet_storage::{ + WalletStorageReadLocked, WalletStorageReadUnlocked, WalletStorageWriteUnlocked, +}; use wallet_types::{ - hw_data::LedgerData, + account_info::DEFAULT_ACCOUNT_INDEX, + hw_data::{HardwareWalletFullInfo, LedgerData, LedgerFullInfo}, partially_signed_transaction::{PartiallySignedTransaction, TokensAdditionalInfo}, signature_status::SignatureStatus, + AccountId, }; use async_trait::async_trait; @@ -86,6 +91,8 @@ use tokio::sync::Mutex; pub enum LedgerError { #[error("No connected Ledger device found")] NoDeviceFound, + #[error("Connected to an unknown Ledger device model")] + UnknownModel, #[error("A different app is currently open on your Ledger device: \"{0}\". Please close it and open the Mintlayer app instead.")] DifferentActiveApp(String), #[error("Received an invalid response from the Ledger device")] @@ -128,6 +135,7 @@ pub trait LedgerFinder { async fn find_ledger_device_from_db( &self, db_tx: &mut T, + chain_config: Arc, ) -> SignerResult<(Self::Ledger, LedgerData)>; } @@ -189,13 +197,14 @@ where | ledger_lib::Error::Tcp(_) | ledger_lib::Error::Ble(_), ) => { - let (mut new_client, data) = - self.provider.find_ledger_device_from_db(db_tx).await?; + let (mut new_client, _data) = self + .provider + .find_ledger_device_from_db(db_tx, self.chain_config.clone()) + .await?; check_public_keys_against_key_chain( db_tx, &mut new_client, - &data, key_chain, &self.chain_config, ) @@ -1012,8 +1021,7 @@ fn to_ledger_chain_type(chain_config: &ChainConfig) -> CoinType { } } -#[allow(dead_code)] -async fn find_ledger_device() -> SignerResult<(LedgerHandle, LedgerData)> { +async fn find_ledger_device() -> SignerResult<(LedgerHandle, LedgerFullInfo)> { let mut provider = LedgerProvider::init().await; let mut devices = provider .list(Filters::Any) @@ -1027,9 +1035,9 @@ async fn find_ledger_device() -> SignerResult<(LedgerHandle, LedgerData)> { .await .map_err(|err| LedgerError::DeviceError(err.to_string()))?; - check_current_app(&mut handle).await?; + let full_info = check_current_app(&mut handle).await?; - Ok((handle, LedgerData {})) + Ok((handle, full_info)) } /// Check that the public keys in the provided key chain are the same as the ones from the @@ -1037,7 +1045,6 @@ async fn find_ledger_device() -> SignerResult<(LedgerHandle, LedgerData)> { async fn check_public_keys_against_key_chain( db_tx: &mut T, client: &mut L, - _ledger_data: &LedgerData, key_chain: &impl AccountKeyChains, chain_config: &ChainConfig, ) -> SignerResult<()> { @@ -1056,6 +1063,31 @@ async fn check_public_keys_against_key_chain( + db_tx: &mut T, + client: &mut LedgerHandle, + chain_config: Arc, +) -> SignerResult<()> { + let (id, first_acc) = db_tx + .get_accounts_info()? + .iter() + .find_map(|(id, info)| { + (info.account_index() == DEFAULT_ACCOUNT_INDEX).then_some((id.clone(), info.clone())) + }) + .ok_or(SignerError::WalletNotInitialized)?; + + let loaded_acc = AccountKeyChainImplHardware::load_from_database( + chain_config.clone(), + db_tx, + &id, + &first_acc, + )?; + + check_public_keys_against_key_chain(db_tx, client, &loaded_acc, &chain_config).await +} + async fn fetch_extended_pub_key( client: &mut L, chain_config: &ChainConfig, @@ -1085,6 +1117,110 @@ fn single_signature( } } +#[derive(Clone, derive_more::Debug)] +pub struct LedgerSignerProvider { + #[debug(skip)] + client: Arc>, + info: LedgerFullInfo, +} + +#[async_trait] +impl LedgerFinder for LedgerSignerProvider { + type Ledger = LedgerHandle; + + async fn find_ledger_device_from_db( + &self, + db_tx: &mut T, + chain_config: Arc, + ) -> SignerResult<(Self::Ledger, LedgerData)> { + let (mut client, info) = find_ledger_device().await?; + + check_public_keys_against_db(db_tx, &mut client, chain_config).await?; + + Ok((client, info.into())) + } +} + +impl LedgerSignerProvider { + pub async fn new() -> SignerResult { + let (client, info) = find_ledger_device().await?; + + Ok(Self { + client: Arc::new(Mutex::new(client)), + info, + }) + } + + pub async fn load_from_database( + chain_config: Arc, + db_tx: &mut T, + ) -> WalletResult { + let (mut client, info) = find_ledger_device().await?; + + check_public_keys_against_db(db_tx, &mut client, chain_config).await?; + + Ok(Self { + client: Arc::new(Mutex::new(client)), + info, + }) + } + + async fn fetch_extended_pub_key( + &self, + chain_config: &Arc, + account_index: U31, + ) -> SignerResult { + fetch_extended_pub_key(&mut *self.client.lock().await, chain_config, account_index) + .await + .map_err(SignerError::LedgerError) + } +} + +#[async_trait] +impl SignerProvider for LedgerSignerProvider { + type S = LedgerSigner; + type K = AccountKeyChainImplHardware; + + fn provide(&mut self, chain_config: Arc, _account_index: U31) -> Self::S { + LedgerSigner::new(chain_config, self.client.clone(), self.clone()) + } + + async fn make_new_account( + &mut self, + chain_config: Arc, + account_index: U31, + name: Option, + db_tx: &mut T, + ) -> WalletResult> { + let account_pubkey = self.fetch_extended_pub_key(&chain_config, account_index).await?; + + let lookahead_size = db_tx.get_lookahead_size()?; + + let key_chain = AccountKeyChainImplHardware::new_from_hardware_key( + chain_config.clone(), + db_tx, + account_pubkey, + account_index, + lookahead_size, + )?; + + Account::new(chain_config, db_tx, key_chain, name) + } + + fn load_account_from_database( + &self, + chain_config: Arc, + db_tx: &impl WalletStorageReadLocked, + id: &AccountId, + ) -> WalletResult> { + Account::load_from_database(chain_config, db_tx, id) + } + + fn get_hardware_wallet_info(&self) -> Option { + Some(HardwareWalletFullInfo::Ledger(self.info.clone())) + } +} + #[cfg(feature = "enable-ledger-device-tests")] #[cfg(test)] mod tests; diff --git a/wallet/src/signer/ledger_signer/tests.rs b/wallet/src/signer/ledger_signer/tests.rs index e7bdd165a8..b773994b51 100644 --- a/wallet/src/signer/ledger_signer/tests.rs +++ b/wallet/src/signer/ledger_signer/tests.rs @@ -40,7 +40,7 @@ use tokio::{ use crate::signer::{ ledger_signer::{ - ledger_messages::{get_app_name, get_extended_public_key, ok_response}, + ledger_messages::{check_current_app, get_app_name, get_extended_public_key, ok_response}, speculos::{Action, Button, Handle, PodmanHandle}, LedgerError, LedgerFinder, LedgerSigner, }, @@ -103,6 +103,7 @@ impl LedgerFinder for DummyProvider { async fn find_ledger_device_from_db( &self, _db_tx: &mut T, + _chain_config: Arc, ) -> SignerResult<(Self::Ledger, LedgerData)> { Err(SignerError::LedgerError(LedgerError::NoDeviceFound)) } @@ -197,7 +198,10 @@ async fn test_app_name() { let info = device.app_info(Duration::from_millis(100)).await.unwrap(); eprintln!("info: {info:?}"); - // assert_eq!(info.name, "mintlayer-app"); + let info = check_current_app(&mut device).await.unwrap(); + eprintln!("info: {info:?}"); + + assert_eq!(info.app_version.to_string(), "0.1.0"); } #[rstest] diff --git a/wallet/src/signer/mod.rs b/wallet/src/signer/mod.rs index bfca2985ec..931ba2dfb4 100644 --- a/wallet/src/signer/mod.rs +++ b/wallet/src/signer/mod.rs @@ -115,6 +115,8 @@ pub enum SignerError { PartiallySignedTransactionError(#[from] PartiallySignedTransactionError), #[error("Duplicate UTXO input: {0:?}")] DuplicateUtxoInput(UtxoOutPoint), + #[error("Wallet not initialized")] + WalletNotInitialized, } type SignerResult = Result; @@ -158,18 +160,19 @@ pub trait Signer { ) -> SignerResult; } -pub trait SignerProvider { +#[async_trait] +pub trait SignerProvider: Send { type S: Signer + Send; type K: AccountKeyChains + Sync + Send; fn provide(&mut self, chain_config: Arc, account_index: U31) -> Self::S; - fn make_new_account( + async fn make_new_account( &mut self, chain_config: Arc, account_index: U31, name: Option, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut T, ) -> WalletResult>; fn load_account_from_database( diff --git a/wallet/src/signer/software_signer/mod.rs b/wallet/src/signer/software_signer/mod.rs index e8f58f05f4..35a1397cdc 100644 --- a/wallet/src/signer/software_signer/mod.rs +++ b/wallet/src/signer/software_signer/mod.rs @@ -480,6 +480,7 @@ impl SoftwareSignerProvider { } } +#[async_trait] impl SignerProvider for SoftwareSignerProvider { type S = SoftwareSigner; type K = AccountKeyChainImplSoftware; @@ -488,12 +489,12 @@ impl SignerProvider for SoftwareSignerProvider { SoftwareSigner::new(chain_config, account_index) } - fn make_new_account( + async fn make_new_account( &mut self, chain_config: Arc, next_account_index: U31, name: Option, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut T, ) -> WalletResult> { let lookahead_size = db_tx.get_lookahead_size()?; let account_key_chain = self.master_key_chain.create_account_key_chain( diff --git a/wallet/src/signer/trezor_signer/mod.rs b/wallet/src/signer/trezor_signer/mod.rs index a6be076ac5..35834f8f10 100644 --- a/wallet/src/signer/trezor_signer/mod.rs +++ b/wallet/src/signer/trezor_signer/mod.rs @@ -1590,19 +1590,14 @@ fn to_trezor_output_lock(lock: &OutputTimeLock) -> trezor_client::protos::Mintla lock_req } -#[derive(Clone)] +#[derive(Clone, derive_more::Debug)] pub struct TrezorSignerProvider { + #[debug(skip)] client: Arc>, info: TrezorFullInfo, session_id: Vec, } -impl std::fmt::Debug for TrezorSignerProvider { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("TrezorSignerProvider") - } -} - impl TrezorSignerProvider { pub fn new(selected: Option) -> Result { let (client, info, session_id) = find_trezor_device(selected)?; @@ -1857,6 +1852,7 @@ fn get_checked_firmware_version(client: &mut Trezor) -> Result( &mut self, chain_config: Arc, account_index: U31, name: Option, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut T, ) -> WalletResult> { let account_pubkey = self.fetch_extended_pub_key(&chain_config, account_index)?; diff --git a/wallet/src/wallet/mod.rs b/wallet/src/wallet/mod.rs index cf95222bec..ddaaf9d887 100644 --- a/wallet/src/wallet/mod.rs +++ b/wallet/src/wallet/mod.rs @@ -357,14 +357,14 @@ where B: storage::BackendWithSendableTransactions + 'static, P: SignerProvider, { - pub fn create_new_wallet) -> WalletResult

>( + pub async fn create_new_wallet) -> WalletResult

>( chain_config: Arc, db: Store, best_block: (BlockHeight, Id), wallet_type: WalletType, signer_provider: F, ) -> WalletResult> { - let mut wallet = Self::new_wallet(chain_config, db, wallet_type, signer_provider)?; + let mut wallet = Self::new_wallet(chain_config, db, wallet_type, signer_provider).await?; if let WalletCreation::Wallet(ref mut w) = wallet { w.set_best_block(best_block.0, best_block.1)?; @@ -373,16 +373,16 @@ where Ok(wallet) } - pub fn recover_wallet) -> WalletResult

>( + pub async fn recover_wallet) -> WalletResult

>( chain_config: Arc, db: Store, wallet_type: WalletType, signer_provider: F, ) -> WalletResult> { - Self::new_wallet(chain_config, db, wallet_type, signer_provider) + Self::new_wallet(chain_config, db, wallet_type, signer_provider).await } - fn new_wallet) -> WalletResult

>( + async fn new_wallet) -> WalletResult

>( chain_config: Arc, mut db: Store, wallet_type: WalletType, @@ -413,7 +413,8 @@ where &mut db_tx, None, &mut signer_provider, - )?; + ) + .await?; let next_unused_account = Wallet::::create_next_unused_account( U31::ONE, @@ -421,7 +422,8 @@ where &mut db_tx, None, &mut signer_provider, - )?; + ) + .await?; db_tx.commit()?; @@ -441,7 +443,7 @@ where /// Migrate the wallet DB from version 1 to version 2 /// * save the chain info in the DB based on the chain type specified by the user /// * reset transactions - fn migration_v2( + async fn migration_v2( db: &mut Store, chain_config: Arc, signer_provider: &mut P, @@ -455,7 +457,7 @@ where Self::reset_wallet_transactions(chain_config.clone(), &mut db_tx)?; // Create the next unused account - Self::migrate_next_unused_account(chain_config, &mut db_tx, signer_provider)?; + Self::migrate_next_unused_account(chain_config, &mut db_tx, signer_provider).await?; db_tx.set_storage_version(WALLET_VERSION_V2)?; db_tx.commit()?; @@ -594,7 +596,7 @@ where } /// Check the wallet DB version and perform any migrations needed - fn check_and_migrate_db< + async fn check_and_migrate_db< F: Fn(u32) -> Result<(), WalletError>, F2: FnOnce(&StoreTxRo) -> WalletResult

, >( @@ -621,7 +623,7 @@ where } WALLET_VERSION_V1 => { pre_migration(WALLET_VERSION_V1)?; - Self::migration_v2(db, chain_config.clone(), &mut signer_provider)?; + Self::migration_v2(db, chain_config.clone(), &mut signer_provider).await?; } WALLET_VERSION_V2 => { pre_migration(WALLET_VERSION_V2)?; @@ -786,11 +788,11 @@ where .collect() } - fn migrate_next_unused_account( + async fn migrate_next_unused_account( chain_config: Arc, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut T, signer_provider: &mut P, - ) -> Result<(), WalletError> { + ) -> WalletResult<()> { let accounts_info = db_tx.get_accounts_info()?; let mut accounts: BTreeMap> = accounts_info .keys() @@ -802,21 +804,25 @@ where .map(|account| (account.account_index(), account)) .collect(); let last_account = accounts.pop_last().ok_or(WalletError::WalletNotInitialized)?; + let next_account_index = last_account .0 .plus_one() .map_err(|_| WalletError::AbsoluteMaxNumAccountsExceeded(last_account.0))?; + Wallet::::create_next_unused_account( next_account_index, chain_config.clone(), db_tx, None, signer_provider, - )?; + ) + .await?; + Ok(()) } - pub fn load_wallet< + pub async fn load_wallet< F: Fn(u32) -> WalletResult<()>, F2: FnOnce(&StoreTxRo) -> WalletResult

, >( @@ -838,7 +844,9 @@ where pre_migration, controller_mode, signer_provider, - ) { + ) + .await + { Ok(x) => x, #[cfg(feature = "trezor")] Err(WalletError::SignerError(SignerError::TrezorError( @@ -985,10 +993,10 @@ where self.signer_provider.get_hardware_wallet_info() } - fn create_next_unused_account( + async fn create_next_unused_account( next_account_index: U31, chain_config: Arc, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut T, name: Option, signer_provider: &mut P, ) -> WalletResult<(U31, Account)> { @@ -997,19 +1005,16 @@ where WalletError::EmptyAccountName ); - let account = signer_provider.make_new_account( - chain_config.clone(), - next_account_index, - name, - db_tx, - )?; + let account = signer_provider + .make_new_account(chain_config.clone(), next_account_index, name, db_tx) + .await?; Ok((next_account_index, account)) } /// Promotes the unused account into the used accounts and creates a new unused account /// Returns the new index and optional name if provided - pub fn create_next_account( + pub async fn create_next_account( &mut self, name: Option, ) -> WalletResult<(U31, Option)> { @@ -1039,7 +1044,8 @@ where &mut db_tx, None, &mut self.signer_provider, - )?; + ) + .await?; self.next_unused_account.1.set_name(name.clone(), &mut db_tx)?; std::mem::swap(&mut self.next_unused_account, &mut next_unused_account); @@ -2509,7 +2515,7 @@ where /// If `common_block_height` is zero, only the genesis block is considered common. /// If a new transaction is recognized for the unused account, it is transferred to the used /// accounts and a new unused account is created. - pub fn scan_new_blocks_unused_account( + pub async fn scan_new_blocks_unused_account( &mut self, common_block_height: BlockHeight, blocks: Vec, @@ -2527,7 +2533,7 @@ where db_tx.commit()?; if added_new_tx_in_unused_acc { - self.create_next_account(None)?; + self.create_next_account(None).await?; } else { break; } diff --git a/wallet/src/wallet/test_helpers.rs b/wallet/src/wallet/test_helpers.rs index 4a3f8de5c5..1e9efda4a8 100644 --- a/wallet/src/wallet/test_helpers.rs +++ b/wallet/src/wallet/test_helpers.rs @@ -34,7 +34,7 @@ use crate::{ DefaultWallet, Wallet, }; -pub fn create_wallet_with_mnemonic( +pub async fn create_wallet_with_mnemonic( chain_config: Arc, mnemonic: &str, ) -> DefaultWallet { @@ -55,6 +55,7 @@ pub fn create_wallet_with_mnemonic( )?) }, ) + .await .unwrap() .wallet() .unwrap() @@ -68,7 +69,7 @@ pub fn create_named_in_memory_store(db_name: &str) -> Store { Store::new(create_named_in_memory_backend(db_name)).unwrap() } -pub fn create_wallet_with_mnemonic_and_named_db( +pub async fn create_wallet_with_mnemonic_and_named_db( chain_config: Arc, mnemonic: &str, db_name: &str, @@ -90,12 +91,13 @@ pub fn create_wallet_with_mnemonic_and_named_db( )?) }, ) + .await .unwrap() .wallet() .unwrap() } -pub fn scan_wallet(wallet: &mut Wallet, height: BlockHeight, blocks: Vec) +pub async fn scan_wallet(wallet: &mut Wallet, height: BlockHeight, blocks: Vec) where B: storage::BackendWithSendableTransactions + 'static, P: SignerProvider, @@ -108,5 +110,6 @@ where wallet .scan_new_blocks_unused_account(height, blocks, &WalletEventsNoOp) + .await .unwrap(); } diff --git a/wallet/src/wallet/tests.rs b/wallet/src/wallet/tests.rs index 74a44202cc..674f74767e 100644 --- a/wallet/src/wallet/tests.rs +++ b/wallet/src/wallet/tests.rs @@ -262,8 +262,7 @@ where (coins, token_balances) } -#[track_caller] -fn verify_wallet_balance( +async fn verify_wallet_balance( chain_config: &Arc, wallet: &Wallet, expected_balance: Amount, @@ -287,6 +286,7 @@ fn verify_wallet_balance( false, |db_tx| SoftwareSignerProvider::load_from_database(chain_config.clone(), db_tx), ) + .await .unwrap() .wallet() .unwrap(); @@ -296,13 +296,11 @@ fn verify_wallet_balance( assert_eq!(coin_balance, expected_balance); } -#[track_caller] -fn create_wallet(chain_config: Arc) -> DefaultWallet { - create_wallet_with_mnemonic(chain_config, MNEMONIC) +async fn create_wallet(chain_config: Arc) -> DefaultWallet { + create_wallet_with_mnemonic(chain_config, MNEMONIC).await } -#[track_caller] -fn create_block_with_reward_address( +async fn create_block_with_reward_address( chain_config: &Arc, wallet: &mut Wallet, transactions: Vec, @@ -323,12 +321,11 @@ where ) .unwrap(); - scan_wallet(wallet, BlockHeight::new(block_height), vec![block1.clone()]); + scan_wallet(wallet, BlockHeight::new(block_height), vec![block1.clone()]).await; block1 } -#[track_caller] -fn create_block( +async fn create_block( chain_config: &Arc, wallet: &mut Wallet, transactions: Vec, @@ -347,12 +344,12 @@ where reward, block_height, address.clone().into_object(), - ); + ) + .await; (address, block) } -#[track_caller] -fn test_balance_from_genesis( +async fn test_balance_from_genesis( chain_type: ChainType, utxos: Vec, expected_balance: Amount, @@ -372,15 +369,17 @@ fn test_balance_from_genesis( ); let db_name = random_ascii_alphanumeric_string(rng, 10..20); - let wallet = create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name); + let wallet = + create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name).await; verify_wallet_balance(&chain_config, &wallet, expected_balance, || { create_named_in_memory_store(&db_name) - }); + }) + .await; } -#[test] -fn wallet_creation_in_memory() { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_creation_in_memory() { let chain_config = Arc::new(create_regtest()); let empty_db = create_wallet_in_memory().unwrap(); let chain_config2 = chain_config.clone(); @@ -394,13 +393,15 @@ fn wallet_creation_in_memory() { WalletControllerMode::Hot, false, |db_tx| SoftwareSignerProvider::load_from_database(chain_config2, db_tx), - ) { + ) + .await + { Ok(_) => panic!("Wallet loading should fail"), Err(err) => assert_eq!(err, WalletError::WalletNotInitialized), } // initialize a new wallet with mnemonic - let wallet = create_wallet(chain_config.clone()); + let wallet = create_wallet(chain_config.clone()).await; let initialized_db = wallet.db; // successfully load a wallet from initialized db @@ -413,13 +414,15 @@ fn wallet_creation_in_memory() { false, |db_tx| SoftwareSignerProvider::load_from_database(chain_config.clone(), db_tx), ) + .await .unwrap(); } #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_migration_to_v2(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_migration_to_v2(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let address = get_address( &create_regtest(), @@ -454,13 +457,15 @@ fn wallet_migration_to_v2(#[case] seed: Seed) { )?) }, ) + .await .unwrap() .wallet() .unwrap(); verify_wallet_balance(&chain_config, &wallet, genesis_amount, || { create_named_in_memory_store(&db_name) - }); + }) + .await; let password = Some("password".into()); wallet.encrypt_wallet(&password).unwrap(); @@ -512,6 +517,7 @@ fn wallet_migration_to_v2(#[case] seed: Seed) { false, |db_tx| SoftwareSignerProvider::load_from_database(chain_config.clone(), db_tx), ) + .await .unwrap() .wallet() .unwrap(); @@ -529,13 +535,15 @@ fn wallet_migration_to_v2(#[case] seed: Seed) { ); verify_wallet_balance(&chain_config, &wallet, genesis_amount, || { create_named_in_memory_store(&new_db_name) - }); + }) + .await; } #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_seed_phrase_retrieval(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_seed_phrase_retrieval(#[case] seed: Seed) { use wallet_types::seed_phrase::SeedPhraseLanguage; let mut rng = make_seedable_rng(seed); @@ -543,7 +551,7 @@ fn wallet_seed_phrase_retrieval(#[case] seed: Seed) { // create wallet without saving the seed phrase { - let wallet = create_wallet(chain_config.clone()); + let wallet = create_wallet(chain_config.clone()).await; let seed_phrase = wallet.seed_phrase().unwrap(); assert!(seed_phrase.is_none()); } @@ -572,6 +580,7 @@ fn wallet_seed_phrase_retrieval(#[case] seed: Seed) { )?) }, ) + .await .unwrap() .wallet() .unwrap(); @@ -646,8 +655,8 @@ fn wallet_seed_phrase_retrieval(#[case] seed: Seed) { assert!(seed_phrase.is_none()); } -#[test] -fn wallet_seed_phrase_check_address() { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_seed_phrase_check_address() { let chain_config = Arc::new(create_mainnet()); // create wallet with saving the seed phrase @@ -669,6 +678,7 @@ fn wallet_seed_phrase_check_address() { )?) }, ) + .await .unwrap() .wallet() .unwrap(); @@ -712,6 +722,7 @@ fn wallet_seed_phrase_check_address() { )?) }, ) + .await .unwrap() .wallet() .unwrap(); @@ -735,7 +746,8 @@ fn wallet_seed_phrase_check_address() { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_balance_genesis(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_balance_genesis(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_type = ChainType::Mainnet; @@ -758,7 +770,8 @@ fn wallet_balance_genesis(#[case] seed: Seed) { vec![genesis_output.clone()], genesis_amount, &mut rng, - ); + ) + .await; let genesis_amount_2 = Amount::from_atoms(54321); let genesis_output_2 = TxOutput::LockThenTransfer( @@ -772,7 +785,8 @@ fn wallet_balance_genesis(#[case] seed: Seed) { vec![genesis_output, genesis_output_2], (genesis_amount + genesis_amount_2).unwrap(), &mut rng, - ); + ) + .await; let address_indexes = [0, LOOKAHEAD_SIZE - 1, LOOKAHEAD_SIZE]; for purpose in KeyPurpose::ALL { @@ -790,14 +804,16 @@ fn wallet_balance_genesis(#[case] seed: Seed) { let genesis_output = make_address_output(address.into_object(), genesis_amount); if address_index.into_u32() == LOOKAHEAD_SIZE { - test_balance_from_genesis(chain_type, vec![genesis_output], Amount::ZERO, &mut rng); + test_balance_from_genesis(chain_type, vec![genesis_output], Amount::ZERO, &mut rng) + .await; } else { test_balance_from_genesis( chain_type, vec![genesis_output], genesis_amount, &mut rng, - ); + ) + .await; } } } @@ -806,7 +822,8 @@ fn wallet_balance_genesis(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn locked_wallet_balance_works(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn locked_wallet_balance_works(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_type = ChainType::Mainnet; let genesis_amount = Amount::from_atoms(rng.gen_range(1..10000)); @@ -833,7 +850,7 @@ fn locked_wallet_balance_works(#[case] seed: Seed) { .build(), ); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, genesis_amount); @@ -849,13 +866,14 @@ fn locked_wallet_balance_works(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_balance_block_reward(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_balance_block_reward(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); let db_name = random_ascii_alphanumeric_string(&mut rng, 10..20); let mut wallet = - create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name); + create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -865,7 +883,7 @@ fn wallet_balance_block_reward(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(10000); - let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; // Verify that the first block reward has been received let (best_block_id, best_block_height) = get_best_block(&wallet); @@ -873,7 +891,8 @@ fn wallet_balance_block_reward(#[case] seed: Seed) { assert_eq!(best_block_height, BlockHeight::new(1)); verify_wallet_balance(&chain_config, &wallet, block1_amount, || { create_named_in_memory_store(&db_name) - }); + }) + .await; // Create the second block that sends the reward to the wallet let block2_amount = Amount::from_atoms(20000); @@ -896,7 +915,7 @@ fn wallet_balance_block_reward(#[case] seed: Seed) { ) .unwrap(); let block2_id = block2.header().block_id(); - scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2]); + scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2]).await; // Verify that the second block reward is also received let (best_block_id, best_block_height) = get_best_block(&wallet); @@ -907,7 +926,8 @@ fn wallet_balance_block_reward(#[case] seed: Seed) { &wallet, (block1_amount + block2_amount).unwrap(), || create_named_in_memory_store(&db_name), - ); + ) + .await; // Create a new block to replace the second block let block2_amount_new = Amount::from_atoms(30000); @@ -930,7 +950,7 @@ fn wallet_balance_block_reward(#[case] seed: Seed) { ) .unwrap(); let block2_new_id = block2_new.header().block_id(); - scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2_new]); + scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2_new]).await; // Verify that the balance includes outputs from block1 and block2_new, but not block2 let (best_block_id, best_block_height) = get_best_block(&wallet); @@ -941,19 +961,21 @@ fn wallet_balance_block_reward(#[case] seed: Seed) { &wallet, (block1_amount + block2_amount_new).unwrap(), || create_named_in_memory_store(&db_name), - ); + ) + .await; } #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_balance_block_transactions(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_balance_block_transactions(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); let db_name = random_ascii_alphanumeric_string(&mut rng, 10..20); let mut wallet = - create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name); + create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name).await; let tx_amount1 = Amount::from_atoms(10000); let address = get_address( @@ -977,24 +999,27 @@ fn wallet_balance_block_transactions(#[case] seed: Seed) { vec![signed_transaction1], Amount::ZERO, 0, - ); + ) + .await; verify_wallet_balance(&chain_config, &wallet, tx_amount1, || { create_named_in_memory_store(&db_name) - }); + }) + .await; } // Verify that outputs can be created and consumed in the same block #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_balance_parent_child_transactions(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_balance_parent_child_transactions(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); let db_name = random_ascii_alphanumeric_string(&mut rng, 10..20); let mut wallet = - create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name); + create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name).await; let tx_amount1 = Amount::from_atoms(20000); let tx_amount2 = Amount::from_atoms(10000); @@ -1038,15 +1063,16 @@ fn wallet_balance_parent_child_transactions(#[case] seed: Seed) { vec![signed_transaction1, signed_transaction2], Amount::ZERO, 0, - ); + ) + .await; verify_wallet_balance(&chain_config, &wallet, tx_amount2, || { create_named_in_memory_store(&db_name) - }); + }) + .await; } -#[track_caller] -fn test_wallet_accounts( +async fn test_wallet_accounts( chain_config: &Arc, wallet: &Wallet, expected_accounts: Vec, @@ -1069,6 +1095,7 @@ fn test_wallet_accounts( false, |db_tx| SoftwareSignerProvider::load_from_database(chain_config.clone(), db_tx), ) + .await .unwrap() .wallet() .unwrap(); @@ -1086,11 +1113,12 @@ async fn wallet_accounts_creation(#[case] seed: Seed) { let db_name = random_ascii_alphanumeric_string(&mut rng, 10..20); let mut wallet = - create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name); + create_wallet_with_mnemonic_and_named_db(chain_config.clone(), MNEMONIC, &db_name).await; test_wallet_accounts(&chain_config, &wallet, vec![DEFAULT_ACCOUNT_INDEX], || { create_named_in_memory_store(&db_name) - }); + }) + .await; // DEFAULT_ACCOUNT_INDEX now has 1 transaction so next account can be created let _ = create_block( &chain_config, @@ -1098,13 +1126,14 @@ async fn wallet_accounts_creation(#[case] seed: Seed) { vec![], Amount::from_atoms(100), 0, - ); + ) + .await; - let res = wallet.create_next_account(Some("name".into())).unwrap(); + let res = wallet.create_next_account(Some("name".into())).await.unwrap(); assert_eq!(res, (U31::from_u32(1).unwrap(), Some("name".into()))); // but we cannot create a third account as the new one has no transactions - let error = wallet.create_next_account(None).err().unwrap(); + let error = wallet.create_next_account(None).await.err().unwrap(); assert_eq!(error, WalletError::EmptyLastAccount); let acc1_pk = wallet.get_new_address(res.0).unwrap().1; @@ -1127,33 +1156,34 @@ async fn wallet_accounts_creation(#[case] seed: Seed) { // even with an unconfirmed transaction we cannot create a new account wallet.add_unconfirmed_tx(tx.clone(), &WalletEventsNoOp).unwrap(); - let error = wallet.create_next_account(None).err().unwrap(); + let error = wallet.create_next_account(None).await.err().unwrap(); assert_eq!(error, WalletError::EmptyLastAccount); // after getting a confirmed transaction we can create a new account - let _ = create_block(&chain_config, &mut wallet, vec![tx], Amount::ZERO, 1); - let res = wallet.create_next_account(Some("name2".into())).unwrap(); + let _ = create_block(&chain_config, &mut wallet, vec![tx], Amount::ZERO, 1).await; + let res = wallet.create_next_account(Some("name2".into())).await.unwrap(); assert_eq!(res, (U31::from_u32(2).unwrap(), Some("name2".into()))); } #[rstest] #[trace] #[case(Seed::from_entropy())] -fn locked_wallet_accounts_creation_fail(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn locked_wallet_accounts_creation_fail(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; // Need at least one address used from the previous account in order to create a new account // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 1..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let password = Some(gen_random_password(&mut rng)); wallet.encrypt_wallet(&password).unwrap(); wallet.lock_wallet().unwrap(); - let err = wallet.create_next_account(None); + let err = wallet.create_next_account(None).await; assert_eq!( err, Err(WalletError::DatabaseError( @@ -1166,10 +1196,11 @@ fn locked_wallet_accounts_creation_fail(#[case] seed: Seed) { // success after unlock wallet.unlock_wallet(&password.unwrap()).unwrap(); if name.is_empty() { - let err = wallet.create_next_account(Some(name)); + let err = wallet.create_next_account(Some(name)).await; assert_eq!(err, Err(WalletError::EmptyAccountName)); } else { - let (new_account_index, new_name) = wallet.create_next_account(Some(name.clone())).unwrap(); + let (new_account_index, new_name) = + wallet.create_next_account(Some(name.clone())).await.unwrap(); assert_ne!(new_account_index, DEFAULT_ACCOUNT_INDEX); assert_eq!(new_name.unwrap(), name); assert_eq!(wallet.number_of_accounts(), 2); @@ -1179,48 +1210,49 @@ fn locked_wallet_accounts_creation_fail(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_recover_new_account(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_recover_new_account(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; - let err = wallet.create_next_account(None).err().unwrap(); + let err = wallet.create_next_account(None).await.err().unwrap(); assert_eq!(err, WalletError::EmptyLastAccount); let mut total_amounts = BTreeMap::new(); let mut last_account_index = DEFAULT_ACCOUNT_INDEX; - let blocks = (0..rng.gen_range(1..100)) - .map(|idx| { - let tx_amount1 = Amount::from_atoms(rng.gen_range(1..10)); - total_amounts - .entry(last_account_index) - .and_modify(|amount: &mut Amount| *amount = (*amount + tx_amount1).unwrap()) - .or_insert(tx_amount1); + let mut blocks = vec![]; + for idx in 0..rng.gen_range(1..100) { + let tx_amount1 = Amount::from_atoms(rng.gen_range(1..10)); + total_amounts + .entry(last_account_index) + .and_modify(|amount: &mut Amount| *amount = (*amount + tx_amount1).unwrap()) + .or_insert(tx_amount1); - let address = wallet.get_new_address(last_account_index).unwrap().1; + let address = wallet.get_new_address(last_account_index).unwrap().1; - let transaction1 = Transaction::new( - 0, - Vec::new(), - vec![make_address_output(address.into_object(), tx_amount1)], - ) - .unwrap(); - let signed_transaction1 = SignedTransaction::new(transaction1, Vec::new()).unwrap(); - let (_, block) = create_block( - &chain_config, - &mut wallet, - vec![signed_transaction1], - Amount::ZERO, - idx, - ); + let transaction1 = Transaction::new( + 0, + Vec::new(), + vec![make_address_output(address.into_object(), tx_amount1)], + ) + .unwrap(); + let signed_transaction1 = SignedTransaction::new(transaction1, Vec::new()).unwrap(); + let (_, block) = create_block( + &chain_config, + &mut wallet, + vec![signed_transaction1], + Amount::ZERO, + idx, + ) + .await; - if rng.gen_bool(0.2) { - last_account_index = wallet.create_next_account(None).unwrap().0; - } - block - }) - .collect_vec(); + if rng.gen_bool(0.2) { + last_account_index = wallet.create_next_account(None).await.unwrap().0; + } + blocks.push(block); + } // verify all accounts have the expected balances for (acc_idx, expected_balance) in total_amounts.iter() { @@ -1229,9 +1261,9 @@ fn wallet_recover_new_account(#[case] seed: Seed) { } // Create a new wallet with the same mnemonic - let mut wallet = create_wallet(chain_config); + let mut wallet = create_wallet(chain_config).await; // scan the blocks again - scan_wallet(&mut wallet, BlockHeight::new(0), blocks.clone()); + scan_wallet(&mut wallet, BlockHeight::new(0), blocks.clone()).await; // verify the wallet has recovered all of the accounts assert_eq!(wallet.number_of_accounts(), total_amounts.len(),); @@ -1251,14 +1283,14 @@ async fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 1..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let password = Some(gen_random_password(&mut rng)); wallet.encrypt_wallet(&password).unwrap(); @@ -1352,7 +1384,7 @@ async fn locked_wallet_standalone_keys( let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -1396,7 +1428,8 @@ async fn locked_wallet_standalone_keys( block1_amount, 0, standalone_destination, - ); + ) + .await; } else { // test that wallet will recognise a destination belonging to a standalone key in a // transaction @@ -1414,7 +1447,7 @@ async fn locked_wallet_standalone_keys( ) .unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]).await; // check the transaction has been added to the wallet let tx_data = wallet @@ -1491,10 +1524,10 @@ async fn wallet_get_transaction(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(100000..1000000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -1534,7 +1567,8 @@ async fn wallet_get_transaction(#[case] seed: Seed) { vec![tx.clone()], Amount::ZERO, 1, - ); + ) + .await; let found_tx = wallet.get_transaction(DEFAULT_ACCOUNT_INDEX, tx_id).unwrap(); assert_eq!( @@ -1552,10 +1586,10 @@ async fn wallet_list_mainchain_transactions(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(100000..1000000)); - let (addr, _) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let (addr, _) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let dest = addr.into_object(); let coin_balance = get_coin_balance(&wallet); @@ -1585,7 +1619,8 @@ async fn wallet_list_mainchain_transactions(#[case] seed: Seed) { vec![tx.clone()], Amount::ZERO, 1, - ); + ) + .await; let tx = wallet .create_transaction_to_addresses( @@ -1608,7 +1643,8 @@ async fn wallet_list_mainchain_transactions(#[case] seed: Seed) { vec![tx.clone()], Amount::ZERO, 2, - ); + ) + .await; let txs = wallet.mainchain_transactions(DEFAULT_ACCOUNT_INDEX, Some(dest), 100).unwrap(); // should have 2 txs the send to and the spent from @@ -1637,14 +1673,14 @@ async fn wallet_transactions_with_fees(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(30000000..50000000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -1755,7 +1791,7 @@ async fn wallet_transactions_with_fees(#[case] seed: Seed) { // make sure we have selected all of the previously created outputs assert!(selected_utxos.len() >= num_outputs as usize); - let account1 = wallet.create_next_account(None).unwrap().0; + let account1 = wallet.create_next_account(None).await.unwrap().0; let address2 = wallet.get_new_address(account1).unwrap().1.into_object(); let feerate = FeeRate::from_amount_per_kb(Amount::from_atoms(rng.gen_range(1..1000))); let SignedTxWithFees { tx, fees } = wallet @@ -1802,11 +1838,11 @@ async fn wallet_transactions_with_fees(#[case] seed: Seed) { assert_eq!(*exact_fee, *fees.get(&Currency::Coin).unwrap()); } -#[test] -fn lock_wallet_fail_empty_password() { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn lock_wallet_fail_empty_password() { let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config); + let mut wallet = create_wallet(chain_config).await; let empty_password = Some(String::new()); assert_eq!( wallet.encrypt_wallet(&empty_password), @@ -1824,7 +1860,7 @@ async fn spend_from_user_specified_utxos(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; // Generate a new block which sends reward to the wallet let utxo_amount = Amount::from_atoms(rng.gen_range(100..10000)); @@ -1848,7 +1884,7 @@ async fn spend_from_user_specified_utxos(#[case] seed: Seed) { BlockReward::new(reward_outputs), ) .unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]).await; let utxos = wallet .get_utxos( @@ -1959,14 +1995,14 @@ async fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -2026,7 +2062,8 @@ async fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -2088,7 +2125,7 @@ async fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { ) .unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(2), vec![block3.clone()]); + scan_wallet(&mut wallet, BlockHeight::new(2), vec![block3.clone()]).await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert_eq!(pool_ids.len(), 1); @@ -2099,7 +2136,7 @@ async fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { ); // do a reorg back to block 2 - scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2.clone()]); + scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2.clone()]).await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert_eq!(pool_ids.len(), 1); let (pool_id, pool_data) = pool_ids.first().unwrap(); @@ -2126,7 +2163,8 @@ async fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { vec![decommission_tx], Amount::ZERO, 2, - ); + ) + .await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::Stake).unwrap(); @@ -2153,8 +2191,8 @@ async fn create_stake_pool_for_different_wallet_and_list_pool_ids(#[case] seed: let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; let coin_balance1 = get_coin_balance(&wallet1); assert_eq!(coin_balance1, Amount::ZERO); @@ -2163,8 +2201,8 @@ async fn create_stake_pool_for_different_wallet_and_list_pool_ids(#[case] seed: // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]); + let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]).await; let pool_ids1 = wallet1.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids1.is_empty()); @@ -2262,8 +2300,9 @@ async fn create_stake_pool_for_different_wallet_and_list_pool_ids(#[case] seed: vec![stake_pool_transaction], Amount::ZERO, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2.clone()]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2.clone()]).await; let coin_balance1 = get_coin_balance(&wallet1); assert_eq!(coin_balance1, Amount::ZERO); @@ -2348,8 +2387,8 @@ async fn create_stake_pool_for_different_wallet_and_list_pool_ids(#[case] seed: ) .unwrap(); - scan_wallet(&mut wallet1, BlockHeight::new(2), vec![block3.clone()]); - scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3.clone()]); + scan_wallet(&mut wallet1, BlockHeight::new(2), vec![block3.clone()]).await; + scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3.clone()]).await; let pool_ids_for_staking1 = wallet1.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::Stake).unwrap(); @@ -2402,8 +2441,9 @@ async fn create_stake_pool_for_different_wallet_and_list_pool_ids(#[case] seed: vec![decommission_tx], Amount::ZERO, 3, - ); - scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]).await; let pool_ids1 = wallet1.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids1.is_empty()); @@ -2424,14 +2464,14 @@ async fn reset_keys_after_failed_transaction(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -2477,8 +2517,8 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -2493,13 +2533,15 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { vec![], block1_amount, block_height, - ); + ) + .await; scan_wallet( &mut wallet2, BlockHeight::new(block_height), vec![block.clone()], - ); + ) + .await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, delegation_amount); @@ -2513,13 +2555,15 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { vec![], block1_amount, block_height, - ); + ) + .await; scan_wallet( &mut wallet, BlockHeight::new(block_height), vec![block.clone()], - ); + ) + .await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, delegation_amount); @@ -2549,12 +2593,14 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { vec![delegation_tx], Amount::ZERO, block_height, - ); + ) + .await; scan_wallet( &mut wallet2, BlockHeight::new(block_height), vec![block.clone()], - ); + ) + .await; let delegation_data = wallet2.get_delegation(DEFAULT_ACCOUNT_INDEX, wallet2_delegation_id).unwrap(); @@ -2584,12 +2630,14 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { vec![delegation_stake_tx], block1_amount, block_height, - ); + ) + .await; scan_wallet( &mut wallet2, BlockHeight::new(block_height), vec![block.clone()], - ); + ) + .await; // Wallet2 should see the transaction and know that someone has staked to the delegation let delegation_data = @@ -2601,7 +2649,7 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); - let (other_acc_idx, _) = wallet.create_next_account(None).unwrap(); + let (other_acc_idx, _) = wallet.create_next_account(None).await.unwrap(); let address = wallet.get_new_address(other_acc_idx).unwrap().1; let unknown_pool_id = PoolId::new(H256::zero()); @@ -2625,7 +2673,8 @@ async fn send_to_unknown_delegation(#[case] seed: Seed) { vec![delegation_tx], Amount::ZERO, 2, - ); + ) + .await; // the new delegation even though created from DEFAULT_ACCOUNT_INDEX is not theirs assert_eq!( @@ -2646,7 +2695,7 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -2654,7 +2703,7 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let delegation_amount = Amount::from_atoms(rng.gen_range(2..100)); let block1_amount = (chain_config.min_stake_pool_pledge() + delegation_amount).unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -2688,7 +2737,8 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, (block1_amount - pool_amount).unwrap(),); @@ -2717,7 +2767,8 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { vec![delegation_tx], Amount::ZERO, 2, - ); + ) + .await; let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); assert_eq!(delegations.len(), 1); @@ -2748,7 +2799,8 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { vec![delegation_stake_tx], Amount::ZERO, 3, - ); + ) + .await; let delegation_tx1 = wallet .create_transaction_to_addresses_from_delegation( @@ -2781,7 +2833,7 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { // Send delegation to account 1 // test that account 1 will receive the money but not register the delegation id as theirs - let (other_acc_idx, _) = wallet.create_next_account(None).unwrap(); + let (other_acc_idx, _) = wallet.create_next_account(None).await.unwrap(); let address = wallet.get_new_address(other_acc_idx).unwrap().1; let delegation_tx2 = wallet @@ -2811,7 +2863,8 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { assert_eq!(*deleg_id, delegation_id); assert_eq!(deleg_data.last_nonce, Some(AccountNonce::new(1))); - let (_, block5) = create_block(&chain_config, &mut wallet, delegation_tx1, Amount::ZERO, 4); + let (_, block5) = + create_block(&chain_config, &mut wallet, delegation_tx1, Amount::ZERO, 4).await; let _ = create_block( &chain_config, @@ -2819,7 +2872,8 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { vec![delegation_tx2.clone()], Amount::ZERO, 5, - ); + ) + .await; // Check delegation balance after confirmed tx status let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); @@ -2840,7 +2894,7 @@ async fn create_spend_from_delegations(#[case] seed: Seed) { assert!(delegations.is_empty()); // roll back the delegation tx to test removal code - scan_wallet(&mut wallet, BlockHeight::new(4), vec![block5]); + scan_wallet(&mut wallet, BlockHeight::new(4), vec![block5]).await; let coin_balance = wallet .get_balance(other_acc_idx, UtxoState::Confirmed.into(), WithLocked::Any) @@ -2899,8 +2953,8 @@ async fn issue_and_transfer_tokens(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -2941,8 +2995,9 @@ async fn issue_and_transfer_tokens(#[case] seed: Seed) { vec![], block1_amount, 0, - ); - scan_wallet(other_wallet, BlockHeight::new(0), vec![block.clone()]); + ) + .await; + scan_wallet(other_wallet, BlockHeight::new(0), vec![block.clone()]).await; let coin_balance = get_coin_balance(random_issuing_wallet); assert_eq!(coin_balance, block1_amount); @@ -3099,7 +3154,8 @@ async fn issue_and_transfer_tokens(#[case] seed: Seed) { token_issuance_transactions, block1_amount, 1, - ); + ) + .await; let (coin_balance, token_balances) = get_currency_balances(&wallet); @@ -3159,7 +3215,8 @@ async fn issue_and_transfer_tokens(#[case] seed: Seed) { vec![transfer_tokens_transaction], block1_amount, 2, - ); + ) + .await; let (coin_balance, token_balances) = get_currency_balances(&wallet); let mut expected_amount = ((block1_amount * 3).unwrap() - issuance_fee).unwrap(); @@ -3226,7 +3283,7 @@ async fn check_tokens_v0_are_ignored(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -3236,7 +3293,7 @@ async fn check_tokens_v0_are_ignored(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -3287,7 +3344,7 @@ async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -3297,7 +3354,7 @@ async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { + (chain_config.fungible_token_issuance_fee() * 4).unwrap()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -3331,7 +3388,8 @@ async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { vec![token_issuance_transaction], block1_amount, 1, - ); + ) + .await; let freezable = token_issuance.is_freezable.as_bool(); let token_info = RPCFungibleTokenInfo::new( @@ -3364,7 +3422,7 @@ async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { .unwrap() .tx; - let _ = create_block(&chain_config, &mut wallet, vec![mint_tx], block2_amount, 2); + let _ = create_block(&chain_config, &mut wallet, vec![mint_tx], block2_amount, 2).await; let unconfirmed_token_info = wallet .get_token_unconfirmed_info(DEFAULT_ACCOUNT_INDEX, token_info.clone()) @@ -3455,7 +3513,8 @@ async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { vec![freeze_tx, unfreeze_tx], block2_amount, 3, - ); + ) + .await; let unconfirmed_token_info = wallet .get_token_unconfirmed_info(DEFAULT_ACCOUNT_INDEX, token_info.clone()) @@ -3568,7 +3627,8 @@ async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { vec![freeze_tx], block2_amount, 4, - ); + ) + .await; // now the transfer tx should be conflicting let pending_txs = wallet.pending_transactions(DEFAULT_ACCOUNT_INDEX).unwrap(); @@ -3601,7 +3661,7 @@ async fn change_token_supply_fixed(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -3611,7 +3671,7 @@ async fn change_token_supply_fixed(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -3644,7 +3704,8 @@ async fn change_token_supply_fixed(#[case] seed: Seed) { vec![token_issuance_transaction], block1_amount, 1, - ); + ) + .await; let freezable = token_issuance.is_freezable.as_bool(); let mut token_info = RPCFungibleTokenInfo::new( @@ -3763,7 +3824,8 @@ async fn change_token_supply_fixed(#[case] seed: Seed) { vec![mint_transaction], block2_amount, 2, - ); + ) + .await; token_info.circulating_supply = unconfirmed_token_info.current_supply().unwrap(); let unconfirmed_token_info = wallet @@ -3824,7 +3886,8 @@ async fn change_token_supply_fixed(#[case] seed: Seed) { vec![unmint_transaction], block2_amount, 3, - ); + ) + .await; token_info.circulating_supply = unconfirmed_token_info.current_supply().unwrap(); let unconfirmed_token_info = wallet @@ -3865,7 +3928,7 @@ async fn change_token_supply_unlimited(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -3875,7 +3938,7 @@ async fn change_token_supply_unlimited(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -3908,7 +3971,8 @@ async fn change_token_supply_unlimited(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); + ) + .await; let freezable = token_issuance.is_freezable.as_bool(); let mut token_info = RPCFungibleTokenInfo::new( @@ -3967,7 +4031,8 @@ async fn change_token_supply_unlimited(#[case] seed: Seed) { vec![mint_transaction], block2_amount, 2, - ); + ) + .await; token_info.circulating_supply = unconfirmed_token_info.current_supply().unwrap(); let unconfirmed_token_info = wallet @@ -4027,7 +4092,8 @@ async fn change_token_supply_unlimited(#[case] seed: Seed) { vec![unmint_transaction], block2_amount, 3, - ); + ) + .await; token_info.circulating_supply = unconfirmed_token_info.current_supply().unwrap(); let unconfirmed_token_info = wallet @@ -4068,7 +4134,7 @@ async fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -4078,7 +4144,7 @@ async fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -4111,7 +4177,8 @@ async fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); + ) + .await; let freezable = token_issuance.is_freezable.as_bool(); let mut token_info = RPCFungibleTokenInfo::new( @@ -4169,7 +4236,8 @@ async fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { vec![mint_transaction], block2_amount, 2, - ); + ) + .await; token_info.circulating_supply = unconfirmed_token_info.current_supply().unwrap(); let unconfirmed_token_info = wallet @@ -4230,7 +4298,8 @@ async fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { vec![unmint_transaction], block2_amount, 3, - ); + ) + .await; token_info.circulating_supply = unconfirmed_token_info.current_supply().unwrap(); let unconfirmed_token_info = wallet @@ -4265,7 +4334,8 @@ async fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { vec![lock_transaction], block2_amount, 4, - ); + ) + .await; token_info.is_locked = true; let unconfirmed_token_info = wallet @@ -4331,7 +4401,7 @@ async fn lock_then_transfer(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -4364,7 +4434,7 @@ async fn lock_then_transfer(#[case] seed: Seed) { // not important that it is not the actual median wallet.set_median_time(timestamp).unwrap(); let timestamp = block1.timestamp().add_int_seconds(seconds_between_blocks).unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]).await; // check balance let coin_balance = get_coin_balance(&wallet); @@ -4419,7 +4489,7 @@ async fn lock_then_transfer(#[case] seed: Seed) { // not important that it is not the actual median wallet.set_median_time(timestamp).unwrap(); let mut timestamp = block2.timestamp().add_int_seconds(seconds_between_blocks).unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2]); + scan_wallet(&mut wallet, BlockHeight::new(1), vec![block2]).await; // check balance let balance_without_locked_transfer = @@ -4458,7 +4528,7 @@ async fn lock_then_transfer(#[case] seed: Seed) { // not important that it is not the actual median wallet.set_median_time(timestamp).unwrap(); timestamp = new_block.timestamp().add_int_seconds(seconds_between_blocks).unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(2 + idx), vec![new_block]); + scan_wallet(&mut wallet, BlockHeight::new(2 + idx), vec![new_block]).await; } // check that after block_count_lock, the amount is included @@ -4477,7 +4547,7 @@ async fn wallet_multiple_transactions_in_single_block(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let blocks_to_add = rng.gen_range(1..10); @@ -4485,7 +4555,7 @@ async fn wallet_multiple_transactions_in_single_block(#[case] seed: Seed) { for i in 0..blocks_to_add { // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 1..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, i as u64); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, i as u64).await; amounts.push(block1_amount); } @@ -4541,7 +4611,8 @@ async fn wallet_multiple_transactions_in_single_block(#[case] seed: Seed) { transactions, Amount::ZERO, blocks_to_add as u64, - ); + ) + .await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, total_change); @@ -4555,7 +4626,7 @@ async fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -4570,7 +4641,7 @@ async fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { (NETWORK_FEE + 1) * (total_num_transactions as u128) ..=(NETWORK_FEE + 1) * (total_num_transactions as u128) + 10000, )); - let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -4663,10 +4734,10 @@ async fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { wallet.scan_mempool(transactions.as_slice(), &WalletEventsNoOp).unwrap(); // create new wallet - let mut wallet = create_wallet(chain_config); + let mut wallet = create_wallet(chain_config).await; // scan the first block - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]).await; // scan mempool transaction in random order transactions.shuffle(&mut rng); @@ -4746,7 +4817,7 @@ async fn wallet_abandon_transactions(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -4759,7 +4830,7 @@ async fn wallet_abandon_transactions(#[case] seed: Seed) { (NETWORK_FEE + 1) * (total_num_transactions as u128) ..=(NETWORK_FEE + 1) * (total_num_transactions as u128) + 10000, )); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -4882,10 +4953,11 @@ async fn wallet_abandon_transactions(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_address_usage(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_address_usage(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let usage = wallet .get_addresses_usage(DEFAULT_ACCOUNT_INDEX, KeyPurpose::ReceiveFunds) @@ -4909,7 +4981,7 @@ fn wallet_address_usage(#[case] seed: Seed) { ); let block1_amount = Amount::from_atoms(10000); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let last_used = addresses_to_issue + 1; let usage = wallet @@ -4922,10 +4994,11 @@ fn wallet_address_usage(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_set_lookahead_size(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_set_lookahead_size(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let usage = wallet .get_addresses_usage(DEFAULT_ACCOUNT_INDEX, KeyPurpose::ReceiveFunds) @@ -4949,7 +5022,7 @@ fn wallet_set_lookahead_size(#[case] seed: Seed) { ); let block1_amount = Amount::from_atoms(10000); - let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let last_used = addresses_to_issue + 1; let usage = wallet @@ -4970,7 +5043,7 @@ fn wallet_set_lookahead_size(#[case] seed: Seed) { wallet.set_lookahead_size(less_than_last_used, true).unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]).await; let coins = get_coin_balance_for_acc(&wallet, DEFAULT_ACCOUNT_INDEX); assert_eq!(coins, Amount::ZERO); let usage = wallet @@ -4982,7 +5055,7 @@ fn wallet_set_lookahead_size(#[case] seed: Seed) { let more_than_last_used = rng.gen_range(last_used + 1..100); wallet.set_lookahead_size(more_than_last_used, false).unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]).await; let coins = get_coin_balance_for_acc(&wallet, DEFAULT_ACCOUNT_INDEX); assert_eq!(coins, block1_amount); let usage = wallet @@ -5003,14 +5076,14 @@ async fn decommission_pool_wrong_account(#[case] seed: Seed) { let acc_0_index = DEFAULT_ACCOUNT_INDEX; let acc_1_index = U31::ONE; - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let pool_ids = wallet.get_pool_ids(acc_0_index, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -5020,7 +5093,7 @@ async fn decommission_pool_wrong_account(#[case] seed: Seed) { let pool_amount = block1_amount; - let res = wallet.create_next_account(Some("name".into())).unwrap(); + let res = wallet.create_next_account(Some("name".into())).await.unwrap(); assert_eq!(res, (U31::from_u32(1).unwrap(), Some("name".into()))); let decommission_key = wallet.get_new_address(acc_1_index).unwrap().1; @@ -5048,7 +5121,8 @@ async fn decommission_pool_wrong_account(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; let pool_ids = wallet.get_pool_ids(acc_0_index, WalletPoolsFilter::All).unwrap(); assert_eq!(pool_ids.len(), 1); @@ -5088,7 +5162,8 @@ async fn decommission_pool_wrong_account(#[case] seed: Seed) { vec![decommission_tx], Amount::ZERO, 2, - ); + ) + .await; let coin_balance = get_coin_balance_for_acc(&wallet, acc_1_index); assert_eq!(coin_balance, pool_amount); @@ -5105,14 +5180,14 @@ async fn decommission_pool_request_wrong_account(#[case] seed: Seed) { let acc_0_index = DEFAULT_ACCOUNT_INDEX; let acc_1_index = U31::ONE; - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let pool_ids = wallet.get_pool_ids(acc_0_index, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -5122,7 +5197,7 @@ async fn decommission_pool_request_wrong_account(#[case] seed: Seed) { let pool_amount = block1_amount; - let res = wallet.create_next_account(Some("name".into())).unwrap(); + let res = wallet.create_next_account(Some("name".into())).await.unwrap(); assert_eq!(res, (U31::from_u32(1).unwrap(), Some("name".into()))); let decommission_key = wallet.get_new_address(acc_1_index).unwrap().1; @@ -5150,7 +5225,8 @@ async fn decommission_pool_request_wrong_account(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; let pool_ids = wallet.get_pool_ids(acc_0_index, WalletPoolsFilter::All).unwrap(); assert_eq!(pool_ids.len(), 1); @@ -5199,14 +5275,14 @@ async fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { let acc_0_index = DEFAULT_ACCOUNT_INDEX; let acc_1_index = U31::ONE; - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let (addr, _) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let (addr, _) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let utxo = make_address_output(addr.clone().into_object(), block1_amount); let pool_ids = wallet.get_pool_ids(acc_0_index, WalletPoolsFilter::All).unwrap(); @@ -5217,7 +5293,7 @@ async fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { let pool_amount = block1_amount; - let res = wallet.create_next_account(Some("name".into())).unwrap(); + let res = wallet.create_next_account(Some("name".into())).await.unwrap(); assert_eq!(res, (U31::from_u32(1).unwrap(), Some("name".into()))); let decommission_key = wallet.get_new_address(acc_1_index).unwrap().1; @@ -5266,7 +5342,8 @@ async fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; assert_eq!(get_coin_balance(&wallet), Amount::ZERO); @@ -5311,7 +5388,7 @@ async fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { .into_signed_tx() .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![signed_tx], Amount::ZERO, 2); + let _ = create_block(&chain_config, &mut wallet, vec![signed_tx], Amount::ZERO, 2).await; // the pool amount is back after decommission assert_eq!(get_coin_balance(&wallet), pool_amount); @@ -5326,12 +5403,12 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut hot_wallet = create_wallet(chain_config.clone()); + let mut hot_wallet = create_wallet(chain_config.clone()).await; // create cold wallet that is not synced and only contains decommission key let another_mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"; - let mut cold_wallet = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic); + let mut cold_wallet = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic).await; let decommission_key = cold_wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; let coin_balance = get_coin_balance(&hot_wallet); @@ -5339,7 +5416,7 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut hot_wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut hot_wallet, vec![], block1_amount, 0).await; let pool_ids = hot_wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -5349,7 +5426,7 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { let pool_amount = block1_amount; - let res = hot_wallet.create_next_account(Some("name".into())).unwrap(); + let res = hot_wallet.create_next_account(Some("name".into())).await.unwrap(); assert_eq!(res, (U31::from_u32(1).unwrap(), Some("name".into()))); let stake_pool_transaction = hot_wallet @@ -5375,7 +5452,8 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; let pool_ids = hot_wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert_eq!(pool_ids.len(), 1); @@ -5426,7 +5504,8 @@ async fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { vec![signed_tx], Amount::ZERO, 2, - ); + ) + .await; let coin_balance = get_coin_balance(&hot_wallet); assert_eq!(coin_balance, pool_amount,); @@ -5440,12 +5519,12 @@ async fn filter_pools(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet1 = create_wallet(chain_config.clone()); + let mut wallet1 = create_wallet(chain_config.clone()).await; // create another wallet to store decommission key let another_mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"; - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic); + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic).await; let decommission_key = wallet2.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; let coin_balance = get_coin_balance(&wallet1); @@ -5453,8 +5532,8 @@ async fn filter_pools(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); - let _ = create_block(&chain_config, &mut wallet2, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; + let _ = create_block(&chain_config, &mut wallet2, vec![], block1_amount, 0).await; let pool_ids = wallet1.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -5488,7 +5567,8 @@ async fn filter_pools(#[case] seed: Seed) { vec![stake_pool_transaction.clone()], Amount::ZERO, 1, - ); + ) + .await; // sync for wallet2 let _ = create_block( &chain_config, @@ -5496,7 +5576,8 @@ async fn filter_pools(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; // check wallet1 filter let pool_ids = wallet1.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); @@ -5531,12 +5612,12 @@ async fn sign_send_request_cold_wallet(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut hot_wallet = create_wallet(chain_config.clone()); + let mut hot_wallet = create_wallet(chain_config.clone()).await; // create cold wallet that is not synced let another_mnemonic = "legal winner thank year wave sausage worth useful legal winner thank yellow"; - let mut cold_wallet = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic); + let mut cold_wallet = create_wallet_with_mnemonic(chain_config.clone(), another_mnemonic).await; let cold_wallet_address = cold_wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; let coin_balance = get_coin_balance(&hot_wallet); @@ -5555,7 +5636,7 @@ async fn sign_send_request_cold_wallet(#[case] seed: Seed) { ) .unwrap(); - scan_wallet(&mut hot_wallet, BlockHeight::new(0), vec![block1.clone()]); + scan_wallet(&mut hot_wallet, BlockHeight::new(0), vec![block1.clone()]).await; // hot wallet has 0 balance let coin_balance = get_coin_balance(&hot_wallet); @@ -5608,7 +5689,8 @@ async fn sign_send_request_cold_wallet(#[case] seed: Seed) { vec![signed_tx], Amount::ZERO, 1, - ); + ) + .await; let coin_balance = get_coin_balance(&hot_wallet); assert_eq!(coin_balance, to_send,); @@ -5650,7 +5732,7 @@ async fn test_not_exhaustion_of_keys(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -5668,7 +5750,7 @@ async fn test_not_exhaustion_of_keys(#[case] seed: Seed) { ) .unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1.clone()]).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -5701,8 +5783,8 @@ async fn test_add_standalone_multisig(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, Amount::ZERO); @@ -5747,7 +5829,7 @@ async fn test_add_standalone_multisig(#[case] seed: Seed) { ) .unwrap(); - scan_wallet(&mut wallet1, BlockHeight::new(0), vec![block1.clone()]); + scan_wallet(&mut wallet1, BlockHeight::new(0), vec![block1.clone()]).await; // Check amount is still zero let coin_balance = get_coin_balance(&wallet1); @@ -5835,15 +5917,15 @@ async fn create_htlc_and_spend(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, block1_amount); @@ -5899,8 +5981,9 @@ async fn create_htlc_and_spend(#[case] seed: Seed) { vec![create_htlc_tx.clone()], Amount::ZERO, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block2]).await; // Htlc is not accounted in balance assert_eq!(get_coin_balance(&wallet1), Amount::ZERO); @@ -5961,8 +6044,9 @@ async fn create_htlc_and_spend(#[case] seed: Seed) { let spend_tx = spend_ptx.into_signed_tx().unwrap(); - let (_, block2) = create_block(&chain_config, &mut wallet2, vec![spend_tx], Amount::ZERO, 1); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block2]); + let (_, block2) = + create_block(&chain_config, &mut wallet2, vec![spend_tx], Amount::ZERO, 1).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block2]).await; // Coins from htlc successfully transferred assert_eq!(get_coin_balance(&wallet1), Amount::ZERO); @@ -5979,15 +6063,15 @@ async fn create_htlc_and_refund(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = Amount::from_atoms(rng.gen_range(NETWORK_FEE + 100..NETWORK_FEE + 10000)); - let _ = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, block1_amount); @@ -6063,8 +6147,9 @@ async fn create_htlc_and_refund(#[case] seed: Seed) { vec![create_htlc_tx], Amount::ZERO, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block2]).await; // Htlc is not accounted in balance assert_eq!(get_coin_balance(&wallet1), Amount::ZERO); @@ -6126,8 +6211,9 @@ async fn create_htlc_and_refund(#[case] seed: Seed) { vec![refund_tx], Amount::ZERO, 2, - ); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block3]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block3]).await; // Refund can be seen in the wallet balance assert_eq!(get_coin_balance(&wallet1), coin_balance); @@ -6142,7 +6228,7 @@ async fn create_order(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -6152,7 +6238,7 @@ async fn create_order(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -6184,7 +6270,8 @@ async fn create_order(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); + ) + .await; // Mint some tokens let freezable = token_issuance.is_freezable.as_bool(); @@ -6224,7 +6311,8 @@ async fn create_order(#[case] seed: Seed) { vec![mint_transaction], Amount::ZERO, 2, - ); + ) + .await; let expected_balance = (block1_amount - chain_config.fungible_token_issuance_fee()).unwrap(); let (coin_balance, token_balances) = get_currency_balances(&wallet); @@ -6264,7 +6352,8 @@ async fn create_order(#[case] seed: Seed) { vec![create_order_tx], Amount::ZERO, 3, - ); + ) + .await; let (coin_balance, token_balances) = get_currency_balances(&wallet); assert_eq!(coin_balance, expected_balance); @@ -6279,7 +6368,7 @@ async fn create_order_and_conclude(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -6289,7 +6378,7 @@ async fn create_order_and_conclude(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, block1_amount); @@ -6321,7 +6410,8 @@ async fn create_order_and_conclude(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); + ) + .await; // Mint some tokens let freezable = token_issuance.is_freezable.as_bool(); @@ -6361,7 +6451,8 @@ async fn create_order_and_conclude(#[case] seed: Seed) { vec![mint_transaction], Amount::ZERO, 2, - ); + ) + .await; let expected_balance = (block1_amount - chain_config.fungible_token_issuance_fee()).unwrap(); let (coin_balance, token_balances) = get_currency_balances(&wallet); @@ -6414,7 +6505,8 @@ async fn create_order_and_conclude(#[case] seed: Seed) { vec![create_order_tx], Amount::ZERO, 3, - ); + ) + .await; let (coin_balance, token_balances) = get_currency_balances(&wallet); assert_eq!(coin_balance, expected_balance); @@ -6457,7 +6549,8 @@ async fn create_order_and_conclude(#[case] seed: Seed) { vec![conclude_order_tx], Amount::ZERO, 4, - ); + ) + .await; let (coin_balance, token_balances) = get_currency_balances(&wallet); assert_eq!(coin_balance, expected_balance); @@ -6475,8 +6568,8 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; assert_eq!(get_coin_balance(&wallet1), Amount::ZERO); assert_eq!(get_coin_balance(&wallet2), Amount::ZERO); @@ -6486,8 +6579,8 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]); + let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, block1_amount); @@ -6519,8 +6612,9 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]).await; // Mint some tokens let address2 = wallet2.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; @@ -6562,8 +6656,9 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { vec![mint_transaction], Amount::from_atoms(NETWORK_FEE), 2, - ); - scan_wallet(&mut wallet1, BlockHeight::new(2), vec![block3]); + ) + .await; + scan_wallet(&mut wallet1, BlockHeight::new(2), vec![block3]).await; { let expected_balance = @@ -6626,8 +6721,9 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { vec![create_order_tx], Amount::ZERO, 3, - ); - scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]).await; { let expected_balance = @@ -6686,8 +6782,9 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { vec![fill_order_tx_1], Amount::ZERO, 4, - ); - scan_wallet(&mut wallet1, BlockHeight::new(4), vec![block5]); + ) + .await; + scan_wallet(&mut wallet1, BlockHeight::new(4), vec![block5]).await; { let expected_balance = @@ -6762,8 +6859,9 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { vec![fill_order_tx_2], Amount::ZERO, 5, - ); - scan_wallet(&mut wallet1, BlockHeight::new(5), vec![block6]); + ) + .await; + scan_wallet(&mut wallet1, BlockHeight::new(5), vec![block6]).await; { let expected_balance = @@ -6830,8 +6928,9 @@ async fn create_order_fill_completely_conclude(#[case] seed: Seed) { vec![conclude_order_tx], Amount::ZERO, 6, - ); - scan_wallet(&mut wallet2, BlockHeight::new(6), vec![block7]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(6), vec![block7]).await; { let expected_balance = @@ -6859,8 +6958,8 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); - let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2); + let mut wallet1 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; + let mut wallet2 = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC2).await; assert_eq!(get_coin_balance(&wallet1), Amount::ZERO); assert_eq!(get_coin_balance(&wallet2), Amount::ZERO); @@ -6870,8 +6969,8 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { + chain_config.fungible_token_issuance_fee()) .unwrap(); - let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]); + let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, block1_amount); @@ -6903,8 +7002,9 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]).await; // Mint some tokens let address2 = wallet2.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; @@ -6946,8 +7046,9 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { vec![mint_transaction], Amount::from_atoms(NETWORK_FEE), 2, - ); - scan_wallet(&mut wallet1, BlockHeight::new(2), vec![block3]); + ) + .await; + scan_wallet(&mut wallet1, BlockHeight::new(2), vec![block3]).await; { let expected_balance = @@ -7010,8 +7111,9 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { vec![create_order_tx], Amount::ZERO, 3, - ); - scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]).await; { let expected_balance = @@ -7070,8 +7172,9 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { vec![fill_order_tx_1], Amount::ZERO, 4, - ); - scan_wallet(&mut wallet1, BlockHeight::new(4), vec![block5]); + ) + .await; + scan_wallet(&mut wallet1, BlockHeight::new(4), vec![block5]).await; { let expected_balance = @@ -7145,8 +7248,9 @@ async fn create_order_fill_partially_conclude(#[case] seed: Seed) { vec![conclude_order_tx], Amount::ZERO, 5, - ); - scan_wallet(&mut wallet2, BlockHeight::new(5), vec![block6]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(5), vec![block6]).await; { let expected_balance = ((block1_amount - chain_config.fungible_token_issuance_fee()) @@ -7187,8 +7291,8 @@ async fn conflicting_delegation_account_nonce(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet1 = create_wallet(chain_config.clone()); - let mut wallet2 = create_wallet(chain_config.clone()); + let mut wallet1 = create_wallet(chain_config.clone()).await; + let mut wallet2 = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, Amount::ZERO); @@ -7196,8 +7300,8 @@ async fn conflicting_delegation_account_nonce(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let delegation_amount = Amount::from_atoms(rng.gen_range(10..100)); let block1_amount = (chain_config.min_stake_pool_pledge() + delegation_amount).unwrap(); - let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]); + let (_, block1) = create_block(&chain_config, &mut wallet1, vec![], block1_amount, 0).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]).await; let pool_ids = wallet1.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -7232,8 +7336,9 @@ async fn conflicting_delegation_account_nonce(#[case] seed: Seed) { vec![stake_pool_transaction.clone()], Amount::ZERO, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]).await; let coin_balance = get_coin_balance(&wallet1); assert_eq!(coin_balance, (block1_amount - pool_amount).unwrap(),); @@ -7263,8 +7368,9 @@ async fn conflicting_delegation_account_nonce(#[case] seed: Seed) { vec![delegation_tx], Amount::ZERO, 2, - ); - scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3]).await; let mut delegations = wallet1.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); assert_eq!(delegations.len(), 1); @@ -7296,8 +7402,9 @@ async fn conflicting_delegation_account_nonce(#[case] seed: Seed) { vec![delegation_stake_tx], Amount::ZERO, 3, - ); - scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]).await; let coin_balance_after_delegating = get_coin_balance(&wallet1); assert_eq!( @@ -7381,9 +7488,10 @@ async fn conflicting_delegation_account_nonce(#[case] seed: Seed) { vec![spend_from_delegation_tx_3], Amount::ZERO, 4, - ); + ) + .await; let block5_id = block5.get_id(); - scan_wallet(&mut wallet1, BlockHeight::new(4), vec![block5]); + scan_wallet(&mut wallet1, BlockHeight::new(4), vec![block5]).await; // if confirmed tx is added conflicting txs must be removed from the output cache let mut delegations = wallet1.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); @@ -7489,7 +7597,7 @@ async fn conflicting_delegation_account_nonce_same_wallet(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -7497,7 +7605,7 @@ async fn conflicting_delegation_account_nonce_same_wallet(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let delegation_amount = Amount::from_atoms(rng.gen_range(2..100)); let block1_amount = (chain_config.min_stake_pool_pledge() + delegation_amount).unwrap(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; // Create a pool let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); @@ -7532,7 +7640,8 @@ async fn conflicting_delegation_account_nonce_same_wallet(#[case] seed: Seed) { vec![stake_pool_transaction], Amount::ZERO, 1, - ); + ) + .await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, (block1_amount - pool_amount).unwrap(),); @@ -7562,7 +7671,8 @@ async fn conflicting_delegation_account_nonce_same_wallet(#[case] seed: Seed) { vec![delegation_tx], Amount::ZERO, 2, - ); + ) + .await; let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); assert_eq!(delegations.len(), 1); @@ -7594,7 +7704,8 @@ async fn conflicting_delegation_account_nonce_same_wallet(#[case] seed: Seed) { vec![delegation_stake_tx], Amount::ZERO, 3, - ); + ) + .await; let coin_balance_after_delegating = get_coin_balance(&wallet); assert_eq!( @@ -7683,7 +7794,8 @@ async fn conflicting_delegation_account_nonce_same_wallet(#[case] seed: Seed) { vec![spend_from_delegation_tx_1], Amount::ZERO, 4, - ); + ) + .await; // Confirmed tx should replace the first one leaving the second one as descendant let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); @@ -7741,14 +7853,14 @@ async fn conflicting_order_account_nonce(#[case] seed: Seed) { .build(); let chain_config = Arc::new(chain_config); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); // Generate a new block which sends reward to the wallet let block1_amount = chain_config.fungible_token_issuance_fee(); - let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); + let _ = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; // Issue a token let address2 = wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; @@ -7777,7 +7889,8 @@ async fn conflicting_order_account_nonce(#[case] seed: Seed) { vec![token_issuance_transaction], block2_amount, 1, - ); + ) + .await; // Mint some tokens let freezable = token_issuance.is_freezable.as_bool(); @@ -7821,7 +7934,8 @@ async fn conflicting_order_account_nonce(#[case] seed: Seed) { vec![mint_transaction], reward_to_spend_on_orders, 2, - ); + ) + .await; // Create an order selling tokens for coins let buy_amount = reward_to_spend_on_orders; @@ -7849,7 +7963,8 @@ async fn conflicting_order_account_nonce(#[case] seed: Seed) { vec![create_order_tx], Amount::ZERO, 3, - ); + ) + .await; let (coin_balance_after_create_order, token_balance_after_create_order) = get_currency_balances(&wallet); @@ -7957,7 +8072,8 @@ async fn conflicting_order_account_nonce(#[case] seed: Seed) { vec![fill_order_tx_1], Amount::ZERO, 4, - ); + ) + .await; // if confirmed tx is added conflicting txs must be replaced in the output cache, leaving descendants intact let mut orders = wallet.get_orders(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); @@ -8024,8 +8140,8 @@ async fn conflicting_delegation_account_nonce_multiple_inputs(#[case] seed: Seed let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet = create_wallet(chain_config.clone()); - let mut wallet2 = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; + let mut wallet2 = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -8033,8 +8149,8 @@ async fn conflicting_delegation_account_nonce_multiple_inputs(#[case] seed: Seed // Generate a new block which sends reward to the wallet let delegation_amount = Amount::from_atoms(rng.gen_range(10..100)); let block1_amount = (chain_config.min_stake_pool_pledge() + delegation_amount).unwrap(); - let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]); + let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]).await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -8069,8 +8185,9 @@ async fn conflicting_delegation_account_nonce_multiple_inputs(#[case] seed: Seed vec![stake_pool_transaction.clone()], Amount::ZERO, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, (block1_amount - pool_amount).unwrap(),); @@ -8100,8 +8217,9 @@ async fn conflicting_delegation_account_nonce_multiple_inputs(#[case] seed: Seed vec![delegation_tx], Amount::ZERO, 2, - ); - scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3]).await; let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); assert_eq!(delegations.len(), 1); @@ -8134,8 +8252,9 @@ async fn conflicting_delegation_account_nonce_multiple_inputs(#[case] seed: Seed vec![delegation_stake_tx], Amount::ZERO, 3, - ); - scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4]).await; let coin_balance_after_delegating = get_coin_balance(&wallet); assert_eq!( @@ -8226,9 +8345,10 @@ async fn conflicting_delegation_account_nonce_multiple_inputs(#[case] seed: Seed vec![spend_from_delegation_tx_confirmed], Amount::ZERO, 4, - ); + ) + .await; let block5_id = block5.get_id(); - scan_wallet(&mut wallet, BlockHeight::new(4), vec![block5]); + scan_wallet(&mut wallet, BlockHeight::new(4), vec![block5]).await; // if confirmed tx is added conflicting txs must be removed from the output cache let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); @@ -8310,8 +8430,8 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); - let mut wallet = create_wallet(chain_config.clone()); - let mut wallet2 = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; + let mut wallet2 = create_wallet(chain_config.clone()).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -8319,8 +8439,8 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { // Generate a new block which sends reward to the wallet let delegation_amount = Amount::from_atoms(rng.gen_range(10..100)); let block1_amount = (chain_config.min_stake_pool_pledge() + delegation_amount).unwrap(); - let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0); - scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]); + let (_, block1) = create_block(&chain_config, &mut wallet, vec![], block1_amount, 0).await; + scan_wallet(&mut wallet2, BlockHeight::new(0), vec![block1]).await; let pool_ids = wallet.get_pool_ids(DEFAULT_ACCOUNT_INDEX, WalletPoolsFilter::All).unwrap(); assert!(pool_ids.is_empty()); @@ -8355,8 +8475,9 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { vec![stake_pool_transaction.clone()], Amount::ZERO, 1, - ); - scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(1), vec![block2]).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, (block1_amount - pool_amount).unwrap(),); @@ -8386,8 +8507,9 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { vec![delegation_tx], Amount::ZERO, 2, - ); - scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(2), vec![block3]).await; let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); assert_eq!(delegations.len(), 1); @@ -8419,8 +8541,9 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { vec![delegation_stake_tx], Amount::ZERO, 3, - ); - scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4.clone()]); + ) + .await; + scan_wallet(&mut wallet2, BlockHeight::new(3), vec![block4.clone()]).await; let coin_balance_after_delegating = get_coin_balance(&wallet); assert_eq!( @@ -8429,7 +8552,7 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { ); // Create an empty block to disconnect later and trigger unconfirmed tx removal - let (_, _) = create_block(&chain_config, &mut wallet, vec![], Amount::ZERO, 4); + let (_, _) = create_block(&chain_config, &mut wallet, vec![], Amount::ZERO, 4).await; // Add unconfirmed tx that spends from delegations let spend_from_delegation_tx_1 = wallet @@ -8462,7 +8585,7 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { assert_eq!(deleg_data.last_nonce, Some(AccountNonce::new(0))); // Reset empty block and unconfirmed tx - scan_wallet(&mut wallet, BlockHeight::new(3), vec![block4]); + scan_wallet(&mut wallet, BlockHeight::new(3), vec![block4]).await; // Create and submit tx with different tx id let withdraw_amount_2 = Amount::from_atoms(5); @@ -8486,9 +8609,10 @@ async fn conflicting_delegation_account_with_reorg(#[case] seed: Seed) { vec![spend_from_delegation_tx_2], Amount::ZERO, 4, - ); + ) + .await; let block5_id = block5.get_id(); - scan_wallet(&mut wallet, BlockHeight::new(4), vec![block5]); + scan_wallet(&mut wallet, BlockHeight::new(4), vec![block5]).await; // if confirmed tx is added, conflicting txs must be removed from the output cache let mut delegations = wallet.get_delegations(DEFAULT_ACCOUNT_INDEX).unwrap().collect_vec(); @@ -8548,7 +8672,7 @@ async fn rollback_utxos_after_abandon(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); - let mut wallet = create_wallet(chain_config.clone()); + let mut wallet = create_wallet(chain_config.clone()).await; // Generate a new block which sends reward to the wallet let utxo_amount = Amount::from_atoms(rng.gen_range(100..10000)); @@ -8572,7 +8696,7 @@ async fn rollback_utxos_after_abandon(#[case] seed: Seed) { BlockReward::new(reward_outputs), ) .unwrap(); - scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]); + scan_wallet(&mut wallet, BlockHeight::new(0), vec![block1]).await; let utxos = wallet .get_utxos( @@ -8675,7 +8799,7 @@ async fn token_id_generation_v1_uses_first_tx_input(#[case] seed: Seed) { .build(), ); - let mut wallet = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC); + let mut wallet = create_wallet_with_mnemonic(chain_config.clone(), MNEMONIC).await; let coin_balance = get_coin_balance(&wallet); assert_eq!(coin_balance, Amount::ZERO); @@ -8702,7 +8826,8 @@ async fn token_id_generation_v1_uses_first_tx_input(#[case] seed: Seed) { vec![], block_amount, generated_blocks_count, - ); + ) + .await; cur_balance = (cur_balance + block_amount).unwrap(); generated_blocks_count += 1; } diff --git a/wallet/src/wallet_events.rs b/wallet/src/wallet_events.rs index 9d96bef170..7ed5000d5e 100644 --- a/wallet/src/wallet_events.rs +++ b/wallet/src/wallet_events.rs @@ -20,7 +20,7 @@ use wallet_types::WalletTx; /// Callbacks that are called when the database is updated and the UI should be re-rendered. /// For example, when a new wallet is imported and the wallet scan is in progress, /// the wallet balance and address/transaction lists should be updated after these callbacks. -pub trait WalletEvents { +pub trait WalletEvents: Sync { /// New block is scanned fn new_block(&self); diff --git a/wallet/types/Cargo.toml b/wallet/types/Cargo.toml index 59e0f435c3..ba232458f1 100644 --- a/wallet/types/Cargo.toml +++ b/wallet/types/Cargo.toml @@ -22,6 +22,7 @@ bip39 = { workspace = true, default-features = false, features = [ "std", "zeroize", ] } +derive_more.workspace = true hex.workspace = true itertools.workspace = true parity-scale-codec.workspace = true diff --git a/wallet/types/src/hw_data.rs b/wallet/types/src/hw_data.rs index b7187e66f2..3ace5d596e 100644 --- a/wallet/types/src/hw_data.rs +++ b/wallet/types/src/hw_data.rs @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +use common::primitives::semver::SemVer; use serialization::{Decode, Encode}; /// This is the data that will be stored in the wallet db. @@ -32,6 +33,7 @@ pub struct TrezorFullInfo { pub firmware_version: semver::Version, } +#[cfg(feature = "trezor")] impl From for TrezorData { fn from(info: TrezorFullInfo) -> Self { Self { @@ -41,10 +43,25 @@ impl From for TrezorData { } } +/// This is the data that will be stored in the wallet db. #[cfg(feature = "ledger")] #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] pub struct LedgerData {} +/// All the info we may want to know about a Ledger device. +#[cfg(feature = "ledger")] +#[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)] +pub struct LedgerFullInfo { + pub app_version: SemVer, +} + +#[cfg(feature = "ledger")] +impl From for LedgerData { + fn from(_value: LedgerFullInfo) -> Self { + Self {} + } +} + /// This is the data that will be stored in the wallet db. #[derive(Debug, Clone, Encode, Decode)] pub enum HardwareWalletData { @@ -61,6 +78,8 @@ pub enum HardwareWalletData { pub enum HardwareWalletFullInfo { #[cfg(feature = "trezor")] Trezor(TrezorFullInfo), + #[cfg(feature = "ledger")] + Ledger(LedgerFullInfo), } impl From for HardwareWalletData { @@ -68,6 +87,8 @@ impl From for HardwareWalletData { match info { #[cfg(feature = "trezor")] HardwareWalletFullInfo::Trezor(trezor_data) => Self::Trezor(trezor_data.into()), + #[cfg(feature = "ledger")] + HardwareWalletFullInfo::Ledger(ledger_data) => Self::Ledger(ledger_data.into()), } } } diff --git a/wallet/wallet-cli-commands/Cargo.toml b/wallet/wallet-cli-commands/Cargo.toml index 55134d5354..aad5989a70 100644 --- a/wallet/wallet-cli-commands/Cargo.toml +++ b/wallet/wallet-cli-commands/Cargo.toml @@ -44,7 +44,13 @@ serde = { workspace = true, features = ["derive"] } serde_json.workspace = true shlex.workspace = true thiserror.workspace = true -tokio = { workspace = true, default-features = false, features = ["io-util", "macros", "net", "rt", "sync"] } +tokio = { workspace = true, default-features = false, features = [ + "io-util", + "macros", + "net", + "rt", + "sync", +] } futures.workspace = true prettytable-rs = "0.10" @@ -65,4 +71,5 @@ rstest.workspace = true [features] trezor = ["wallet-types/trezor", "wallet-rpc-lib/trezor"] -default = ["trezor"] +ledger = ["wallet-types/ledger", "wallet-rpc-lib/ledger"] +default = ["trezor", "ledger"] diff --git a/wallet/wallet-cli-commands/src/command_handler/mod.rs b/wallet/wallet-cli-commands/src/command_handler/mod.rs index d7b333cca0..fda3a57710 100644 --- a/wallet/wallet-cli-commands/src/command_handler/mod.rs +++ b/wallet/wallet-cli-commands/src/command_handler/mod.rs @@ -335,6 +335,10 @@ where device_name, device_id, firmware_version ) } + WalletExtraInfo::LedgerWallet { app_version } => format!( + "This is a ledger wallet, running app version {}", + app_version + ), }; let account_names = info .account_names diff --git a/wallet/wallet-controller/Cargo.toml b/wallet/wallet-controller/Cargo.toml index 8daced808c..ca1b880809 100644 --- a/wallet/wallet-controller/Cargo.toml +++ b/wallet/wallet-controller/Cargo.toml @@ -28,7 +28,10 @@ wallet-storage = { path = "../storage" } wallet-types = { path = "../types" } async-trait.workspace = true -bip39 = { workspace = true, default-features = false, features = ["std", "zeroize"] } +bip39 = { workspace = true, default-features = false, features = [ + "std", + "zeroize", +] } ctor.workspace = true derive_more.workspace = true futures = { workspace = true, default-features = false } @@ -36,7 +39,13 @@ itertools.workspace = true serde.workspace = true strum.workspace = true thiserror.workspace = true -tokio = { workspace = true, default-features = false, features = ["io-util", "macros", "net", "rt", "sync"] } +tokio = { workspace = true, default-features = false, features = [ + "io-util", + "macros", + "net", + "rt", + "sync", +] } zeroize.workspace = true [dev-dependencies] @@ -52,4 +61,5 @@ rstest.workspace = true [features] trezor = ["wallet-types/trezor"] -default = ["trezor"] +ledger = ["wallet-types/ledger"] +default = ["trezor", "ledger"] diff --git a/wallet/wallet-controller/src/helpers/tests.rs b/wallet/wallet-controller/src/helpers/tests.rs index eaad6fe667..049e114641 100644 --- a/wallet/wallet-controller/src/helpers/tests.rs +++ b/wallet/wallet-controller/src/helpers/tests.rs @@ -93,7 +93,7 @@ mod tx_to_partially_signed_tx_general_test { let chain_config = Arc::new(create_regtest()); let block_timestamp = chain_config.genesis_block().timestamp(); - let mut wallet = create_wallet_with_mnemonic(Arc::clone(&chain_config), MNEMONIC); + let mut wallet = create_wallet_with_mnemonic(Arc::clone(&chain_config), MNEMONIC).await; // Transfer to a destination belonging to the wallet. let token0_transfer_utxo_dest = wallet_new_dest(&mut wallet); @@ -235,7 +235,7 @@ mod tx_to_partially_signed_tx_general_test { let known_create_pool_outpoint = UtxoOutPoint::new(last_block_id.into(), 1); let last_height = blocks.len() as u64 + 1; - scan_wallet(&mut wallet, BlockHeight::new(0), blocks); + scan_wallet(&mut wallet, BlockHeight::new(0), blocks).await; let htlc_spend_key = Destination::PublicKeyHash(PublicKeyHash::random_using(&mut rng)); let htlc_refund_key = Destination::PublicKeyHash(PublicKeyHash::random_using(&mut rng)); @@ -853,7 +853,7 @@ async fn tx_to_partially_signed_tx_htlc_input_with_known_utxo_test( let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet_with_mnemonic(Arc::clone(&chain_config), MNEMONIC); + let mut wallet = create_wallet_with_mnemonic(Arc::clone(&chain_config), MNEMONIC).await; let token_id = TokenId::random_using(&mut rng); @@ -903,7 +903,8 @@ async fn tx_to_partially_signed_tx_htlc_input_with_known_utxo_test( Amount::from_atoms(rng.gen()), Destination::PublicKeyHash(PublicKeyHash::random_using(&mut rng)), 0, - ); + ) + .await; let last_height = 1; let node_mock = { diff --git a/wallet/wallet-controller/src/lib.rs b/wallet/wallet-controller/src/lib.rs index e1fb90375e..2c3901f80c 100644 --- a/wallet/wallet-controller/src/lib.rs +++ b/wallet/wallet-controller/src/lib.rs @@ -120,7 +120,7 @@ use wallet_types::{ Currency, }; -#[cfg(feature = "trezor")] +#[cfg(any(feature = "trezor", feature = "ledger"))] use crate::types::WalletExtraInfo; // Note: the standard `Debug` macro is not smart enough and requires N to implement the `Debug` @@ -219,7 +219,7 @@ pub type ColdController = Controller Controller where N: NodeInterface + Clone + Send + Sync + 'static, - W: WalletEvents, + W: WalletEvents + Send + 'static, B: storage::BackendWithSendableTransactions + 'static, { pub async fn new( @@ -257,7 +257,7 @@ where } } - pub fn create_wallet( + pub async fn create_wallet( chain_config: Arc, file_path: impl AsRef, args: WalletTypeArgsComputed, @@ -298,6 +298,7 @@ where )?) }, ) + .await .map_err(ControllerError::WalletError) .map(|w| w.map_wallet(RuntimeWallet::Software)) } @@ -314,6 +315,7 @@ where .map_err(SignerError::TrezorError)?) }, ) + .await .map_err(ControllerError::WalletError) .map(|w| w.map_wallet(RuntimeWallet::Trezor)), }; @@ -322,7 +324,7 @@ where res } - pub fn recover_wallet( + pub async fn recover_wallet( chain_config: Arc, file_path: impl AsRef, args: WalletTypeArgsComputed, @@ -361,6 +363,7 @@ where )?) }, ) + .await .map_err(ControllerError::WalletError)?; Ok(wallet.map_wallet(RuntimeWallet::Software)) } @@ -377,6 +380,7 @@ where .map_err(SignerError::TrezorError)?) }, ) + .await .map_err(ControllerError::WalletError)?; Ok(wallet.map_wallet(RuntimeWallet::Trezor)) } @@ -435,7 +439,7 @@ where Ok(()) } - pub fn open_wallet( + pub async fn open_wallet( chain_config: Arc, file_path: impl AsRef, password: Option, @@ -466,6 +470,7 @@ where force_change_wallet_type, |db_tx| SoftwareSignerProvider::load_from_database(chain_config.clone(), db_tx), ) + .await .map_err(ControllerError::WalletError)?; Ok(wallet.map_wallet(RuntimeWallet::Software)) } @@ -486,6 +491,7 @@ where ) }, ) + .await .map_err(ControllerError::WalletError)?; Ok(wallet.map_wallet(RuntimeWallet::Trezor)) } @@ -580,6 +586,10 @@ where device_id: trezor_info.device_id, firmware_version: trezor_info.firmware_version.to_string(), }, + #[cfg(feature = "ledger")] + HardwareWalletFullInfo::Ledger(ledger_data) => WalletExtraInfo::LedgerWallet { + app_version: ledger_data.app_version.to_string(), + }, }, None => WalletExtraInfo::SoftwareWallet, }; @@ -747,11 +757,14 @@ where .map_err(|err| ControllerError::SearchForTimestampsFailed(err)) } - pub fn create_account( + pub async fn create_account( &mut self, name: Option, ) -> Result<(U31, Option), ControllerError> { - self.wallet.create_next_account(name).map_err(ControllerError::WalletError) + self.wallet + .create_next_account(name) + .await + .map_err(ControllerError::WalletError) } pub fn update_account_name( diff --git a/wallet/wallet-controller/src/runtime_wallet.rs b/wallet/wallet-controller/src/runtime_wallet.rs index 4b91db6617..81dbab57ed 100644 --- a/wallet/wallet-controller/src/runtime_wallet.rs +++ b/wallet/wallet-controller/src/runtime_wallet.rs @@ -197,14 +197,14 @@ where } } - pub fn create_next_account( + pub async fn create_next_account( &mut self, name: Option, ) -> Result<(U31, Option), WalletError> { match self { - RuntimeWallet::Software(w) => w.create_next_account(name), + RuntimeWallet::Software(w) => w.create_next_account(name).await, #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_next_account(name), + RuntimeWallet::Trezor(w) => w.create_next_account(name).await, } } diff --git a/wallet/wallet-controller/src/sync/mod.rs b/wallet/wallet-controller/src/sync/mod.rs index bfe7c5af4b..67dc8adefc 100644 --- a/wallet/wallet-controller/src/sync/mod.rs +++ b/wallet/wallet-controller/src/sync/mod.rs @@ -15,6 +15,8 @@ use std::{cmp::Reverse, collections::BTreeMap, iter}; +use async_trait::async_trait; + use common::{ chain::{block::timestamp::BlockTimestamp, Block, ChainConfig, GenBlock}, primitives::{BlockHeight, Id}, @@ -32,6 +34,7 @@ use crate::ControllerError; const MAX_FETCH_BLOCK_COUNT: usize = 100; +#[async_trait] pub trait SyncingWallet { fn syncing_state(&self) -> WalletSyncingState; @@ -40,19 +43,20 @@ pub trait SyncingWallet { account: U31, common_block_height: BlockHeight, blocks: Vec, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send), ) -> WalletResult<()>; - fn scan_blocks_for_unused_account( + async fn scan_blocks_for_unused_account( &mut self, common_block_height: BlockHeight, blocks: Vec, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send), ) -> WalletResult<()>; fn update_median_time(&mut self, median_time: BlockTimestamp) -> WalletResult<()>; } +#[async_trait] impl SyncingWallet for Wallet where B: storage::BackendWithSendableTransactions + 'static, @@ -67,18 +71,19 @@ where account: U31, common_block_height: BlockHeight, blocks: Vec, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send), ) -> WalletResult<()> { self.scan_new_blocks(account, common_block_height, blocks, wallet_events) } - fn scan_blocks_for_unused_account( + async fn scan_blocks_for_unused_account( &mut self, common_block_height: BlockHeight, blocks: Vec, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send), ) -> WalletResult<()> { self.scan_new_blocks_unused_account(common_block_height, blocks, wallet_events) + .await } fn update_median_time(&mut self, median_time: BlockTimestamp) -> WalletResult<()> { @@ -122,7 +127,7 @@ pub async fn sync_once( chain_config: &ChainConfig, rpc_client: &T, wallet: &mut impl SyncingWallet, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send + 'static), ) -> Result> { let mut print_flag = SetFlag::new(); let mut _log_on_exit = None; @@ -224,7 +229,7 @@ async fn fetch_and_sync_to_next_group( mut next_group_accounts: Vec, rpc_client: &T, wallet: &mut impl SyncingWallet, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send + 'static), ) -> Result<(NextBlockInfo, Vec), ControllerError> { let block_to_fetch = (next_group_block_info.common_block_height - current.0.common_block_height) .expect("already sorted") @@ -241,7 +246,7 @@ async fn fetch_and_sync( block_to_fetch: usize, rpc_client: &T, wallet: &mut impl SyncingWallet, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send + 'static), ) -> Result<(), ControllerError> { let FetchedBlocks { blocks, @@ -260,20 +265,21 @@ async fn fetch_and_sync( common_block_height, blocks.clone(), wallet_events, - )?; + ) + .await?; } Ok(()) } -fn scan_new_blocks( +async fn scan_new_blocks( acc: &AccountType, new_height: u64, block_id: Id, wallet: &mut impl SyncingWallet, common_block_height: BlockHeight, blocks: Vec, - wallet_events: &impl WalletEvents, + wallet_events: &(impl WalletEvents + Send + 'static), ) -> Result<(), ControllerError> { match acc { AccountType::Account(account) => { @@ -296,6 +302,7 @@ fn scan_new_blocks( wallet .scan_blocks_for_unused_account(common_block_height, blocks, wallet_events) + .await .map_err(ControllerError::WalletError)?; } } diff --git a/wallet/wallet-controller/src/sync/tests/mod.rs b/wallet/wallet-controller/src/sync/tests/mod.rs index 2119443cd5..a70e2c6aaa 100644 --- a/wallet/wallet-controller/src/sync/tests/mod.rs +++ b/wallet/wallet-controller/src/sync/tests/mod.rs @@ -19,6 +19,10 @@ use std::{ time::Duration, }; +use futures::executor::block_on; +use rstest::rstest; +use tokio::sync::mpsc; + use blockprod::TimestampSearchData; use chainstate::ChainInfo; use chainstate_test_framework::TestFramework; @@ -31,7 +35,6 @@ use common::{ }; use consensus::GenerateBlockInputData; use crypto::ephemeral_e2e::EndToEndPublicKey; -use futures::executor::block_on; use logging::log; use mempool::{tx_accumulator::PackingStrategy, FeeRate}; use mempool_types::tx_options::TxOptionsOverrides; @@ -41,9 +44,7 @@ use node_comm::{ }; use p2p_types::{bannable_address::BannableAddress, socket_address::SocketAddress}; use randomness::{seq::IteratorRandom, CryptoRng, Rng}; -use rstest::rstest; use test_utils::random::{make_seedable_rng, Seed}; -use tokio::sync::mpsc; use utils_networking::IpOrSocketAddress; use wallet::wallet_events::WalletEventsNoOp; use wallet_types::{account_info::DEFAULT_ACCOUNT_INDEX, wallet_type::WalletControllerMode}; @@ -90,6 +91,7 @@ impl MockWallet { } } +#[async_trait::async_trait] impl SyncingWallet for MockWallet { fn syncing_state(&self) -> WalletSyncingState { WalletSyncingState { @@ -109,7 +111,7 @@ impl SyncingWallet for MockWallet { account: U31, common_block_height: BlockHeight, blocks: Vec, - _wallet_events: &impl WalletEvents, + _wallet_events: &(impl WalletEvents + Send), ) -> WalletResult<()> { assert!(account == DEFAULT_ACCOUNT_INDEX); assert!(!blocks.is_empty()); @@ -131,7 +133,7 @@ impl SyncingWallet for MockWallet { )) .await }) - .unwrap(); + .unwrap() } log::debug!( @@ -143,11 +145,11 @@ impl SyncingWallet for MockWallet { Ok(()) } - fn scan_blocks_for_unused_account( + async fn scan_blocks_for_unused_account( &mut self, common_block_height: BlockHeight, blocks: Vec, - _wallet_events: &impl WalletEvents, + _wallet_events: &(impl WalletEvents + Send), ) -> WalletResult<()> { assert!(!blocks.is_empty()); assert!( @@ -163,12 +165,10 @@ impl SyncingWallet for MockWallet { self.get_unused_acc_best_block_id() ); self.next_unused_blocks.push(block.header().block_id()); - block_on(async { - self.new_tip_tx - .send((AccountType::UnusedAccount, block.header().block_id())) - .await - }) - .unwrap(); + self.new_tip_tx + .send((AccountType::UnusedAccount, block.header().block_id())) + .await + .unwrap() } log::debug!( diff --git a/wallet/wallet-controller/src/tests/compose_transaction_tests.rs b/wallet/wallet-controller/src/tests/compose_transaction_tests.rs index 3dfe5fa7de..5f0fa536c0 100644 --- a/wallet/wallet-controller/src/tests/compose_transaction_tests.rs +++ b/wallet/wallet-controller/src/tests/compose_transaction_tests.rs @@ -67,7 +67,7 @@ async fn general_test(#[case] seed: Seed, #[case] use_htlc_secret: bool) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); - let mut wallet = create_wallet_with_mnemonic(Arc::clone(&chain_config), MNEMONIC); + let mut wallet = create_wallet_with_mnemonic(Arc::clone(&chain_config), MNEMONIC).await; let token1_id = TokenId::random_using(&mut rng); let token2_id = TokenId::random_using(&mut rng); @@ -98,7 +98,8 @@ async fn general_test(#[case] seed: Seed, #[case] use_htlc_secret: bool) { block_reward_amount, Destination::PublicKeyHash(PublicKeyHash::random_using(&mut rng)), 0, - ); + ) + .await; let last_height = 1; let token1_outpoint = UtxoOutPoint::new(tx_with_token1_id.into(), 0); diff --git a/wallet/wallet-controller/src/tests/test_utils.rs b/wallet/wallet-controller/src/tests/test_utils.rs index 9c1e4162a5..459701d833 100644 --- a/wallet/wallet-controller/src/tests/test_utils.rs +++ b/wallet/wallet-controller/src/tests/test_utils.rs @@ -162,7 +162,7 @@ pub fn tx_with_outputs(outputs: Vec) -> SignedTransaction { SignedTransaction::new(Transaction::new(0, vec![], outputs).unwrap(), Vec::new()).unwrap() } -pub fn create_block_scan_wallet( +pub async fn create_block_scan_wallet( chain_config: &ChainConfig, wallet: &mut Wallet, transactions: Vec, @@ -186,7 +186,7 @@ where ) .unwrap(); - scan_wallet(wallet, BlockHeight::new(block_height), vec![block.clone()]); + scan_wallet(wallet, BlockHeight::new(block_height), vec![block.clone()]).await; block } diff --git a/wallet/wallet-controller/src/types/mod.rs b/wallet/wallet-controller/src/types/mod.rs index 53e310f84c..347b6f9bb8 100644 --- a/wallet/wallet-controller/src/types/mod.rs +++ b/wallet/wallet-controller/src/types/mod.rs @@ -68,6 +68,10 @@ pub enum WalletExtraInfo { // Note: semver::Version is not serializable, so we can't use it here. firmware_version: String, }, + #[cfg(feature = "ledger")] + LedgerWallet { + app_version: String, + }, } impl rpc_description::HasValueHint for WalletExtraInfo { diff --git a/wallet/wallet-rpc-client/Cargo.toml b/wallet/wallet-rpc-client/Cargo.toml index 764ee2f1d2..f019a9a22f 100644 --- a/wallet/wallet-rpc-client/Cargo.toml +++ b/wallet/wallet-rpc-client/Cargo.toml @@ -36,8 +36,25 @@ tower.workspace = true [dev-dependencies] chainstate-storage = { path = "../../chainstate/storage" } -tokio = { workspace = true, default-features = false, features = ["io-util", "macros", "net", "rt", "sync"] } +tokio = { workspace = true, default-features = false, features = [ + "io-util", + "macros", + "net", + "rt", + "sync", +] } [features] -trezor = ["wallet/trezor", "wallet-types/trezor", "wallet-rpc-lib/trezor", "wallet-controller/trezor"] -default = ["trezor"] +trezor = [ + "wallet/trezor", + "wallet-types/trezor", + "wallet-rpc-lib/trezor", + "wallet-controller/trezor", +] +ledger = [ + "wallet/ledger", + "wallet-types/ledger", + "wallet-rpc-lib/ledger", + "wallet-controller/ledger", +] +default = ["trezor", "ledger"] diff --git a/wallet/wallet-rpc-lib/Cargo.toml b/wallet/wallet-rpc-lib/Cargo.toml index 5419863cff..c01ae081d0 100644 --- a/wallet/wallet-rpc-lib/Cargo.toml +++ b/wallet/wallet-rpc-lib/Cargo.toml @@ -43,7 +43,7 @@ tokio.workspace = true consensus = { path = "../../consensus" } mempool = { path = "../../mempool" } -rpc = { path = "../../rpc", features = [ "test-support" ] } +rpc = { path = "../../rpc", features = ["test-support"] } subsystem = { path = "../../subsystem" } test-utils = { path = "../../test-utils" } wallet-test-node = { path = "../wallet-test-node" } @@ -53,4 +53,5 @@ rstest.workspace = true [features] trezor = ["wallet-types/trezor", "wallet/trezor", "wallet-controller/trezor"] -default = ["trezor"] +ledger = ["wallet-types/ledger", "wallet/ledger", "wallet-controller/ledger"] +default = ["trezor", "ledger"] diff --git a/wallet/wallet-rpc-lib/src/rpc/mod.rs b/wallet/wallet-rpc-lib/src/rpc/mod.rs index bbe69eb854..7b46022b75 100644 --- a/wallet/wallet-rpc-lib/src/rpc/mod.rs +++ b/wallet/wallet-rpc-lib/src/rpc/mod.rs @@ -277,7 +277,10 @@ where } pub async fn create_account(&self, name: Option) -> WRpcResult { - let (num, name) = self.wallet.call(|w| w.create_account(name)).await??; + let (num, name) = self + .wallet + .call_async(move |w| Box::pin(async move { w.create_account(name).await })) + .await??; Ok(NewAccountInfo::new(num, name)) } diff --git a/wallet/wallet-rpc-lib/src/service/mod.rs b/wallet/wallet-rpc-lib/src/service/mod.rs index 3bbafa4b5b..a6ecfa729b 100644 --- a/wallet/wallet-rpc-lib/src/service/mod.rs +++ b/wallet/wallet-rpc-lib/src/service/mod.rs @@ -77,7 +77,8 @@ where force_change_wallet_type, *open_as_wallet_type, None, - )? + ) + .await? .wallet()? }; diff --git a/wallet/wallet-rpc-lib/src/service/worker.rs b/wallet/wallet-rpc-lib/src/service/worker.rs index ba7f3c09cf..bc83f9af3f 100644 --- a/wallet/wallet-rpc-lib/src/service/worker.rs +++ b/wallet/wallet-rpc-lib/src/service/worker.rs @@ -172,7 +172,8 @@ where force_migrate_wallet_type, open_as_wallet_type, device_id, - )?; + ) + .await?; let wallet = match wallet { wallet::wallet::WalletCreation::Wallet(w) => w, @@ -227,6 +228,7 @@ where wallet_type, options.overwrite_wallet_file, ) + .await } else { WalletController::recover_wallet( self.chain_config.clone(), @@ -234,6 +236,7 @@ where computed_args, wallet_type, ) + .await } .map_err(RpcError::Controller)?; diff --git a/wallet/wallet-rpc-lib/tests/utils.rs b/wallet/wallet-rpc-lib/tests/utils.rs index d87b670239..ea55917c93 100644 --- a/wallet/wallet-rpc-lib/tests/utils.rs +++ b/wallet/wallet-rpc-lib/tests/utils.rs @@ -80,6 +80,7 @@ impl TestFramework { )?) }, ) + .await .unwrap(); wallet_path