diff --git a/Cargo.lock b/Cargo.lock index d9f06a5a1..10a10d098 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8581,11 +8581,13 @@ dependencies = [ name = "wallet" version = "1.0.0" dependencies = [ + "async-trait", "bip39", "chainstate", "common", "consensus", "crypto", + "futures", "hex", "itertools 0.13.0", "logging", @@ -8602,6 +8604,7 @@ dependencies = [ "tempfile", "test-utils", "thiserror", + "tokio", "trezor-client", "tx-verifier", "utils", diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index 35b342c30..6b5436a22 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -28,7 +28,9 @@ wallet-storage = { path = "./storage" } wallet-types = { path = "./types" } trezor-client = { git = "https://github.com/mintlayer/mintlayer-trezor-firmware", branch = "feature/mintlayer-pk", features = ["bitcoin", "mintlayer"], optional = true } +async-trait.workspace = true bip39 = { workspace = true, default-features = false, features = ["std", "zeroize"] } +futures = { workspace = true, default-features = false } hex.workspace = true itertools.workspace = true parity-scale-codec.workspace = true @@ -38,6 +40,7 @@ zeroize.workspace = true [dev-dependencies] test-utils = { path = "../test-utils" } +tokio = { workspace = true, default-features = false, features = ["io-util", "macros", "net", "rt", "sync"] } rstest.workspace = true tempfile.workspace = true diff --git a/wallet/src/account/mod.rs b/wallet/src/account/mod.rs index 31459cd1d..8795a8fed 100644 --- a/wallet/src/account/mod.rs +++ b/wallet/src/account/mod.rs @@ -120,7 +120,7 @@ pub struct Account { account_info: AccountInfo, } -impl Account { +impl Account { /// Create a new account by providing a key chain pub fn new( chain_config: Arc, @@ -654,7 +654,7 @@ impl Account { pub fn process_send_request_and_sign( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, request: SendRequest, inputs: SelectedInputs, change_addresses: BTreeMap>, @@ -676,7 +676,7 @@ impl Account { fn decommission_stake_pool_impl( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, pool_id: PoolId, pool_balance: Amount, output_address: Option, @@ -739,7 +739,7 @@ impl Account { pub fn decommission_stake_pool( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, pool_id: PoolId, pool_balance: Amount, output_address: Option, @@ -756,7 +756,7 @@ impl Account { pub fn decommission_stake_pool_request( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, pool_id: PoolId, pool_balance: Amount, output_address: Option, @@ -900,7 +900,7 @@ impl Account { pub fn create_htlc_tx( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, output_value: OutputValue, htlc: HashedTimelockContract, median_time: BlockTimestamp, @@ -923,7 +923,7 @@ impl Account { pub fn create_order_tx( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, ask_value: OutputValue, give_value: OutputValue, conclude_address: Address, @@ -949,7 +949,7 @@ impl Account { pub fn create_conclude_order_tx( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, order_id: OrderId, order_info: RpcOrderInfo, output_address: Option, @@ -1002,7 +1002,7 @@ impl Account { #[allow(clippy::too_many_arguments)] pub fn create_fill_order_tx( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, order_id: OrderId, order_info: RpcOrderInfo, fill_amount_in_ask_currency: Amount, @@ -1058,7 +1058,7 @@ impl Account { pub fn create_issue_nft_tx( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, nft_issue_arguments: IssueNftArguments, median_time: BlockTimestamp, fee_rate: CurrentFeeRate, @@ -1119,7 +1119,7 @@ impl Account { pub fn mint_tokens( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, address: Address, amount: Amount, @@ -1147,7 +1147,7 @@ impl Account { pub fn unmint_tokens( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, amount: Amount, median_time: BlockTimestamp, @@ -1174,7 +1174,7 @@ impl Account { pub fn lock_token_supply( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, median_time: BlockTimestamp, fee_rate: CurrentFeeRate, @@ -1198,7 +1198,7 @@ impl Account { pub fn freeze_token( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, is_token_unfreezable: IsTokenUnfreezable, median_time: BlockTimestamp, @@ -1225,7 +1225,7 @@ impl Account { pub fn unfreeze_token( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, median_time: BlockTimestamp, fee_rate: CurrentFeeRate, @@ -1249,7 +1249,7 @@ impl Account { pub fn change_token_authority( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, address: Address, median_time: BlockTimestamp, @@ -1276,7 +1276,7 @@ impl Account { pub fn change_token_metadata_uri( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, token_info: &UnconfirmedTokenInfo, metadata_uri: Vec, median_time: BlockTimestamp, @@ -1304,7 +1304,7 @@ impl Account { authority: Destination, tx_input: TxInput, outputs: Vec, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, median_time: BlockTimestamp, fee_rate: CurrentFeeRate, ) -> Result { @@ -2128,7 +2128,7 @@ struct PreselectedInputAmounts { pub burn: Amount, } -impl Account { +impl Account { fn get_vrf_public_key( &mut self, db_tx: &mut impl WalletStorageWriteLocked, @@ -2199,7 +2199,7 @@ impl Account { pub fn create_stake_pool_tx( &mut self, - db_tx: &mut impl WalletStorageWriteUnlocked, + db_tx: &mut impl WalletStorageWriteLocked, stake_pool_arguments: StakePoolDataArguments, median_time: BlockTimestamp, fee_rate: CurrentFeeRate, diff --git a/wallet/src/signer/mod.rs b/wallet/src/signer/mod.rs index d8ad31244..79c7d83c7 100644 --- a/wallet/src/signer/mod.rs +++ b/wallet/src/signer/mod.rs @@ -15,6 +15,7 @@ use std::sync::Arc; +use async_trait::async_trait; use common::{ address::AddressError, chain::{ @@ -99,13 +100,14 @@ type SignerResult = Result; /// Signer trait responsible for signing transactions or challenges using a software or hardware /// wallet +#[async_trait] pub trait Signer { /// Sign a partially signed transaction and return the before and after signature statuses. - fn sign_tx( + async fn sign_tx( &mut self, tx: PartiallySignedTransaction, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult<( PartiallySignedTransaction, Vec, @@ -113,30 +115,30 @@ pub trait Signer { )>; /// Sign an arbitrary message for a destination known to this key chain. - fn sign_challenge( + async fn sign_challenge( &mut self, message: &[u8], destination: &Destination, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult; /// Sign a transaction intent. The number of `input_destinations` must be the same as /// the number of inputs in the transaction; all of the destinations must be known /// to this key chain. - fn sign_transaction_intent( + async fn sign_transaction_intent( &mut self, transaction: &Transaction, input_destinations: &[Destination], intent: &str, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult; } pub trait SignerProvider { type S: Signer; - type K: AccountKeyChains; + type K: AccountKeyChains + Sync; fn provide(&mut self, chain_config: Arc, account_index: U31) -> Self::S; diff --git a/wallet/src/signer/software_signer/mod.rs b/wallet/src/signer/software_signer/mod.rs index e3d45e06e..668841e13 100644 --- a/wallet/src/signer/software_signer/mod.rs +++ b/wallet/src/signer/software_signer/mod.rs @@ -15,6 +15,7 @@ use std::sync::Arc; +use async_trait::async_trait; use common::chain::{ htlc::HtlcSecret, signature::{ @@ -253,12 +254,13 @@ impl SoftwareSigner { } } +#[async_trait] impl Signer for SoftwareSigner { - fn sign_tx( + async fn sign_tx( &mut self, ptx: PartiallySignedTransaction, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult<( PartiallySignedTransaction, Vec, @@ -359,12 +361,12 @@ impl Signer for SoftwareSigner { Ok((ptx.with_witnesses(witnesses), prev_statuses, new_statuses)) } - fn sign_challenge( + async fn sign_challenge( &mut self, message: &[u8], destination: &Destination, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult { let private_key = self .get_private_key_for_destination(destination, key_chain, db_tx)? @@ -380,13 +382,13 @@ impl Signer for SoftwareSigner { Ok(sig) } - fn sign_transaction_intent( + async fn sign_transaction_intent( &mut self, transaction: &Transaction, input_destinations: &[Destination], intent: &str, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult { SignedTransactionIntent::produce_from_transaction( transaction, diff --git a/wallet/src/signer/software_signer/tests.rs b/wallet/src/signer/software_signer/tests.rs index 96838e610..e31b76568 100644 --- a/wallet/src/signer/software_signer/tests.rs +++ b/wallet/src/signer/software_signer/tests.rs @@ -51,7 +51,10 @@ const MNEMONIC: &str = #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_message(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_message(#[case] seed: Seed) { + use wallet_storage::TransactionRwUnlocked; + let mut rng = make_seedable_rng(seed); let config = Arc::new(create_regtest()); @@ -75,8 +78,11 @@ fn sign_message(#[case] seed: Seed) { let destination = account.get_new_address(&mut db_tx, ReceiveFunds).unwrap().1.into_object(); let mut signer = SoftwareSigner::new(config.clone(), DEFAULT_ACCOUNT_INDEX); let message = vec![rng.gen::(), rng.gen::(), rng.gen::()]; + db_tx.commit().unwrap(); + let db_tx = db.local_rw_unlocked().read_only_store(); let res = signer .sign_challenge(&message, &destination, account.key_chain(), &db_tx) + .await .unwrap(); let message_challenge = produce_message_challenge(&message); @@ -86,8 +92,10 @@ fn sign_message(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_transaction_intent(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_transaction_intent(#[case] seed: Seed) { use common::primitives::Idable; + use wallet_storage::TransactionRwUnlocked; let mut rng = make_seedable_rng(seed); @@ -134,8 +142,10 @@ fn sign_transaction_intent(#[case] seed: Seed) { )], ) .unwrap(); + db_tx.commit().unwrap(); let intent: String = [rng.gen::(), rng.gen::(), rng.gen::()].iter().collect(); + let db_tx = db.local_rw_unlocked().read_only_store(); let res = signer .sign_transaction_intent( &tx, @@ -144,6 +154,7 @@ fn sign_transaction_intent(#[case] seed: Seed) { account.key_chain(), &db_tx, ) + .await .unwrap(); let expected_signed_message = @@ -154,7 +165,8 @@ fn sign_transaction_intent(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_transaction(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_transaction(#[case] seed: Seed) { use std::num::NonZeroU8; use common::{ @@ -173,6 +185,7 @@ fn sign_transaction(#[case] seed: Seed) { }; use crypto::vrf::VRFPrivateKey; use serialization::extras::non_empty_vec::DataOrNoVec; + use wallet_storage::TransactionRwUnlocked; let mut rng = make_seedable_rng(seed); @@ -439,8 +452,10 @@ fn sign_transaction(#[case] seed: Seed) { let additional_info = BTreeMap::new(); let ptx = req.into_partially_signed_tx(&additional_info).unwrap(); + db_tx.commit().unwrap(); + let db_tx = db.local_rw_unlocked().read_only_store(); let mut signer = SoftwareSigner::new(chain_config.clone(), DEFAULT_ACCOUNT_INDEX); - let (ptx, _, _) = signer.sign_tx(ptx, account.key_chain(), &db_tx).unwrap(); + let (ptx, _, _) = signer.sign_tx(ptx, account.key_chain(), &db_tx).await.unwrap(); eprintln!("num inputs in tx: {} {:?}", inputs.len(), ptx.witnesses()); assert!(ptx.all_signatures_available()); diff --git a/wallet/src/signer/trezor_signer/mod.rs b/wallet/src/signer/trezor_signer/mod.rs index bb2a21e41..21fc0ab0c 100644 --- a/wallet/src/signer/trezor_signer/mod.rs +++ b/wallet/src/signer/trezor_signer/mod.rs @@ -18,6 +18,7 @@ use std::{ sync::{Arc, Mutex}, }; +use async_trait::async_trait; use common::{ address::Address, chain::{ @@ -253,12 +254,13 @@ impl TrezorSigner { } } +#[async_trait] impl Signer for TrezorSigner { - fn sign_tx( + async fn sign_tx( &mut self, ptx: PartiallySignedTransaction, - key_chain: &impl AccountKeyChains, - _db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + _db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult<( PartiallySignedTransaction, Vec, @@ -416,12 +418,12 @@ impl Signer for TrezorSigner { Ok((ptx.with_witnesses(witnesses), prev_statuses, new_statuses)) } - fn sign_challenge( + async fn sign_challenge( &mut self, message: &[u8], destination: &Destination, - key_chain: &impl AccountKeyChains, - _db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + _db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult { let data = match key_chain.find_public_key(destination) { Some(FoundPubKey::Hierarchy(xpub)) => { @@ -476,20 +478,21 @@ impl Signer for TrezorSigner { Ok(sig) } - fn sign_transaction_intent( + async fn sign_transaction_intent( &mut self, transaction: &Transaction, input_destinations: &[Destination], intent: &str, - key_chain: &impl AccountKeyChains, - db_tx: &impl WalletStorageReadUnlocked, + key_chain: &(impl AccountKeyChains + Sync), + db_tx: &(impl WalletStorageReadUnlocked + Sync), ) -> SignerResult { let tx_id = transaction.get_id(); let message_to_sign = SignedTransactionIntent::get_message_to_sign(intent, &tx_id); let mut signatures = Vec::with_capacity(input_destinations.len()); for dest in input_destinations { - let sig = self.sign_challenge(message_to_sign.as_bytes(), dest, key_chain, db_tx)?; + let sig = + self.sign_challenge(message_to_sign.as_bytes(), dest, key_chain, db_tx).await?; signatures.push(sig.into_raw()); } diff --git a/wallet/src/signer/trezor_signer/tests.rs b/wallet/src/signer/trezor_signer/tests.rs index ad3c9fad3..aafe51c5e 100644 --- a/wallet/src/signer/trezor_signer/tests.rs +++ b/wallet/src/signer/trezor_signer/tests.rs @@ -48,7 +48,10 @@ const MNEMONIC: &str = #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_message(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_message(#[case] seed: Seed) { + use wallet_storage::TransactionRwUnlocked; + let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -76,8 +79,11 @@ fn sign_message(#[case] seed: Seed) { let mut signer = TrezorSigner::new(chain_config.clone(), Arc::new(Mutex::new(client))); let message = vec![rng.gen::(), rng.gen::(), rng.gen::()]; + db_tx.commit().unwrap(); + let db_tx = db.local_rw_unlocked().read_only_store(); let res = signer .sign_challenge(&message, &destination, account.key_chain(), &db_tx) + .await .unwrap(); let message_challenge = produce_message_challenge(&message); @@ -87,8 +93,10 @@ fn sign_message(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_transaction_intent(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_transaction_intent(#[case] seed: Seed) { use common::primitives::Idable; + use wallet_storage::TransactionRwUnlocked; let mut rng = make_seedable_rng(seed); @@ -140,6 +148,9 @@ fn sign_transaction_intent(#[case] seed: Seed) { ) .unwrap(); + db_tx.commit().unwrap(); + let db_tx = db.local_rw_unlocked().read_only_store(); + let intent: String = [rng.gen::(), rng.gen::(), rng.gen::()].iter().collect(); let res = signer .sign_transaction_intent( @@ -149,6 +160,7 @@ fn sign_transaction_intent(#[case] seed: Seed) { account.key_chain(), &db_tx, ) + .await .unwrap(); let expected_signed_message = @@ -159,7 +171,8 @@ fn sign_transaction_intent(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_transaction(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_transaction(#[case] seed: Seed) { use std::num::NonZeroU8; use common::{ @@ -172,6 +185,7 @@ fn sign_transaction(#[case] seed: Seed) { }; use crypto::vrf::VRFPrivateKey; use serialization::extras::non_empty_vec::DataOrNoVec; + use wallet_storage::TransactionRwUnlocked; let mut rng = make_seedable_rng(seed); @@ -442,8 +456,10 @@ fn sign_transaction(#[case] seed: Seed) { assert!(!devices.is_empty()); let client = devices.pop().unwrap().connect().unwrap(); + db_tx.commit().unwrap(); + let db_tx = db.local_rw_unlocked().read_only_store(); let mut signer = TrezorSigner::new(chain_config.clone(), Arc::new(Mutex::new(client))); - let (ptx, _, _) = signer.sign_tx(ptx, account.key_chain(), &db_tx).unwrap(); + let (ptx, _, _) = signer.sign_tx(ptx, account.key_chain(), &db_tx).await.unwrap(); eprintln!("num inputs in tx: {} {:?}", inputs.len(), ptx.witnesses()); assert!(ptx.all_signatures_available()); diff --git a/wallet/src/wallet/mod.rs b/wallet/src/wallet/mod.rs index b79a25262..01f89f2ce 100644 --- a/wallet/src/wallet/mod.rs +++ b/wallet/src/wallet/mod.rs @@ -14,6 +14,7 @@ // limitations under the License. use std::collections::{BTreeMap, BTreeSet}; +use std::future::Future; use std::path::{Path, PathBuf}; use std::sync::Arc; @@ -68,10 +69,10 @@ use tx_verifier::{check_transaction, CheckTransactionError}; use utils::ensure; pub use wallet_storage::Error; use wallet_storage::{ - DefaultBackend, Store, StoreTxRo, StoreTxRw, StoreTxRwUnlocked, TransactionRoLocked, - TransactionRwLocked, TransactionRwUnlocked, Transactional, WalletStorageReadLocked, - WalletStorageReadUnlocked, WalletStorageReadWriteLocked, WalletStorageReadWriteUnlocked, - WalletStorageWriteLocked, WalletStorageWriteUnlocked, + DefaultBackend, Store, StoreLocalReadWriteUnlocked, StoreTxRo, StoreTxRw, StoreTxRwUnlocked, + TransactionRoLocked, TransactionRwLocked, TransactionRwUnlocked, Transactional, + WalletStorageReadLocked, WalletStorageReadUnlocked, WalletStorageReadWriteLocked, + WalletStorageReadWriteUnlocked, WalletStorageWriteLocked, WalletStorageWriteUnlocked, }; use wallet_types::account_info::{StandaloneAddressDetails, StandaloneAddresses}; use wallet_types::chain_info::ChainInfo; @@ -1040,38 +1041,109 @@ where } } - fn for_account_rw_unlocked_and_check_tx_generic( + async fn async_for_account_rw_unlocked( + &mut self, + account_index: U31, + f: impl FnOnce( + Account, + &mut StoreLocalReadWriteUnlocked, + Arc, +

::S, + ) -> Fut, + ) -> WalletResult + where + Fut: Future, WalletResult)>, + { + let mut db_tx = self.db.local_rw_unlocked(); + + Self::use_account_mut(&mut self.accounts, account_index, |account| async { + let signer = self.signer_provider.provide(self.chain_config.clone(), account_index); + let (mut account, result) = + f(account, &mut db_tx, self.chain_config.clone(), signer).await; + match result { + Ok(value) => { + match self + .db + .transaction_rw(None) + .and_then(|mut tx| db_tx.perform_operations(&mut tx).map(|_| tx)) + { + Err(err) => return (account, Err(err.into())), + Ok(tx) => { + // Abort the process if the DB transaction fails. See `for_account_rw` for more information. + tx.commit().expect("RW transaction commit failed unexpectedly"); + } + } + (account, Ok(value)) + } + Err(err) => { + // db_tx.abort(); + // In case of an error reload the keys in case the operation issued new ones and + // are saved in the cache but not in the DB + if let Err(err) = self + .db + .transaction_ro() + .map_err(Into::into) + .and_then(|db_tx| account.reload_keys(&db_tx)) + { + return (account, Err(err)); + }; + + (account, Err(err)) + } + } + }) + .await? + } + + async fn async_for_account_rw_unlocked_and_check_tx_custom_error( &mut self, account_index: U31, additional_utxo_infos: &BTreeMap, f: impl FnOnce( &mut Account, - &mut StoreTxRwUnlocked, + &mut StoreLocalReadWriteUnlocked, ) -> WalletResult<(SendRequest, AddlData)>, error_mapper: impl FnOnce(WalletError) -> WalletError, ) -> WalletResult<(SignedTransaction, AddlData)> { let (_, block_height) = self.get_best_block_for_account(account_index)?; - self.for_account_rw_unlocked( + self.async_for_account_rw_unlocked( account_index, - |account, db_tx, chain_config, signer_provider| { - let (request, additional_data) = f(account, db_tx)?; - - let ptx = request.into_partially_signed_tx(additional_utxo_infos)?; - - let mut signer = - signer_provider.provide(Arc::new(chain_config.clone()), account_index); - let ptx = signer.sign_tx(ptx, account.key_chain(), db_tx).map(|(ptx, _, _)| ptx)?; - - let inputs_utxo_refs: Vec<_> = - ptx.input_utxos().iter().map(|u| u.as_ref().map(|x| &x.utxo)).collect(); - let is_fully_signed = - ptx.destinations().iter().enumerate().zip(ptx.witnesses()).all( - |((i, destination), witness)| match (witness, destination) { + |mut account, db_tx, chain_config, mut signer| { + let request = f(&mut account, db_tx); + let store = db_tx.read_only_store(); + async move { + let (request, additional_data) = match request { + Ok(x) => x, + Err(err) => return (account, Err(err)), + }; + + let ptx = match request.into_partially_signed_tx(additional_utxo_infos) { + Ok(x) => x, + Err(err) => return (account, Err(err)), + }; + + let ptx = match signer + .sign_tx(ptx, account.key_chain(), &store) + .await + .map(|(ptx, _, _)| ptx) + { + Ok(x) => x, + Err(err) => return (account, Err(err.into())), + }; + + let inputs_utxo_refs: Vec<_> = + ptx.input_utxos().iter().map(|u| u.as_ref().map(|x| &x.utxo)).collect(); + let is_fully_signed = ptx + .destinations() + .iter() + .enumerate() + .zip(ptx.witnesses()) + .all(|((i, destination), witness)| match (witness, destination) { (None | Some(_), None) | (None, Some(_)) => false, (Some(_), Some(destination)) => { tx_verifier::input_check::signature_only_check::verify_tx_signature( - chain_config, + &chain_config, destination, &ptx, &inputs_utxo_refs, @@ -1079,39 +1151,54 @@ where ) .is_ok() } - }, - ); - - if !is_fully_signed { - return Err(error_mapper(WalletError::FailedToConvertPartiallySignedTx( - ptx, - ))); + }); + + if !is_fully_signed { + return ( + account, + Err(error_mapper(WalletError::FailedToConvertPartiallySignedTx( + ptx, + ))), + ); + } + + let tx = match ptx.into_signed_tx().map_err(|e| { + error_mapper(WalletError::PartiallySignedTransactionCreation(e)) + }) { + Ok(x) => x, + Err(err) => return (account, Err(err)), + }; + + if let Err(err) = + check_transaction(&chain_config, block_height.next_height(), &tx) + { + return (account, Err(err.into())); + } + + (account, Ok((tx, additional_data))) } - - let tx = ptx.into_signed_tx().map_err(|e| { - error_mapper(WalletError::PartiallySignedTransactionCreation(e)) - })?; - - check_transaction(chain_config, block_height.next_height(), &tx)?; - Ok((tx, additional_data)) }, ) + .await } - fn for_account_rw_unlocked_and_check_tx( + async fn async_for_account_rw_unlocked_and_check_tx( &mut self, account_index: U31, additional_utxo_infos: &BTreeMap, - f: impl FnOnce(&mut Account, &mut StoreTxRwUnlocked) -> WalletResult, + f: impl FnOnce( + &mut Account, + &mut StoreLocalReadWriteUnlocked, + ) -> WalletResult, ) -> WalletResult { - Ok(self - .for_account_rw_unlocked_and_check_tx_generic( - account_index, - additional_utxo_infos, - |account, db_tx| Ok((f(account, db_tx)?, ())), - |err| err, - )? - .0) + self.async_for_account_rw_unlocked_and_check_tx_custom_error( + account_index, + additional_utxo_infos, + |account, db_tx| Ok((f(account, db_tx)?, ())), + |err| err, + ) + .await + .map(|(tx, _)| tx) } fn get_account(&self, account_index: U31) -> WalletResult<&Account> { @@ -1129,6 +1216,24 @@ where .ok_or(WalletError::NoAccountFoundWithIndex(account_index)) } + async fn use_account_mut( + accounts: &mut BTreeMap>, + account_index: U31, + f: impl FnOnce(Account) -> Fut, + ) -> WalletResult + where + Fut: Future, T)>, + { + let acc = accounts + .remove(&account_index) + .ok_or(WalletError::NoAccountFoundWithIndex(account_index))?; + + let (acc, res) = f(acc).await; + + accounts.insert(account_index, acc); + Ok(res) + } + pub fn get_balance( &self, account_index: U31, @@ -1417,7 +1522,7 @@ where /// /// A `WalletResult` containing the signed transaction if successful, or an error indicating the reason for failure. #[allow(clippy::too_many_arguments)] - pub fn create_transaction_to_addresses( + pub async fn create_transaction_to_addresses( &mut self, account_index: U31, outputs: impl IntoIterator, @@ -1425,7 +1530,7 @@ where change_addresses: BTreeMap>, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, - additional_utxo_infos: &BTreeMap, + additional_utxo_infos: BTreeMap, ) -> WalletResult { Ok(self .create_transaction_to_addresses_impl( @@ -1436,15 +1541,16 @@ where current_fee_rate, consolidate_fee_rate, |_s| (), - additional_utxo_infos, - )? + &additional_utxo_infos, + ) + .await? .0) } /// Same as `create_transaction_to_addresses`, but it also allows to specify the "intent" for the transaction, /// which will be concatenated with the transaction id and signed with all the keys used to sign the transaction's inputs. #[allow(clippy::too_many_arguments)] - pub fn create_transaction_to_addresses_with_intent( + pub async fn create_transaction_to_addresses_with_intent( &mut self, account_index: U31, outputs: impl IntoIterator, @@ -1455,38 +1561,47 @@ where consolidate_fee_rate: FeeRate, additional_utxo_infos: &BTreeMap, ) -> WalletResult<(SignedTransaction, SignedTransactionIntent)> { - let (signed_tx, input_destinations) = self.create_transaction_to_addresses_impl( - account_index, - outputs, - inputs, - change_addresses, - current_fee_rate, - consolidate_fee_rate, - |send_request| send_request.destinations().to_owned(), - additional_utxo_infos, - )?; + let (signed_tx, input_destinations) = self + .create_transaction_to_addresses_impl( + account_index, + outputs, + inputs, + change_addresses, + current_fee_rate, + consolidate_fee_rate, + |send_request| send_request.destinations().to_owned(), + additional_utxo_infos, + ) + .await?; - let signed_intent = self.for_account_rw_unlocked( - account_index, - |account, db_tx, chain_config, signer_provider| { - let mut signer = - signer_provider.provide(Arc::new(chain_config.clone()), account_index); - - Ok(signer.sign_transaction_intent( - signed_tx.transaction(), - &input_destinations, - &intent, - account.key_chain(), - db_tx, - )?) - }, - )?; + let transaction = signed_tx.transaction(); + let signed_intent = self + .async_for_account_rw_unlocked( + account_index, + |account, db_tx, _chain_config, mut signer| { + let store = db_tx.read_only_store(); + async move { + let result = signer + .sign_transaction_intent( + transaction, + &input_destinations, + &intent, + account.key_chain(), + &store, + ) + .await + .map_err(Into::into); + (account, result) + } + }, + ) + .await?; Ok((signed_tx, signed_intent)) } #[allow(clippy::too_many_arguments)] - fn create_transaction_to_addresses_impl( + async fn create_transaction_to_addresses_impl( &mut self, account_index: U31, outputs: impl IntoIterator, @@ -1499,7 +1614,7 @@ where ) -> WalletResult<(SignedTransaction, AddlData)> { let request = SendRequest::new().with_outputs(outputs); let latest_median_time = self.latest_median_time; - self.for_account_rw_unlocked_and_check_tx_generic( + self.async_for_account_rw_unlocked_and_check_tx_custom_error( account_index, additional_utxo_infos, |account, db_tx| { @@ -1520,6 +1635,7 @@ where }, |err| err, ) + .await } #[allow(clippy::too_many_arguments)] @@ -1553,7 +1669,7 @@ where }) } - pub fn create_sweep_transaction( + pub async fn create_sweep_transaction( &mut self, account_index: U31, destination: Destination, @@ -1566,14 +1682,15 @@ where &|_| None, )?; - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, additional_utxo_infos, |account, _| account.sweep_addresses(destination, request, current_fee_rate), ) + .await } - pub fn create_sweep_from_delegation_transaction( + pub async fn create_sweep_from_delegation_transaction( &mut self, account_index: U31, address: Address, @@ -1581,12 +1698,17 @@ where delegation_share: Amount, current_fee_rate: FeeRate, ) -> WalletResult { - self.for_account_rw_unlocked_and_check_tx(account_index, &BTreeMap::new(), |account, _| { - account.sweep_delegation(address, delegation_id, delegation_share, current_fee_rate) - }) + self.async_for_account_rw_unlocked_and_check_tx( + account_index, + &BTreeMap::new(), + |account, _| { + account.sweep_delegation(address, delegation_id, delegation_share, current_fee_rate) + }, + ) + .await } - pub fn create_transaction_to_addresses_from_delegation( + pub async fn create_transaction_to_addresses_from_delegation( &mut self, account_index: U31, address: Address, @@ -1595,18 +1717,23 @@ where delegation_share: Amount, current_fee_rate: FeeRate, ) -> WalletResult { - self.for_account_rw_unlocked_and_check_tx(account_index, &BTreeMap::new(), |account, _| { - account.spend_from_delegation( - address, - amount, - delegation_id, - delegation_share, - current_fee_rate, - ) - }) + self.async_for_account_rw_unlocked_and_check_tx( + account_index, + &BTreeMap::new(), + |account, _| { + account.spend_from_delegation( + address, + amount, + delegation_id, + delegation_share, + current_fee_rate, + ) + }, + ) + .await } - pub fn mint_tokens( + pub async fn mint_tokens( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1617,7 +1744,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1634,9 +1761,10 @@ where ) }, ) + .await } - pub fn unmint_tokens( + pub async fn unmint_tokens( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1646,7 +1774,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1662,9 +1790,10 @@ where ) }, ) + .await } - pub fn lock_token_supply( + pub async fn lock_token_supply( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1673,7 +1802,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1688,9 +1817,10 @@ where ) }, ) + .await } - pub fn freeze_token( + pub async fn freeze_token( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1700,7 +1830,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1716,9 +1846,10 @@ where ) }, ) + .await } - pub fn unfreeze_token( + pub async fn unfreeze_token( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1727,7 +1858,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1742,9 +1873,10 @@ where ) }, ) + .await } - pub fn change_token_authority( + pub async fn change_token_authority( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1754,7 +1886,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1770,9 +1902,10 @@ where ) }, ) + .await } - pub fn change_token_metadata_uri( + pub async fn change_token_metadata_uri( &mut self, account_index: U31, token_info: &UnconfirmedTokenInfo, @@ -1782,7 +1915,7 @@ where ) -> WalletResult { let latest_median_time = self.latest_median_time; let additional_utxo_infos = to_token_additional_info(token_info); - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &additional_utxo_infos, |account, db_tx| { @@ -1798,6 +1931,7 @@ where ) }, ) + .await } pub fn find_used_tokens( @@ -1817,28 +1951,30 @@ where self.get_account(account_index)?.get_token_unconfirmed_info(token_info) } - pub fn create_delegation( + pub async fn create_delegation( &mut self, account_index: U31, outputs: Vec, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> WalletResult<(DelegationId, SignedTransaction)> { - let tx = self.create_transaction_to_addresses( - account_index, - outputs, - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - current_fee_rate, - consolidate_fee_rate, - &BTreeMap::new(), - )?; + let tx = self + .create_transaction_to_addresses( + account_index, + outputs, + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + current_fee_rate, + consolidate_fee_rate, + BTreeMap::new(), + ) + .await?; let input0_outpoint = crate::utils::get_first_utxo_outpoint(tx.transaction().inputs())?; let delegation_id = make_delegation_id(input0_outpoint); Ok((delegation_id, tx)) } - pub fn issue_new_token( + pub async fn issue_new_token( &mut self, account_index: U31, token_issuance: TokenIssuance, @@ -1847,21 +1983,23 @@ where ) -> WalletResult<(TokenId, SignedTransaction)> { let outputs = make_issue_token_outputs(token_issuance, self.chain_config.as_ref())?; - let tx = self.create_transaction_to_addresses( - account_index, - outputs, - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - current_fee_rate, - consolidate_fee_rate, - &BTreeMap::new(), - )?; + let tx = self + .create_transaction_to_addresses( + account_index, + outputs, + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + current_fee_rate, + consolidate_fee_rate, + BTreeMap::new(), + ) + .await?; let token_id = make_token_id(tx.transaction().inputs()).ok_or(WalletError::MissingTokenId)?; Ok((token_id, tx)) } - pub fn issue_new_nft( + pub async fn issue_new_nft( &mut self, account_index: U31, address: Address, @@ -1872,31 +2010,33 @@ where let destination = address.into_object(); let latest_median_time = self.latest_median_time; - let signed_transaction = self.for_account_rw_unlocked_and_check_tx( - account_index, - &BTreeMap::new(), - |account, db_tx| { - account.create_issue_nft_tx( - db_tx, - IssueNftArguments { - metadata, - destination, - }, - latest_median_time, - CurrentFeeRate { - current_fee_rate, - consolidate_fee_rate, - }, - ) - }, - )?; + let signed_transaction = self + .async_for_account_rw_unlocked_and_check_tx( + account_index, + &BTreeMap::new(), + |account, db_tx| { + account.create_issue_nft_tx( + db_tx, + IssueNftArguments { + metadata, + destination, + }, + latest_median_time, + CurrentFeeRate { + current_fee_rate, + consolidate_fee_rate, + }, + ) + }, + ) + .await?; let token_id = make_token_id(signed_transaction.transaction().inputs()) .ok_or(WalletError::MissingTokenId)?; Ok((token_id, signed_transaction)) } - pub fn decommission_stake_pool( + pub async fn decommission_stake_pool( &mut self, account_index: U31, pool_id: PoolId, @@ -1908,28 +2048,27 @@ where PoolOrTokenId::PoolId(pool_id), UtxoAdditionalInfo::PoolInfo { staker_balance }, )]); - Ok(self - .for_account_rw_unlocked_and_check_tx_generic( - account_index, - &additional_utxo_infos, - |account, db_tx| { - Ok(( - account.decommission_stake_pool( - db_tx, - pool_id, - staker_balance, - output_address, - current_fee_rate, - )?, - (), - )) - }, - |_err| WalletError::PartiallySignedTransactionInDecommissionCommand, - )? - .0) + self.async_for_account_rw_unlocked_and_check_tx_custom_error( + account_index, + &additional_utxo_infos, + |account: &mut Account<

::K>, db_tx| { + account + .decommission_stake_pool( + db_tx, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .map(|r| (r, ())) + }, + |_err| WalletError::PartiallySignedTransactionInDecommissionCommand, + ) + .await + .map(|(x, _)| x) } - pub fn decommission_stake_pool_request( + pub async fn decommission_stake_pool_request( &mut self, account_index: U31, pool_id: PoolId, @@ -1941,32 +2080,76 @@ where PoolOrTokenId::PoolId(pool_id), UtxoAdditionalInfo::PoolInfo { staker_balance }, )]); - self.for_account_rw_unlocked( + + self.async_for_account_rw_unlocked( account_index, - |account, db_tx, chain_config, signer_provider| { + |mut account, db_tx, chain_config, signer| { let request = account.decommission_stake_pool_request( db_tx, pool_id, staker_balance, output_address, current_fee_rate, - )?; - - let ptx = request.into_partially_signed_tx(&additional_utxo_infos)?; + ); + + let store = db_tx.read_only_store(); + async move { + let mut signer = signer; + let request = match request { + Ok(x) => x, + Err(err) => return (account, Err(err)), + }; + + let ptx = match request.into_partially_signed_tx(&additional_utxo_infos) { + Ok(x) => x, + Err(err) => return (account, Err(err)), + }; + + let ptx = match signer + .sign_tx(ptx, account.key_chain(), &store) + .await + .map(|(ptx, _, _)| ptx) + { + Ok(x) => x, + Err(err) => return (account, Err(err.into())), + }; + + let inputs_utxo_refs: Vec<_> = + ptx.input_utxos().iter().map(|u| u.as_ref().map(|x| &x.utxo)).collect(); + let is_fully_signed = ptx + .destinations() + .iter() + .enumerate() + .zip(ptx.witnesses()) + .all(|((i, destination), witness)| match (witness, destination) { + (None | Some(_), None) | (None, Some(_)) => false, + (Some(_), Some(destination)) => { + tx_verifier::input_check::signature_only_check::verify_tx_signature( + &chain_config, + destination, + &ptx, + &inputs_utxo_refs, + i, + ) + .is_ok() + } + }); - let mut signer = - signer_provider.provide(Arc::new(chain_config.clone()), account_index); - let ptx = signer.sign_tx(ptx, account.key_chain(), db_tx).map(|(ptx, _, _)| ptx)?; + if is_fully_signed { + return ( + account, + Err(WalletError::FullySignedTransactionInDecommissionReq), + ); + } - if ptx.all_signatures_available() { - return Err(WalletError::FullySignedTransactionInDecommissionReq); + (account, Ok(ptx)) } - Ok(ptx) }, ) + .await } - pub fn create_htlc_tx( + pub async fn create_htlc_tx( &mut self, account_index: U31, output_value: OutputValue, @@ -1976,7 +2159,7 @@ where additional_utxo_infos: &BTreeMap, ) -> WalletResult { let latest_median_time = self.latest_median_time; - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, additional_utxo_infos, |account, db_tx| { @@ -1992,10 +2175,11 @@ where ) }, ) + .await } #[allow(clippy::too_many_arguments)] - pub fn create_order_tx( + pub async fn create_order_tx( &mut self, account_index: U31, ask_value: OutputValue, @@ -2006,30 +2190,32 @@ where additional_utxo_infos: &BTreeMap, ) -> WalletResult<(OrderId, SignedTransaction)> { let latest_median_time = self.latest_median_time; - let tx = self.for_account_rw_unlocked_and_check_tx( - account_index, - additional_utxo_infos, - |account, db_tx| { - account.create_order_tx( - db_tx, - ask_value, - give_value, - conclude_key, - latest_median_time, - CurrentFeeRate { - current_fee_rate, - consolidate_fee_rate, - }, - ) - }, - )?; + let tx = self + .async_for_account_rw_unlocked_and_check_tx( + account_index, + additional_utxo_infos, + |account, db_tx| { + account.create_order_tx( + db_tx, + ask_value, + give_value, + conclude_key, + latest_median_time, + CurrentFeeRate { + current_fee_rate, + consolidate_fee_rate, + }, + ) + }, + ) + .await?; let input0_outpoint = crate::utils::get_first_utxo_outpoint(tx.transaction().inputs())?; let order_id = make_order_id(input0_outpoint); Ok((order_id, tx)) } #[allow(clippy::too_many_arguments)] - pub fn create_conclude_order_tx( + pub async fn create_conclude_order_tx( &mut self, account_index: U31, order_id: OrderId, @@ -2040,7 +2226,7 @@ where additional_utxo_infos: &BTreeMap, ) -> WalletResult { let latest_median_time = self.latest_median_time; - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, additional_utxo_infos, |account, db_tx| { @@ -2057,10 +2243,11 @@ where ) }, ) + .await } #[allow(clippy::too_many_arguments)] - pub fn create_fill_order_tx( + pub async fn create_fill_order_tx( &mut self, account_index: U31, order_id: OrderId, @@ -2072,7 +2259,7 @@ where additional_utxo_infos: &BTreeMap, ) -> WalletResult { let latest_median_time = self.latest_median_time; - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, additional_utxo_infos, |account, db_tx| { @@ -2090,9 +2277,10 @@ where ) }, ) + .await } - pub fn sign_raw_transaction( + pub async fn sign_raw_transaction( &mut self, account_index: U31, ptx: PartiallySignedTransaction, @@ -2101,34 +2289,41 @@ where Vec, Vec, )> { - self.for_account_rw_unlocked( + self.async_for_account_rw_unlocked( account_index, - |account, db_tx, chain_config, signer_provider| { - let mut signer = - signer_provider.provide(Arc::new(chain_config.clone()), account_index); + |account, db_tx, _chain_config, mut signer| { + let store = db_tx.read_only_store(); - let res = signer.sign_tx(ptx, account.key_chain(), db_tx)?; - Ok(res) + async move { + let result = + signer.sign_tx(ptx, account.key_chain(), &store).await.map_err(Into::into); + (account, result) + } }, ) + .await } - pub fn sign_challenge( + pub async fn sign_challenge( &mut self, account_index: U31, challenge: &[u8], destination: &Destination, ) -> WalletResult { - self.for_account_rw_unlocked( + self.async_for_account_rw_unlocked( account_index, - |account, db_tx, chain_config, signer_provider| { - let mut signer = - signer_provider.provide(Arc::new(chain_config.clone()), account_index); - let msg = - signer.sign_challenge(challenge, destination, account.key_chain(), db_tx)?; - Ok(msg) + |account, db_tx, _chain_config, mut signer| { + let store = db_tx.read_only_store(); + async move { + let result = signer + .sign_challenge(challenge, destination, account.key_chain(), &store) + .await + .map_err(Into::into); + (account, result) + } }, ) + .await } /// Returns the last scanned block hash and height for all accounts. @@ -2340,7 +2535,7 @@ where Ok(account.get_legacy_vrf_public_key()) } - pub fn create_stake_pool_tx( + pub async fn create_stake_pool_tx( &mut self, account_index: U31, current_fee_rate: FeeRate, @@ -2348,7 +2543,7 @@ where stake_pool_arguments: StakePoolDataArguments, ) -> WalletResult { let latest_median_time = self.latest_median_time; - self.for_account_rw_unlocked_and_check_tx( + self.async_for_account_rw_unlocked_and_check_tx( account_index, &BTreeMap::new(), |account, db_tx| { @@ -2363,6 +2558,7 @@ where ) }, ) + .await } pub fn get_pos_gen_block_data( &self, diff --git a/wallet/src/wallet/tests.rs b/wallet/src/wallet/tests.rs index 7cbaf2945..794360390 100644 --- a/wallet/src/wallet/tests.rs +++ b/wallet/src/wallet/tests.rs @@ -964,8 +964,8 @@ fn test_wallet_accounts( assert_eq!(accounts, expected_accounts); } -#[test] -fn wallet_accounts_creation() { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_accounts_creation() { let chain_config = Arc::new(create_mainnet()); let mut wallet = create_wallet(chain_config.clone()); @@ -999,8 +999,9 @@ fn wallet_accounts_creation() { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); // even with an unconfirmed transaction we cannot create a new account @@ -1124,7 +1125,8 @@ fn wallet_recover_new_account(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1152,18 +1154,20 @@ fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) { ); assert_eq!( - wallet.create_transaction_to_addresses( - DEFAULT_ACCOUNT_INDEX, - [new_output.clone()], - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - FeeRate::from_amount_per_kb(Amount::ZERO), - FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), - ), - Err(WalletError::DatabaseError( - wallet_storage::Error::WalletLocked - )) + wallet + .create_transaction_to_addresses( + DEFAULT_ACCOUNT_INDEX, + [new_output.clone()], + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + FeeRate::from_amount_per_kb(Amount::ZERO), + FeeRate::from_amount_per_kb(Amount::ZERO), + BTreeMap::new(), + ) + .await, + Err(WalletError::SignerError(SignerError::KeyChainError( + KeyChainError::DatabaseError(wallet_storage::Error::WalletLocked) + ))) ); // success after unlock @@ -1177,8 +1181,9 @@ fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); } else { // check if we remove the password it should fail to lock @@ -1207,15 +1212,17 @@ fn locked_wallet_cant_sign_transaction(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); } } #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_get_transaction(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_get_transaction(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1235,8 +1242,9 @@ fn wallet_get_transaction(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); let tx_id = tx.transaction().get_id(); @@ -1273,7 +1281,8 @@ fn wallet_get_transaction(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_list_mainchain_transactions(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_list_mainchain_transactions(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -1295,8 +1304,9 @@ fn wallet_list_mainchain_transactions(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); let send_tx_id = tx.transaction().get_id(); @@ -1318,8 +1328,9 @@ fn wallet_list_mainchain_transactions(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); let spend_from_tx_id = tx.transaction().get_id(); @@ -1341,7 +1352,8 @@ fn wallet_list_mainchain_transactions(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_transaction_with_fees(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_transaction_with_fees(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1373,8 +1385,9 @@ fn wallet_transaction_with_fees(#[case] seed: Seed) { BTreeMap::new(), very_big_feerate, very_big_feerate, - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap_err(); match err { @@ -1401,8 +1414,9 @@ fn wallet_transaction_with_fees(#[case] seed: Seed) { BTreeMap::new(), feerate, feerate, - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); let tx_size = serialization::Encode::encoded_size(&transaction); @@ -1437,7 +1451,8 @@ fn lock_wallet_fail_empty_password() { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn spend_from_user_specified_utxos(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn spend_from_user_specified_utxos(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1488,8 +1503,9 @@ fn spend_from_user_specified_utxos(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotFindUtxo(missing_utxo.clone())); @@ -1515,8 +1531,9 @@ fn spend_from_user_specified_utxos(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); // check that we only have the selected_utxo as inputs @@ -1553,8 +1570,9 @@ fn spend_from_user_specified_utxos(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap_err(); assert_eq!( @@ -1567,7 +1585,8 @@ fn spend_from_user_specified_utxos(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { use crypto::vrf::transcript::no_rng::VRFTranscript; let mut rng = make_seedable_rng(seed); @@ -1604,6 +1623,7 @@ fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { decommission_key: decommission_key.as_object().clone(), }, ) + .await .unwrap(); let stake_pool_transaction_id = stake_pool_transaction.transaction().get_id(); let (addr, block2) = create_block( @@ -1696,6 +1716,7 @@ fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { None, FeeRate::from_amount_per_kb(Amount::from_atoms(0)), ) + .await .unwrap(); let _ = create_block( @@ -1715,7 +1736,8 @@ fn create_stake_pool_and_list_pool_ids(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn reset_keys_after_failed_transaction(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn reset_keys_after_failed_transaction(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1736,17 +1758,19 @@ fn reset_keys_after_failed_transaction(#[case] seed: Seed) { let last_issued_address = wallet.get_addresses_usage(DEFAULT_ACCOUNT_INDEX).unwrap().last_issued(); - let result = wallet.create_stake_pool_tx( - DEFAULT_ACCOUNT_INDEX, - FeeRate::from_amount_per_kb(Amount::ZERO), - FeeRate::from_amount_per_kb(Amount::ZERO), - StakePoolDataArguments { - amount: not_enough, - margin_ratio_per_thousand: PerThousand::new_from_rng(&mut rng), - cost_per_block: Amount::ZERO, - decommission_key: Destination::AnyoneCanSpend, - }, - ); + let result = wallet + .create_stake_pool_tx( + DEFAULT_ACCOUNT_INDEX, + FeeRate::from_amount_per_kb(Amount::ZERO), + FeeRate::from_amount_per_kb(Amount::ZERO), + StakePoolDataArguments { + amount: not_enough, + margin_ratio_per_thousand: PerThousand::new_from_rng(&mut rng), + cost_per_block: Amount::ZERO, + decommission_key: Destination::AnyoneCanSpend, + }, + ) + .await; // check that result is an error and we last issued address is still the same assert!(result.is_err()); assert_eq!( @@ -1758,7 +1782,8 @@ fn reset_keys_after_failed_transaction(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn send_to_unknown_delegation(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn send_to_unknown_delegation(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1820,6 +1845,7 @@ fn send_to_unknown_delegation(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block_height = 2; @@ -1851,8 +1877,9 @@ fn send_to_unknown_delegation(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); let block_height = 3; @@ -1890,6 +1917,7 @@ fn send_to_unknown_delegation(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let _ = create_block( @@ -1914,7 +1942,8 @@ fn send_to_unknown_delegation(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_spend_from_delegations(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn create_spend_from_delegations(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -1948,6 +1977,7 @@ fn create_spend_from_delegations(#[case] seed: Seed) { decommission_key: Destination::AnyoneCanSpend, }, ) + .await .unwrap(); let (address, _) = create_block( @@ -1972,6 +2002,7 @@ fn create_spend_from_delegations(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let _ = create_block( @@ -1999,8 +2030,9 @@ fn create_spend_from_delegations(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); let _ = create_block( @@ -2020,6 +2052,7 @@ fn create_spend_from_delegations(#[case] seed: Seed) { Amount::from_atoms(2), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet @@ -2052,6 +2085,7 @@ fn create_spend_from_delegations(#[case] seed: Seed) { Amount::from_atoms(1), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet .add_account_unconfirmed_tx( @@ -2123,6 +2157,7 @@ fn create_spend_from_delegations(#[case] seed: Seed) { Amount::from_atoms(1), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet .add_account_unconfirmed_tx(DEFAULT_ACCOUNT_INDEX, delegation_tx3, &WalletEventsNoOp) @@ -2149,7 +2184,8 @@ fn create_spend_from_delegations(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn issue_and_transfer_tokens(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn issue_and_transfer_tokens(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -2223,6 +2259,7 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let freezable = token_issuance.is_freezable.as_bool(); @@ -2266,8 +2303,9 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet .add_account_unconfirmed_tx( @@ -2289,6 +2327,7 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); ( @@ -2315,6 +2354,7 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); random_issuing_wallet .add_unconfirmed_tx(nft_issuance_transaction.clone(), &WalletEventsNoOp) @@ -2331,8 +2371,9 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); (issued_token_id, vec![nft_issuance_transaction, transfer_tx]) }; @@ -2384,8 +2425,9 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &additional_info, + additional_info.clone(), ) + .await .unwrap(); wallet .add_account_unconfirmed_tx( @@ -2438,8 +2480,9 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &additional_info, + additional_info, ) + .await .err() .unwrap(); @@ -2463,7 +2506,8 @@ fn issue_and_transfer_tokens(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn check_tokens_v0_are_ignored(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn check_tokens_v0_are_ignored(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -2485,25 +2529,27 @@ fn check_tokens_v0_are_ignored(#[case] seed: Seed) { let address2 = wallet.get_new_address(DEFAULT_ACCOUNT_INDEX).unwrap().1; let token_ticker = "XXXX".as_bytes().to_vec(); let number_of_decimals = rng.gen_range(1..18); - let result = wallet.create_transaction_to_addresses( - DEFAULT_ACCOUNT_INDEX, - [TxOutput::Transfer( - OutputValue::TokenV0(Box::new(TokenData::TokenIssuance(Box::new( - TokenIssuanceV0 { - token_ticker, - number_of_decimals, - metadata_uri: "http://uri".as_bytes().to_vec(), - amount_to_issue: Amount::from_atoms(rng.gen_range(1..10000)), - }, - )))), - address2.into_object(), - )], - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - FeeRate::from_amount_per_kb(Amount::ZERO), - FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), - ); + let result = wallet + .create_transaction_to_addresses( + DEFAULT_ACCOUNT_INDEX, + [TxOutput::Transfer( + OutputValue::TokenV0(Box::new(TokenData::TokenIssuance(Box::new( + TokenIssuanceV0 { + token_ticker, + number_of_decimals, + metadata_uri: "http://uri".as_bytes().to_vec(), + amount_to_issue: Amount::from_atoms(rng.gen_range(1..10000)), + }, + )))), + address2.into_object(), + )], + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + FeeRate::from_amount_per_kb(Amount::ZERO), + FeeRate::from_amount_per_kb(Amount::ZERO), + BTreeMap::new(), + ) + .await; matches!( result.unwrap_err(), @@ -2521,7 +2567,8 @@ fn check_tokens_v0_are_ignored(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -2558,6 +2605,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -2596,6 +2644,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let _ = create_block(&chain_config, &mut wallet, vec![mint_tx], block2_amount, 2); @@ -2612,6 +2661,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet.add_unconfirmed_tx(freeze_tx.clone(), &WalletEventsNoOp).unwrap(); @@ -2640,6 +2690,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet.add_unconfirmed_tx(unfreeze_tx.clone(), &WalletEventsNoOp).unwrap(); @@ -2711,6 +2762,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let tokens_to_transfer = Amount::from_atoms(rng.gen_range(1..=amount_to_mint.into_atoms())); @@ -2735,8 +2787,9 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &additional_info, + additional_info, ) + .await .unwrap(); wallet @@ -2771,6 +2824,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotFreezeAlreadyFrozenToken); @@ -2782,6 +2836,7 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotUnfreezeToken); @@ -2820,7 +2875,8 @@ fn freeze_and_unfreeze_tokens(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn change_token_supply_fixed(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn change_token_supply_fixed(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -2856,6 +2912,7 @@ fn change_token_supply_fixed(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -2909,6 +2966,7 @@ fn change_token_supply_fixed(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet.add_unconfirmed_tx(mint_transaction.clone(), &WalletEventsNoOp).unwrap(); @@ -2930,6 +2988,7 @@ fn change_token_supply_fixed(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!( @@ -3008,6 +3067,7 @@ fn change_token_supply_fixed(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!( err, @@ -3024,6 +3084,7 @@ fn change_token_supply_fixed(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet @@ -3067,6 +3128,7 @@ fn change_token_supply_fixed(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotLockTokenSupply("Fixed")); } @@ -3074,7 +3136,8 @@ fn change_token_supply_fixed(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn change_token_supply_unlimited(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn change_token_supply_unlimited(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -3109,6 +3172,7 @@ fn change_token_supply_unlimited(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -3163,6 +3227,7 @@ fn change_token_supply_unlimited(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet.add_unconfirmed_tx(mint_transaction.clone(), &WalletEventsNoOp).unwrap(); @@ -3203,6 +3268,7 @@ fn change_token_supply_unlimited(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!( err, @@ -3219,6 +3285,7 @@ fn change_token_supply_unlimited(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet .add_unconfirmed_tx(unmint_transaction.clone(), &WalletEventsNoOp) @@ -3261,6 +3328,7 @@ fn change_token_supply_unlimited(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotLockTokenSupply("Unlimited")); } @@ -3268,7 +3336,8 @@ fn change_token_supply_unlimited(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -3303,6 +3372,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -3357,6 +3427,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet.add_unconfirmed_tx(mint_transaction.clone(), &WalletEventsNoOp).unwrap(); let unconfirmed_token_info = wallet @@ -3396,6 +3467,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!( err, @@ -3412,6 +3484,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); wallet @@ -3452,6 +3525,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let _ = create_block( @@ -3491,6 +3565,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotChangeLockedTokenSupply); let err = wallet @@ -3501,6 +3576,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotChangeLockedTokenSupply); @@ -3511,6 +3587,7 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap_err(); assert_eq!(err, WalletError::CannotLockTokenSupply("Locked")); } @@ -3518,7 +3595,8 @@ fn change_and_lock_token_supply_lockable(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn lock_then_transfer(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn lock_then_transfer(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -3583,8 +3661,9 @@ fn lock_then_transfer(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet .add_unconfirmed_tx(lock_then_transfer_transaction.clone(), &WalletEventsNoOp) @@ -3655,7 +3734,8 @@ fn lock_then_transfer(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_multiple_transactions_in_single_block(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -3705,8 +3785,9 @@ fn wallet_multiple_transactions_in_single_block(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet.add_unconfirmed_tx(transaction.clone(), &WalletEventsNoOp).unwrap(); @@ -3734,7 +3815,8 @@ fn wallet_multiple_transactions_in_single_block(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -3797,8 +3879,9 @@ fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet.add_unconfirmed_tx(transaction.clone(), &WalletEventsNoOp).unwrap(); @@ -3833,8 +3916,9 @@ fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet.add_unconfirmed_tx(transaction.clone(), &WalletEventsNoOp).unwrap(); @@ -3873,8 +3957,9 @@ fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap_err(); assert_eq!( err, @@ -3900,8 +3985,9 @@ fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet.add_unconfirmed_tx(transaction.clone(), &WalletEventsNoOp).unwrap(); @@ -3924,7 +4010,8 @@ fn wallet_scan_multiple_transactions_from_mempool(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn wallet_abandone_transactions(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn wallet_abandone_transactions(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -3985,8 +4072,9 @@ fn wallet_abandone_transactions(#[case] seed: Seed) { BTreeMap::new(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); wallet .add_account_unconfirmed_tx( @@ -4131,7 +4219,8 @@ fn wallet_set_lookahead_size(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn decommission_pool_wrong_account(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn decommission_pool_wrong_account(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -4172,6 +4261,7 @@ fn decommission_pool_wrong_account(#[case] seed: Seed) { decommission_key: decommission_key.into_object(), }, ) + .await .unwrap(); let _ = create_block( &chain_config, @@ -4186,13 +4276,15 @@ fn decommission_pool_wrong_account(#[case] seed: Seed) { // Try to decommission the pool with default account let pool_id = pool_ids.first().unwrap().0; - let decommission_cmd_res = wallet.decommission_stake_pool( - acc_0_index, - pool_id, - pool_amount, - None, - FeeRate::from_amount_per_kb(Amount::from_atoms(0)), - ); + let decommission_cmd_res = wallet + .decommission_stake_pool( + acc_0_index, + pool_id, + pool_amount, + None, + FeeRate::from_amount_per_kb(Amount::from_atoms(0)), + ) + .await; assert_eq!( decommission_cmd_res.unwrap_err(), WalletError::PartiallySignedTransactionInDecommissionCommand @@ -4207,6 +4299,7 @@ fn decommission_pool_wrong_account(#[case] seed: Seed) { None, FeeRate::from_amount_per_kb(Amount::from_atoms(0)), ) + .await .unwrap(); let _ = create_block( @@ -4224,7 +4317,8 @@ fn decommission_pool_wrong_account(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn decommission_pool_request_wrong_account(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn decommission_pool_request_wrong_account(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_mainnet()); @@ -4265,6 +4359,7 @@ fn decommission_pool_request_wrong_account(#[case] seed: Seed) { decommission_key: decommission_key.into_object(), }, ) + .await .unwrap(); let _ = create_block( &chain_config, @@ -4279,13 +4374,15 @@ fn decommission_pool_request_wrong_account(#[case] seed: Seed) { // Try to create decommission request from account that holds the key let pool_id = pool_ids.first().unwrap().0; - let decommission_req_res = wallet.decommission_stake_pool_request( - acc_1_index, - pool_id, - pool_amount, - None, - FeeRate::from_amount_per_kb(Amount::from_atoms(0)), - ); + let decommission_req_res = wallet + .decommission_stake_pool_request( + acc_1_index, + pool_id, + pool_amount, + None, + FeeRate::from_amount_per_kb(Amount::from_atoms(0)), + ) + .await; assert_eq!( decommission_req_res.unwrap_err(), WalletError::FullySignedTransactionInDecommissionReq @@ -4299,6 +4396,7 @@ fn decommission_pool_request_wrong_account(#[case] seed: Seed) { None, FeeRate::from_amount_per_kb(Amount::from_atoms(0)), ) + .await .unwrap(); assert!(!decommission_partial_tx.all_signatures_available()); matches!( @@ -4310,7 +4408,8 @@ fn decommission_pool_request_wrong_account(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -4352,6 +4451,7 @@ fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { decommission_key: decommission_key.into_object(), }, ) + .await .unwrap(); // remove the signatures and try to sign it again @@ -4369,6 +4469,7 @@ fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { .unwrap(); let stake_pool_transaction = wallet .sign_raw_transaction(acc_0_index, ptx) + .await .unwrap() .0 .into_signed_tx() @@ -4396,11 +4497,13 @@ fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { None, FeeRate::from_amount_per_kb(Amount::from_atoms(0)), ) + .await .unwrap(); // Try to sign decommission request with wrong account let sign_from_acc0_res = wallet .sign_raw_transaction(acc_0_index, decommission_partial_tx.clone()) + .await .unwrap() .0; // the tx is still not fully signed @@ -4408,6 +4511,7 @@ fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { let signed_tx = wallet .sign_raw_transaction(acc_1_index, decommission_partial_tx) + .await .unwrap() .0 .into_signed_tx() @@ -4423,7 +4527,8 @@ fn sign_decommission_pool_request_between_accounts(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -4465,6 +4570,7 @@ fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { decommission_key: decommission_key.into_object(), }, ) + .await .unwrap(); let _ = create_block( &chain_config, @@ -4486,11 +4592,13 @@ fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { None, FeeRate::from_amount_per_kb(Amount::from_atoms(0)), ) + .await .unwrap(); // sign the tx with cold wallet let partially_signed_transaction = cold_wallet .sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, decommission_partial_tx) + .await .unwrap() .0; assert!(partially_signed_transaction.all_signatures_available()); @@ -4499,6 +4607,7 @@ fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { // destinations for the inputs let partially_signed_transaction = hot_wallet .sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, partially_signed_transaction) + .await .unwrap() .0; assert!(partially_signed_transaction.all_signatures_available()); @@ -4520,7 +4629,8 @@ fn sign_decommission_pool_request_cold_wallet(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn filter_pools(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn filter_pools(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -4560,6 +4670,7 @@ fn filter_pools(#[case] seed: Seed) { decommission_key: decommission_key.into_object(), }, ) + .await .unwrap(); // sync for wallet1 let _ = create_block( @@ -4606,7 +4717,8 @@ fn filter_pools(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn sign_send_request_cold_wallet(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn sign_send_request_cold_wallet(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -4660,6 +4772,7 @@ fn sign_send_request_cold_wallet(#[case] seed: Seed) { // Try to sign request with the hot wallet let tx = hot_wallet .sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, send_req.clone()) + .await .unwrap() .0; // the tx is not fully signed @@ -4668,6 +4781,7 @@ fn sign_send_request_cold_wallet(#[case] seed: Seed) { // sign the tx with cold wallet let signed_tx = cold_wallet .sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, send_req) + .await .unwrap() .0 .into_signed_tx() @@ -4716,7 +4830,8 @@ fn sign_send_request_cold_wallet(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn test_not_exhaustion_of_keys(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_not_exhaustion_of_keys(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -4756,8 +4871,9 @@ fn test_not_exhaustion_of_keys(#[case] seed: Seed) { [].into(), FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), - &BTreeMap::new(), + BTreeMap::new(), ) + .await .unwrap(); } } @@ -4818,7 +4934,8 @@ fn test_add_standalone_private_key(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn test_add_standalone_multisig(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_add_standalone_multisig(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_regtest()); @@ -4902,28 +5019,32 @@ fn test_add_standalone_multisig(#[case] seed: Seed) { .unwrap(); // sign it with wallet1 - let (ptx, _, statuses) = - wallet1.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, spend_multisig_tx).unwrap(); + let (ptx, _, statuses) = wallet1 + .sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, spend_multisig_tx) + .await + .unwrap(); // check it is still not fully signed assert!(ptx.all_signatures_available()); assert!(!statuses.iter().all(|s| *s == SignatureStatus::FullySigned)); // try to sign it with wallet1 again - let (ptx, _, statuses) = wallet1.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, ptx).unwrap(); + let (ptx, _, statuses) = + wallet1.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, ptx).await.unwrap(); // check it is still not fully signed assert!(ptx.all_signatures_available()); assert!(!statuses.iter().all(|s| *s == SignatureStatus::FullySigned)); // try to sign it with wallet2 but wallet2 does not have the multisig added as standalone - let ptx = wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, ptx).unwrap().0; + let ptx = wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, ptx).await.unwrap().0; // add it to wallet2 as well wallet2.add_standalone_multisig(DEFAULT_ACCOUNT_INDEX, challenge, None).unwrap(); // now we can sign it - let (ptx, _, statuses) = wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, ptx).unwrap(); + let (ptx, _, statuses) = + wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, ptx).await.unwrap(); // now it is fully signed assert!(ptx.all_signatures_available()); @@ -4933,7 +5054,8 @@ fn test_add_standalone_multisig(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_htlc_and_spend(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn create_htlc_and_spend(#[case] seed: Seed) { use common::chain::htlc::HtlcSecret; let mut rng = make_seedable_rng(seed); @@ -4993,6 +5115,7 @@ fn create_htlc_and_spend(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &BTreeMap::new(), ) + .await .unwrap(); let create_htlc_tx_id = create_htlc_tx.transaction().get_id(); let (_, block2) = create_block( @@ -5061,7 +5184,7 @@ fn create_htlc_and_spend(#[case] seed: Seed) { .unwrap(); let (spend_ptx, _, new_statuses) = - wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, spend_ptx).unwrap(); + wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, spend_ptx).await.unwrap(); assert_eq!(vec![SignatureStatus::FullySigned], new_statuses); let spend_tx = spend_ptx.into_signed_tx().unwrap(); @@ -5077,7 +5200,8 @@ fn create_htlc_and_spend(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_htlc_and_refund(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn create_htlc_and_refund(#[case] seed: Seed) { use common::chain::htlc::HtlcSecret; let mut rng = make_seedable_rng(seed); @@ -5139,6 +5263,7 @@ fn create_htlc_and_refund(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &BTreeMap::new(), ) + .await .unwrap(); let create_htlc_tx_id = create_htlc_tx.transaction().get_id(); @@ -5198,7 +5323,7 @@ fn create_htlc_and_refund(#[case] seed: Seed) { assert_eq!(wallet2_multisig_utxos.len(), 1); let (refund_ptx, prev_statuses, new_statuses) = - wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, refund_ptx).unwrap(); + wallet2.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, refund_ptx).await.unwrap(); assert_eq!(vec![SignatureStatus::NotSigned], prev_statuses); assert_eq!( @@ -5210,7 +5335,7 @@ fn create_htlc_and_refund(#[case] seed: Seed) { ); let (refund_ptx, prev_statuses, new_statuses) = - wallet1.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, refund_ptx).unwrap(); + wallet1.sign_raw_transaction(DEFAULT_ACCOUNT_INDEX, refund_ptx).await.unwrap(); assert_eq!( vec![SignatureStatus::PartialMultisig { required_signatures: 2, @@ -5239,7 +5364,8 @@ fn create_htlc_and_refund(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_order(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn create_order(#[case] seed: Seed) { let mut rng = make_seedable_rng(seed); let chain_config = Arc::new(create_unit_test_config()); @@ -5270,6 +5396,7 @@ fn create_order(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -5309,6 +5436,7 @@ fn create_order(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let _ = create_block( @@ -5347,6 +5475,7 @@ fn create_order(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let _ = create_block( @@ -5365,7 +5494,8 @@ fn create_order(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_order_and_conclude(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -5396,6 +5526,7 @@ fn create_order_and_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -5435,6 +5566,7 @@ fn create_order_and_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let _ = create_block( @@ -5473,6 +5605,7 @@ fn create_order_and_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let order_info = RpcOrderInfo { conclude_key: address2.clone().into_object(), @@ -5517,6 +5650,7 @@ fn create_order_and_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let _ = create_block( @@ -5538,7 +5672,8 @@ fn create_order_and_conclude(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_order_fill_completely_conclude(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -5571,6 +5706,7 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -5613,6 +5749,7 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let (_, block3) = create_block( @@ -5662,6 +5799,7 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let order_info = RpcOrderInfo { conclude_key: address1.clone().into_object(), @@ -5723,6 +5861,7 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let (_, block5) = create_block( @@ -5787,6 +5926,7 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let (_, block6) = create_block( @@ -5843,6 +5983,7 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let (_, block7) = create_block( @@ -5875,7 +6016,8 @@ fn create_order_fill_completely_conclude(#[case] seed: Seed) { #[rstest] #[trace] #[case(Seed::from_entropy())] -fn create_order_fill_partially_conclude(#[case] seed: Seed) { +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +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()); @@ -5908,6 +6050,7 @@ fn create_order_fill_partially_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let block2_amount = chain_config.token_supply_change_fee(BlockHeight::zero()); @@ -5950,6 +6093,7 @@ fn create_order_fill_partially_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), FeeRate::from_amount_per_kb(Amount::ZERO), ) + .await .unwrap(); let (_, block3) = create_block( @@ -5999,6 +6143,7 @@ fn create_order_fill_partially_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let order_info = RpcOrderInfo { conclude_key: address1.clone().into_object(), @@ -6060,6 +6205,7 @@ fn create_order_fill_partially_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let (_, block5) = create_block( @@ -6123,6 +6269,7 @@ fn create_order_fill_partially_conclude(#[case] seed: Seed) { FeeRate::from_amount_per_kb(Amount::ZERO), &additional_info, ) + .await .unwrap(); let (_, block6) = create_block( diff --git a/wallet/storage/src/internal/mod.rs b/wallet/storage/src/internal/mod.rs index 8b6948827..67387ee14 100644 --- a/wallet/storage/src/internal/mod.rs +++ b/wallet/storage/src/internal/mod.rs @@ -24,7 +24,9 @@ mod password; use password::{challenge_to_sym_key, password_to_sym_key}; mod store_tx; -pub use store_tx::{StoreTxRo, StoreTxRoUnlocked, StoreTxRw, StoreTxRwUnlocked}; +pub use store_tx::{ + StoreLocalReadWriteUnlocked, StoreTxRo, StoreTxRoUnlocked, StoreTxRw, StoreTxRwUnlocked, +}; use self::store_tx::EncryptionState; @@ -151,6 +153,10 @@ impl Store { pub fn dump_raw(&self) -> crate::Result> { self.storage.transaction_ro()?.dump_raw().map_err(crate::Error::from) } + + pub fn local_rw_unlocked(&self) -> StoreLocalReadWriteUnlocked { + StoreLocalReadWriteUnlocked::new(self.clone()) + } } impl Clone for Store diff --git a/wallet/storage/src/internal/store_tx.rs b/wallet/storage/src/internal/store_tx.rs index fa2828290..da61f4e15 100644 --- a/wallet/storage/src/internal/store_tx.rs +++ b/wallet/storage/src/internal/store_tx.rs @@ -17,8 +17,9 @@ use std::collections::BTreeMap; use crate::{ schema::{self as db, Schema}, - WalletStorageEncryptionRead, WalletStorageEncryptionWrite, WalletStorageReadLocked, - WalletStorageReadUnlocked, WalletStorageWriteLocked, WalletStorageWriteUnlocked, + Transactional, WalletStorageEncryptionRead, WalletStorageEncryptionWrite, + WalletStorageReadLocked, WalletStorageReadUnlocked, WalletStorageWriteLocked, + WalletStorageWriteUnlocked, }; use common::{ address::Address, @@ -30,7 +31,7 @@ use crypto::{ symkey::SymmetricKey, }; use serialization::{Codec, DecodeAll, Encode, EncodeLike}; -use storage::{schema, MakeMapRef}; +use storage::{schema, Backend, MakeMapRef}; use utils::{ ensure, maybe_encrypted::{MaybeEncrypted, MaybeEncryptedError}, @@ -47,6 +48,8 @@ use wallet_types::{ AccountDerivationPathId, AccountId, AccountInfo, AccountKeyPurposeId, AccountWalletCreatedTxId, AccountWalletTxId, KeychainUsageState, WalletTx, }; + +use super::Store; mod well_known { use common::chain::block::timestamp::BlockTimestamp; use crypto::kdf::KdfChallenge; @@ -153,6 +156,565 @@ impl<'st, B: storage::Backend> StoreTxRwUnlocked<'st, B> { } } +type TxOperation = dyn FnOnce(&mut StoreTxRw<'_, B>) -> crate::Result<()> + 'static + Send; + +/// A local read/write object, stores each write operation and performs them only at the end +/// Avoids references to avoid lifetime issues in async functions +pub struct StoreLocalReadWriteUnlocked { + operations: Vec>>, + local_read: Store, +} + +/// A wrapper around the store itself that opens a new read only transaction on each read operation +/// Can be used in async contexts +pub struct StoreLocalReadOnlyUnlocked { + local_read: Store, +} + +impl StoreLocalReadWriteUnlocked { + pub fn new(local_read: Store) -> Self { + Self { + operations: vec![], + local_read, + } + } + + pub fn add_operation(&mut self, op: Box>) { + self.operations.push(op); + } + + /// perform the local operations + pub fn perform_operations(self, dbtx: &mut StoreTxRw<'_, B>) -> crate::Result<()> { + for op in self.operations { + op(dbtx)?; + } + + Ok(()) + } + + pub fn read_only_store(&self) -> StoreLocalReadOnlyUnlocked { + StoreLocalReadOnlyUnlocked { + local_read: self.local_read.clone(), + } + } + + pub fn transaction_ro_unlocked(&self) -> crate::Result> { + self.local_read.transaction_ro_unlocked() + } +} + +impl WalletStorageReadLocked for StoreLocalReadWriteUnlocked { + fn get_storage_version(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_storage_version() + } + + fn get_wallet_type(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_wallet_type() + } + + fn get_chain_info(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_chain_info() + } + + fn get_transaction(&self, id: &AccountWalletTxId) -> crate::Result> { + self.local_read.transaction_ro()?.get_transaction(id) + } + + fn get_accounts_info(&self) -> crate::Result> { + self.local_read.transaction_ro()?.get_accounts_info() + } + + fn get_address(&self, id: &AccountDerivationPathId) -> crate::Result> { + self.local_read.transaction_ro()?.get_address(id) + } + + fn get_addresses( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_addresses(account_id) + } + + fn check_root_keys_sanity(&self) -> crate::Result<()> { + self.local_read.transaction_ro()?.check_root_keys_sanity() + } + + /// Collect and return all transactions from the storage + fn get_transactions( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_transactions(account_id) + } + + /// Collect and return all signed transactions from the storage + fn get_user_transactions(&self) -> crate::Result> { + self.local_read.transaction_ro()?.get_user_transactions() + } + + fn get_account_unconfirmed_tx_counter( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_account_unconfirmed_tx_counter(account_id) + } + + fn get_account_vrf_public_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_account_vrf_public_keys(account_id) + } + + fn get_account_standalone_watch_only_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read + .transaction_ro()? + .get_account_standalone_watch_only_keys(account_id) + } + fn get_account_standalone_multisig_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read + .transaction_ro()? + .get_account_standalone_multisig_keys(account_id) + } + + fn get_account_standalone_private_keys( + &self, + account_id: &AccountId, + ) -> crate::Result)>> { + self.local_read + .transaction_ro()? + .get_account_standalone_private_keys(account_id) + } + + fn get_keychain_usage_state( + &self, + id: &AccountKeyPurposeId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_keychain_usage_state(id) + } + + fn get_vrf_keychain_usage_state( + &self, + id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_vrf_keychain_usage_state(id) + } + + fn get_keychain_usage_states( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_keychain_usage_states(account_id) + } + + fn get_public_key( + &self, + id: &AccountDerivationPathId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_public_key(id) + } + + fn get_public_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_public_keys(account_id) + } + + fn get_median_time(&self) -> crate::Result> { + self.local_read.transaction_ro()?.get_median_time() + } + + fn get_lookahead_size(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_lookahead_size() + } +} + +impl WalletStorageReadUnlocked for StoreLocalReadWriteUnlocked { + fn get_root_key(&self) -> crate::Result> { + self.local_read.transaction_ro_unlocked()?.get_root_key() + } + fn get_seed_phrase(&self) -> crate::Result> { + self.local_read.transaction_ro_unlocked()?.get_seed_phrase() + } + + fn get_account_standalone_private_key( + &self, + account_pubkey: &AccountPublicKey, + ) -> crate::Result> { + self.local_read + .transaction_ro_unlocked()? + .get_account_standalone_private_key(account_pubkey) + } +} + +impl WalletStorageReadLocked for StoreLocalReadOnlyUnlocked { + fn get_storage_version(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_storage_version() + } + + fn get_wallet_type(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_wallet_type() + } + + fn get_chain_info(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_chain_info() + } + + fn get_transaction(&self, id: &AccountWalletTxId) -> crate::Result> { + self.local_read.transaction_ro()?.get_transaction(id) + } + + fn get_accounts_info(&self) -> crate::Result> { + self.local_read.transaction_ro()?.get_accounts_info() + } + + fn get_address(&self, id: &AccountDerivationPathId) -> crate::Result> { + self.local_read.transaction_ro()?.get_address(id) + } + + fn get_addresses( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_addresses(account_id) + } + + fn check_root_keys_sanity(&self) -> crate::Result<()> { + self.local_read.transaction_ro()?.check_root_keys_sanity() + } + + /// Collect and return all transactions from the storage + fn get_transactions( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_transactions(account_id) + } + + /// Collect and return all signed transactions from the storage + fn get_user_transactions(&self) -> crate::Result> { + self.local_read.transaction_ro()?.get_user_transactions() + } + + fn get_account_unconfirmed_tx_counter( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_account_unconfirmed_tx_counter(account_id) + } + + fn get_account_vrf_public_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_account_vrf_public_keys(account_id) + } + + fn get_account_standalone_watch_only_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read + .transaction_ro()? + .get_account_standalone_watch_only_keys(account_id) + } + fn get_account_standalone_multisig_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read + .transaction_ro()? + .get_account_standalone_multisig_keys(account_id) + } + + fn get_account_standalone_private_keys( + &self, + account_id: &AccountId, + ) -> crate::Result)>> { + self.local_read + .transaction_ro()? + .get_account_standalone_private_keys(account_id) + } + + fn get_keychain_usage_state( + &self, + id: &AccountKeyPurposeId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_keychain_usage_state(id) + } + + fn get_vrf_keychain_usage_state( + &self, + id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_vrf_keychain_usage_state(id) + } + + fn get_keychain_usage_states( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_keychain_usage_states(account_id) + } + + fn get_public_key( + &self, + id: &AccountDerivationPathId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_public_key(id) + } + + fn get_public_keys( + &self, + account_id: &AccountId, + ) -> crate::Result> { + self.local_read.transaction_ro()?.get_public_keys(account_id) + } + + fn get_median_time(&self) -> crate::Result> { + self.local_read.transaction_ro()?.get_median_time() + } + + fn get_lookahead_size(&self) -> crate::Result { + self.local_read.transaction_ro()?.get_lookahead_size() + } +} + +impl WalletStorageReadUnlocked for StoreLocalReadOnlyUnlocked { + fn get_root_key(&self) -> crate::Result> { + self.local_read.transaction_ro_unlocked()?.get_root_key() + } + fn get_seed_phrase(&self) -> crate::Result> { + self.local_read.transaction_ro_unlocked()?.get_seed_phrase() + } + + fn get_account_standalone_private_key( + &self, + account_pubkey: &AccountPublicKey, + ) -> crate::Result> { + self.local_read + .transaction_ro_unlocked()? + .get_account_standalone_private_key(account_pubkey) + } +} + +impl WalletStorageWriteLocked for StoreLocalReadWriteUnlocked { + fn set_storage_version(&mut self, version: u32) -> crate::Result<()> { + self.add_operation(Box::new(move |dbtx| dbtx.set_storage_version(version))); + Ok(()) + } + + fn set_wallet_type(&mut self, wallet_type: WalletType) -> crate::Result<()> { + self.add_operation(Box::new(move |dbtx| dbtx.set_wallet_type(wallet_type))); + Ok(()) + } + + fn set_chain_info(&mut self, chain_info: &ChainInfo) -> crate::Result<()> { + let chain_info = chain_info.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.set_chain_info(&chain_info))); + Ok(()) + } + + fn set_transaction(&mut self, id: &AccountWalletTxId, tx: &WalletTx) -> crate::Result<()> { + let id = id.clone(); + let tx = tx.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.set_transaction(&id, &tx))); + Ok(()) + } + + fn del_transaction(&mut self, id: &AccountWalletTxId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_transaction(&id))); + Ok(()) + } + + fn clear_transactions(&mut self) -> crate::Result<()> { + self.add_operation(Box::new(|dbtx| dbtx.clear_transactions())); + Ok(()) + } + + fn clear_public_keys(&mut self) -> crate::Result<()> { + self.add_operation(Box::new(|dbtx| dbtx.clear_public_keys())); + Ok(()) + } + + fn clear_addresses(&mut self) -> crate::Result<()> { + self.add_operation(Box::new(|dbtx| dbtx.clear_addresses())); + Ok(()) + } + + fn set_account_unconfirmed_tx_counter( + &mut self, + id: &AccountId, + counter: u64, + ) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| { + dbtx.set_account_unconfirmed_tx_counter(&id, counter) + })); + Ok(()) + } + + fn set_account_vrf_public_keys( + &mut self, + id: &AccountId, + account_vrf_keys: &AccountVrfKeys, + ) -> crate::Result<()> { + let id = id.clone(); + let account_vrf_keys = account_vrf_keys.clone(); + self.add_operation(Box::new(move |dbtx| { + dbtx.set_account_vrf_public_keys(&id, &account_vrf_keys) + })); + Ok(()) + } + + fn set_user_transaction( + &mut self, + id: &AccountWalletCreatedTxId, + tx: &SignedTransaction, + ) -> crate::Result<()> { + let id = id.clone(); + let tx = tx.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.set_user_transaction(&id, &tx))); + Ok(()) + } + + fn del_user_transaction(&mut self, id: &AccountWalletCreatedTxId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_user_transaction(&id))); + Ok(()) + } + + fn set_standalone_watch_only_key( + &mut self, + id: &AccountAddress, + key: &StandaloneWatchOnlyKey, + ) -> crate::Result<()> { + let id = id.clone(); + let key = key.clone(); + self.add_operation(Box::new(move |dbtx| { + dbtx.set_standalone_watch_only_key(&id, &key) + })); + Ok(()) + } + fn set_standalone_multisig_key( + &mut self, + id: &AccountAddress, + key: &StandaloneMultisig, + ) -> crate::Result<()> { + let id = id.clone(); + let key = key.clone(); + self.add_operation(Box::new(move |dbtx| { + dbtx.set_standalone_multisig_key(&id, &key) + })); + Ok(()) + } + + fn set_account(&mut self, id: &AccountId, tx: &AccountInfo) -> crate::Result<()> { + let id = id.clone(); + let tx = tx.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.set_account(&id, &tx))); + Ok(()) + } + + fn del_account(&mut self, id: &AccountId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_account(&id))); + Ok(()) + } + + fn set_address( + &mut self, + id: &AccountDerivationPathId, + address: &Address, + ) -> crate::Result<()> { + let id = id.clone(); + let address = address.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.set_address(&id, &address))); + Ok(()) + } + + fn del_address(&mut self, id: &AccountDerivationPathId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_address(&id))); + Ok(()) + } + + fn set_keychain_usage_state( + &mut self, + id: &AccountKeyPurposeId, + usage_state: &KeychainUsageState, + ) -> crate::Result<()> { + let id = id.clone(); + let usage_state = usage_state.clone(); + self.add_operation(Box::new(move |dbtx| { + dbtx.set_keychain_usage_state(&id, &usage_state) + })); + Ok(()) + } + + fn set_vrf_keychain_usage_state( + &mut self, + id: &AccountId, + usage_state: &KeychainUsageState, + ) -> crate::Result<()> { + let id = id.clone(); + let usage_state = usage_state.clone(); + self.add_operation(Box::new(move |dbtx| { + dbtx.set_vrf_keychain_usage_state(&id, &usage_state) + })); + Ok(()) + } + + fn del_keychain_usage_state(&mut self, id: &AccountKeyPurposeId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_keychain_usage_state(&id))); + Ok(()) + } + + fn del_vrf_keychain_usage_state(&mut self, id: &AccountId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_vrf_keychain_usage_state(&id))); + Ok(()) + } + + fn set_public_key( + &mut self, + id: &AccountDerivationPathId, + pub_key: &ExtendedPublicKey, + ) -> crate::Result<()> { + let id = id.clone(); + let pub_key = pub_key.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.set_public_key(&id, &pub_key))); + Ok(()) + } + + fn del_public_key(&mut self, id: &AccountDerivationPathId) -> crate::Result<()> { + let id = id.clone(); + self.add_operation(Box::new(move |dbtx| dbtx.del_public_key(&id))); + Ok(()) + } + + fn set_median_time(&mut self, median_time: BlockTimestamp) -> crate::Result<()> { + self.add_operation(Box::new(move |dbtx| dbtx.set_median_time(median_time))); + Ok(()) + } + + fn set_lookahead_size(&mut self, lookahead_size: u32) -> crate::Result<()> { + self.add_operation(Box::new(move |dbtx| { + dbtx.set_lookahead_size(lookahead_size) + })); + Ok(()) + } +} + macro_rules! impl_read_ops { ($TxType:ident) => { /// Wallet data storage transaction @@ -589,7 +1151,7 @@ macro_rules! impl_write_ops { self.write::(id, pub_key) } - fn det_public_key(&mut self, id: &AccountDerivationPathId) -> crate::Result<()> { + fn del_public_key(&mut self, id: &AccountDerivationPathId) -> crate::Result<()> { self.storage.get_mut::().del(id).map_err(Into::into) } @@ -760,3 +1322,4 @@ impl<'st, B: storage::Backend> crate::IsTransaction for StoreTxRo<'st, B> {} impl<'st, B: storage::Backend> crate::IsTransaction for StoreTxRw<'st, B> {} impl<'st, B: storage::Backend> crate::IsTransaction for StoreTxRoUnlocked<'st, B> {} impl<'st, B: storage::Backend> crate::IsTransaction for StoreTxRwUnlocked<'st, B> {} +impl crate::IsTransaction for StoreLocalReadWriteUnlocked {} diff --git a/wallet/storage/src/is_transaction_seal.rs b/wallet/storage/src/is_transaction_seal.rs index f2f03135b..d037a2d6e 100644 --- a/wallet/storage/src/is_transaction_seal.rs +++ b/wallet/storage/src/is_transaction_seal.rs @@ -20,3 +20,4 @@ impl<'st, B: storage::Backend> Seal for crate::internal::StoreTxRo<'st, B> {} impl<'st, B: storage::Backend> Seal for crate::internal::StoreTxRw<'st, B> {} impl<'st, B: storage::Backend> Seal for crate::internal::StoreTxRoUnlocked<'st, B> {} impl<'st, B: storage::Backend> Seal for crate::internal::StoreTxRwUnlocked<'st, B> {} +impl Seal for crate::internal::StoreLocalReadWriteUnlocked {} diff --git a/wallet/storage/src/lib.rs b/wallet/storage/src/lib.rs index eb1797aec..caf1b1434 100644 --- a/wallet/storage/src/lib.rs +++ b/wallet/storage/src/lib.rs @@ -28,7 +28,9 @@ use crypto::{ key::{extended::ExtendedPublicKey, PrivateKey}, symkey::SymmetricKey, }; -pub use internal::{Store, StoreTxRo, StoreTxRoUnlocked, StoreTxRw, StoreTxRwUnlocked}; +pub use internal::{ + Store, StoreLocalReadWriteUnlocked, StoreTxRo, StoreTxRoUnlocked, StoreTxRw, StoreTxRwUnlocked, +}; use std::collections::BTreeMap; use wallet_types::{ @@ -192,7 +194,7 @@ pub trait WalletStorageWriteLocked { id: &AccountDerivationPathId, content: &ExtendedPublicKey, ) -> Result<()>; - fn det_public_key(&mut self, id: &AccountDerivationPathId) -> Result<()>; + fn del_public_key(&mut self, id: &AccountDerivationPathId) -> Result<()>; fn set_median_time(&mut self, median_time: BlockTimestamp) -> Result<()>; fn set_lookahead_size(&mut self, lookahead_size: u32) -> Result<()>; fn clear_public_keys(&mut self) -> Result<()>; diff --git a/wallet/wallet-controller/src/runtime_wallet.rs b/wallet/wallet-controller/src/runtime_wallet.rs index f883de2de..83fa2dffd 100644 --- a/wallet/wallet-controller/src/runtime_wallet.rs +++ b/wallet/wallet-controller/src/runtime_wallet.rs @@ -538,7 +538,7 @@ impl RuntimeWallet { } } - pub fn issue_new_token( + pub async fn issue_new_token( &mut self, account_index: U31, token_issuance: TokenIssuance, @@ -546,23 +546,29 @@ impl RuntimeWallet { consolidate_fee_rate: FeeRate, ) -> WalletResult<(TokenId, SignedTransaction)> { match self { - RuntimeWallet::Software(w) => w.issue_new_token( - account_index, - token_issuance, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.issue_new_token( + account_index, + token_issuance, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.issue_new_token( - account_index, - token_issuance, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.issue_new_token( + account_index, + token_issuance, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn issue_new_nft( + pub async fn issue_new_nft( &mut self, account_index: U31, address: Address, @@ -571,212 +577,260 @@ impl RuntimeWallet { consolidate_fee_rate: FeeRate, ) -> WalletResult<(TokenId, SignedTransaction)> { match self { - RuntimeWallet::Software(w) => w.issue_new_nft( - account_index, - address, - metadata, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.issue_new_nft( + account_index, + address, + metadata, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.issue_new_nft( - account_index, - address, - metadata, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.issue_new_nft( + account_index, + address, + metadata, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn mint_tokens( + pub async fn mint_tokens( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, amount: Amount, address: Address, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.mint_tokens( - account_index, - token_info, - amount, - address, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.mint_tokens( + account_index, + &token_info, + amount, + address, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.mint_tokens( - account_index, - token_info, - amount, - address, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.mint_tokens( + account_index, + &token_info, + amount, + address, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn unmint_tokens( + pub async fn unmint_tokens( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, amount: Amount, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.unmint_tokens( - account_index, - token_info, - amount, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.unmint_tokens( + account_index, + &token_info, + amount, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.unmint_tokens( - account_index, - token_info, - amount, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.unmint_tokens( + account_index, + &token_info, + amount, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn lock_token_supply( + pub async fn lock_token_supply( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.lock_token_supply( - account_index, - token_info, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.lock_token_supply( + account_index, + &token_info, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.lock_token_supply( - account_index, - token_info, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.lock_token_supply( + account_index, + &token_info, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn freeze_token( + pub async fn freeze_token( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, is_token_unfreezable: IsTokenUnfreezable, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.freeze_token( - account_index, - token_info, - is_token_unfreezable, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.freeze_token( + account_index, + &token_info, + is_token_unfreezable, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.freeze_token( - account_index, - token_info, - is_token_unfreezable, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.freeze_token( + account_index, + &token_info, + is_token_unfreezable, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn unfreeze_token( + pub async fn unfreeze_token( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.unfreeze_token( - account_index, - token_info, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.unfreeze_token( + account_index, + &token_info, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.unfreeze_token( - account_index, - token_info, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.unfreeze_token( + account_index, + &token_info, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn change_token_authority( + pub async fn change_token_authority( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, address: Address, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.change_token_authority( - account_index, - token_info, - address, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.change_token_authority( + account_index, + &token_info, + address, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.change_token_authority( - account_index, - token_info, - address, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.change_token_authority( + account_index, + &token_info, + address, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn change_token_metadata_uri( + pub async fn change_token_metadata_uri( &mut self, account_index: U31, - token_info: &UnconfirmedTokenInfo, + token_info: UnconfirmedTokenInfo, metadata_uri: Vec, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, ) -> Result { match self { - RuntimeWallet::Software(w) => w.change_token_metadata_uri( - account_index, - token_info, - metadata_uri, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.change_token_metadata_uri( + account_index, + &token_info, + metadata_uri, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.change_token_metadata_uri( - account_index, - token_info, - metadata_uri, - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.change_token_metadata_uri( + account_index, + &token_info, + metadata_uri, + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } #[allow(clippy::too_many_arguments)] - pub fn create_transaction_to_addresses( + pub async fn create_transaction_to_addresses( &mut self, account_index: U31, outputs: impl IntoIterator, @@ -784,32 +838,38 @@ impl RuntimeWallet { change_addresses: BTreeMap>, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, - additional_utxo_infos: &BTreeMap, + additional_utxo_infos: BTreeMap, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_transaction_to_addresses( - account_index, - outputs, - inputs, - change_addresses, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_transaction_to_addresses( + account_index, + outputs, + inputs, + change_addresses, + current_fee_rate, + consolidate_fee_rate, + additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_transaction_to_addresses( - account_index, - outputs, - inputs, - change_addresses, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_transaction_to_addresses( + account_index, + outputs, + inputs, + change_addresses, + current_fee_rate, + consolidate_fee_rate, + additional_utxo_infos, + ) + .await + } } } - pub fn create_sweep_transaction( + pub async fn create_sweep_transaction( &mut self, account_index: U31, destination_address: Destination, @@ -818,21 +878,27 @@ impl RuntimeWallet { additional_utxo_infos: BTreeMap, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_sweep_transaction( - account_index, - destination_address, - filtered_inputs, - current_fee_rate, - &additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_sweep_transaction( + account_index, + destination_address, + filtered_inputs, + current_fee_rate, + &additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_sweep_transaction( - account_index, - destination_address, - filtered_inputs, - current_fee_rate, - &additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_sweep_transaction( + account_index, + destination_address, + filtered_inputs, + current_fee_rate, + &additional_utxo_infos, + ) + .await + } } } @@ -848,7 +914,7 @@ impl RuntimeWallet { } } - pub fn create_sweep_from_delegation_transaction( + pub async fn create_sweep_from_delegation_transaction( &mut self, account_index: U31, destination_address: Address, @@ -857,21 +923,27 @@ impl RuntimeWallet { current_fee_rate: FeeRate, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_sweep_from_delegation_transaction( - account_index, - destination_address, - delegation_id, - delegation_share, - current_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.create_sweep_from_delegation_transaction( + account_index, + destination_address, + delegation_id, + delegation_share, + current_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_sweep_from_delegation_transaction( - account_index, - destination_address, - delegation_id, - delegation_share, - current_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.create_sweep_from_delegation_transaction( + account_index, + destination_address, + delegation_id, + delegation_share, + current_fee_rate, + ) + .await + } } } @@ -912,7 +984,7 @@ impl RuntimeWallet { } } - pub fn create_delegation( + pub async fn create_delegation( &mut self, account_index: U31, output: TxOutput, @@ -920,23 +992,29 @@ impl RuntimeWallet { consolidate_fee_rate: FeeRate, ) -> WalletResult<(DelegationId, SignedTransaction)> { match self { - RuntimeWallet::Software(w) => w.create_delegation( - account_index, - vec![output], - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.create_delegation( + account_index, + vec![output], + current_fee_rate, + consolidate_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_delegation( - account_index, - vec![output], - current_fee_rate, - consolidate_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.create_delegation( + account_index, + vec![output], + current_fee_rate, + consolidate_fee_rate, + ) + .await + } } } - pub fn create_transaction_to_addresses_from_delegation( + pub async fn create_transaction_to_addresses_from_delegation( &mut self, account_index: U31, address: Address, @@ -946,27 +1024,33 @@ impl RuntimeWallet { current_fee_rate: FeeRate, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_transaction_to_addresses_from_delegation( - account_index, - address, - amount, - delegation_id, - delegation_share, - current_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.create_transaction_to_addresses_from_delegation( + account_index, + address, + amount, + delegation_id, + delegation_share, + current_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_transaction_to_addresses_from_delegation( - account_index, - address, - amount, - delegation_id, - delegation_share, - current_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.create_transaction_to_addresses_from_delegation( + account_index, + address, + amount, + delegation_id, + delegation_share, + current_fee_rate, + ) + .await + } } } - pub fn create_stake_pool_tx( + pub async fn create_stake_pool_tx( &mut self, account_index: U31, current_fee_rate: FeeRate, @@ -974,18 +1058,21 @@ impl RuntimeWallet { stake_pool_arguments: StakePoolDataArguments, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_stake_pool_tx( - account_index, - current_fee_rate, - consolidate_fee_rate, - stake_pool_arguments, - ), + RuntimeWallet::Software(w) => { + w.create_stake_pool_tx( + account_index, + current_fee_rate, + consolidate_fee_rate, + stake_pool_arguments, + ) + .await + } #[cfg(feature = "trezor")] RuntimeWallet::Trezor(_) => Err(WalletError::UnsupportedHardwareWalletOperation), } } - pub fn decommission_stake_pool( + pub async fn decommission_stake_pool( &mut self, account_index: U31, pool_id: PoolId, @@ -994,25 +1081,31 @@ impl RuntimeWallet { current_fee_rate: FeeRate, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.decommission_stake_pool( - account_index, - pool_id, - staker_balance, - output_address, - current_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.decommission_stake_pool( + account_index, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.decommission_stake_pool( - account_index, - pool_id, - staker_balance, - output_address, - current_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.decommission_stake_pool( + account_index, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .await + } } } - pub fn decommission_stake_pool_request( + pub async fn decommission_stake_pool_request( &mut self, account_index: U31, pool_id: PoolId, @@ -1021,25 +1114,31 @@ impl RuntimeWallet { current_fee_rate: FeeRate, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.decommission_stake_pool_request( - account_index, - pool_id, - staker_balance, - output_address, - current_fee_rate, - ), + RuntimeWallet::Software(w) => { + w.decommission_stake_pool_request( + account_index, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.decommission_stake_pool_request( - account_index, - pool_id, - staker_balance, - output_address, - current_fee_rate, - ), + RuntimeWallet::Trezor(w) => { + w.decommission_stake_pool_request( + account_index, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .await + } } } - pub fn create_htlc_tx( + pub async fn create_htlc_tx( &mut self, account_index: U31, output_value: OutputValue, @@ -1049,28 +1148,34 @@ impl RuntimeWallet { additional_utxo_infos: &BTreeMap, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_htlc_tx( - account_index, - output_value, - htlc, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_htlc_tx( + account_index, + output_value, + htlc, + current_fee_rate, + consolidate_fee_rate, + additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_htlc_tx( - account_index, - output_value, - htlc, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_htlc_tx( + account_index, + output_value, + htlc, + current_fee_rate, + consolidate_fee_rate, + additional_utxo_infos, + ) + .await + } } } #[allow(clippy::too_many_arguments)] - pub fn create_order_tx( + pub async fn create_order_tx( &mut self, account_index: U31, ask_value: OutputValue, @@ -1078,33 +1183,39 @@ impl RuntimeWallet { conclude_key: Address, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, - additional_utxo_infos: &BTreeMap, + additional_utxo_infos: BTreeMap, ) -> WalletResult<(OrderId, SignedTransaction)> { match self { - RuntimeWallet::Software(w) => w.create_order_tx( - account_index, - ask_value, - give_value, - conclude_key, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_order_tx( + account_index, + ask_value, + give_value, + conclude_key, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_order_tx( - account_index, - ask_value, - give_value, - conclude_key, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_order_tx( + account_index, + ask_value, + give_value, + conclude_key, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } } } #[allow(clippy::too_many_arguments)] - pub fn create_conclude_order_tx( + pub async fn create_conclude_order_tx( &mut self, account_index: U31, order_id: OrderId, @@ -1112,33 +1223,39 @@ impl RuntimeWallet { output_address: Option, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, - additional_utxo_infos: &BTreeMap, + additional_utxo_infos: BTreeMap, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_conclude_order_tx( - account_index, - order_id, - order_info, - output_address, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_conclude_order_tx( + account_index, + order_id, + order_info, + output_address, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_conclude_order_tx( - account_index, - order_id, - order_info, - output_address, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_conclude_order_tx( + account_index, + order_id, + order_info, + output_address, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } } } #[allow(clippy::too_many_arguments)] - pub fn create_fill_order_tx( + pub async fn create_fill_order_tx( &mut self, account_index: U31, order_id: OrderId, @@ -1147,34 +1264,40 @@ impl RuntimeWallet { output_address: Option, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, - additional_utxo_infos: &BTreeMap, + additional_utxo_infos: BTreeMap, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.create_fill_order_tx( - account_index, - order_id, - order_info, - fill_amount_in_ask_currency, - output_address, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_fill_order_tx( + account_index, + order_id, + order_info, + fill_amount_in_ask_currency, + output_address, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_fill_order_tx( - account_index, - order_id, - order_info, - fill_amount_in_ask_currency, - output_address, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_fill_order_tx( + account_index, + order_id, + order_info, + fill_amount_in_ask_currency, + output_address, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } } } - pub fn sign_raw_transaction( + pub async fn sign_raw_transaction( &mut self, account_index: U31, ptx: PartiallySignedTransaction, @@ -1184,27 +1307,31 @@ impl RuntimeWallet { Vec, )> { match self { - RuntimeWallet::Software(w) => w.sign_raw_transaction(account_index, ptx), + RuntimeWallet::Software(w) => w.sign_raw_transaction(account_index, ptx).await, #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.sign_raw_transaction(account_index, ptx), + RuntimeWallet::Trezor(w) => w.sign_raw_transaction(account_index, ptx).await, } } - pub fn sign_challenge( + pub async fn sign_challenge( &mut self, account_index: U31, challenge: &[u8], destination: &Destination, ) -> WalletResult { match self { - RuntimeWallet::Software(w) => w.sign_challenge(account_index, challenge, destination), + RuntimeWallet::Software(w) => { + w.sign_challenge(account_index, challenge, destination).await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.sign_challenge(account_index, challenge, destination), + RuntimeWallet::Trezor(w) => { + w.sign_challenge(account_index, challenge, destination).await + } } } #[allow(clippy::too_many_arguments)] - pub fn create_transaction_to_addresses_with_intent( + pub async fn create_transaction_to_addresses_with_intent( &mut self, account_index: U31, outputs: impl IntoIterator, @@ -1213,30 +1340,36 @@ impl RuntimeWallet { intent: String, current_fee_rate: FeeRate, consolidate_fee_rate: FeeRate, - additional_utxo_infos: &BTreeMap, + additional_utxo_infos: BTreeMap, ) -> WalletResult<(SignedTransaction, SignedTransactionIntent)> { match self { - RuntimeWallet::Software(w) => w.create_transaction_to_addresses_with_intent( - account_index, - outputs, - inputs, - change_addresses, - intent, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Software(w) => { + w.create_transaction_to_addresses_with_intent( + account_index, + outputs, + inputs, + change_addresses, + intent, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } #[cfg(feature = "trezor")] - RuntimeWallet::Trezor(w) => w.create_transaction_to_addresses_with_intent( - account_index, - outputs, - inputs, - change_addresses, - intent, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - ), + RuntimeWallet::Trezor(w) => { + w.create_transaction_to_addresses_with_intent( + account_index, + outputs, + inputs, + change_addresses, + intent, + current_fee_rate, + consolidate_fee_rate, + &additional_utxo_infos, + ) + .await + } } } diff --git a/wallet/wallet-controller/src/synced_controller.rs b/wallet/wallet-controller/src/synced_controller.rs index bf4ab36c9..5ea0eef34 100644 --- a/wallet/wallet-controller/src/synced_controller.rs +++ b/wallet/wallet-controller/src/synced_controller.rs @@ -39,7 +39,11 @@ use crypto::{ }, vrf::VRFPublicKey, }; -use futures::{stream::FuturesUnordered, TryStreamExt}; +use futures::{ + future::{self, BoxFuture}, + stream::FuturesUnordered, + FutureExt, TryStreamExt, +}; use itertools::Itertools; use logging::log; use mempool::FeeRate; @@ -299,19 +303,21 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.issue_new_token( - account_index, - TokenIssuance::V1(TokenIssuanceV1 { - token_ticker, - number_of_decimals, - metadata_uri, - total_supply: token_total_supply, - authority: address.into_object(), - is_freezable, - }), - current_fee_rate, - consolidate_fee_rate, - ) + wallet + .issue_new_token( + account_index, + TokenIssuance::V1(TokenIssuanceV1 { + token_ticker, + number_of_decimals, + metadata_uri, + total_supply: token_total_supply, + authority: address.into_object(), + is_freezable, + }), + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -327,13 +333,15 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.issue_new_nft( - account_index, - address, - metadata, - current_fee_rate, - consolidate_fee_rate, - ) + wallet + .issue_new_nft( + account_index, + address, + metadata, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -351,16 +359,20 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - token_info.check_can_be_used()?; - wallet.mint_tokens( - account_index, - token_info, - amount, - address, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + if let Err(err) = token_info.check_can_be_used() { + return future::err(err).boxed(); + }; + wallet + .mint_tokens( + account_index, + token_info, + amount, + address, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -376,15 +388,19 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - token_info.check_can_be_used()?; - wallet.unmint_tokens( - account_index, - token_info, - amount, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + if let Err(err) = token_info.check_can_be_used() { + return future::err(err).boxed(); + }; + wallet + .unmint_tokens( + account_index, + token_info, + amount, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -400,14 +416,18 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - token_info.check_can_be_used()?; - wallet.lock_token_supply( - account_index, - token_info, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + if let Err(err) = token_info.check_can_be_used() { + return future::err(err).boxed(); + }; + wallet + .lock_token_supply( + account_index, + token_info, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -426,14 +446,16 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - wallet.freeze_token( - account_index, - token_info, - is_token_unfreezable, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + wallet + .freeze_token( + account_index, + token_info, + is_token_unfreezable, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -450,13 +472,15 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - wallet.unfreeze_token( - account_index, - token_info, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + wallet + .unfreeze_token( + account_index, + token_info, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -475,14 +499,19 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - wallet.change_token_authority( - account_index, - token_info, - address, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + if let Err(err) = token_info.check_can_be_used() { + return future::err(err).boxed(); + }; + wallet + .change_token_authority( + account_index, + token_info, + address, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -499,14 +528,16 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - wallet.change_token_metadata_uri( - account_index, - token_info, - metadata_uri, - current_fee_rate, - consolidate_fee_rate, - ) + token_info: UnconfirmedTokenInfo| { + wallet + .change_token_metadata_uri( + account_index, + token_info, + metadata_uri, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -524,15 +555,17 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_transaction_to_addresses( - account_index, - outputs, - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - current_fee_rate, - consolidate_fee_rate, - &BTreeMap::new(), - ) + wallet + .create_transaction_to_addresses( + account_index, + outputs, + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + current_fee_rate, + consolidate_fee_rate, + BTreeMap::new(), + ) + .boxed() }, ) .await @@ -556,15 +589,17 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_transaction_to_addresses( - account_index, - [output], - SelectedInputs::Utxos(selected_utxos), - BTreeMap::new(), - current_fee_rate, - consolidate_fee_rate, - &BTreeMap::new(), - ) + wallet + .create_transaction_to_addresses( + account_index, + [output], + SelectedInputs::Utxos(selected_utxos), + BTreeMap::new(), + current_fee_rate, + consolidate_fee_rate, + BTreeMap::new(), + ) + .boxed() }, ) .await @@ -600,13 +635,15 @@ where _consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_sweep_transaction( - account_index, - destination_address, - filtered_inputs, - current_fee_rate, - additional_utxo_infos, - ) + wallet + .create_sweep_transaction( + account_index, + destination_address, + filtered_inputs, + current_fee_rate, + additional_utxo_infos, + ) + .boxed() }, ) .await @@ -639,13 +676,15 @@ where _consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_sweep_from_delegation_transaction( - account_index, - destination_address, - delegation_id, - delegation_share, - current_fee_rate, - ) + wallet + .create_sweep_from_delegation_transaction( + account_index, + destination_address, + delegation_id, + delegation_share, + current_fee_rate, + ) + .boxed() }, ) .await @@ -868,12 +907,14 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_delegation( - account_index, - output, - current_fee_rate, - consolidate_fee_rate, - ) + wallet + .create_delegation( + account_index, + output, + current_fee_rate, + consolidate_fee_rate, + ) + .boxed() }, ) .await @@ -892,15 +933,17 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_transaction_to_addresses( - account_index, - [output], - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - current_fee_rate, - consolidate_fee_rate, - &BTreeMap::new(), - ) + wallet + .create_transaction_to_addresses( + account_index, + [output], + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + current_fee_rate, + consolidate_fee_rate, + BTreeMap::new(), + ) + .boxed() }, ) .await @@ -930,14 +973,16 @@ where _consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_transaction_to_addresses_from_delegation( - account_index, - address, - amount, - delegation_id, - delegation_share, - current_fee_rate, - ) + wallet + .create_transaction_to_addresses_from_delegation( + account_index, + address, + amount, + delegation_id, + delegation_share, + current_fee_rate, + ) + .boxed() }, ) .await @@ -958,8 +1003,10 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - token_info.check_can_be_used()?; + token_info: UnconfirmedTokenInfo| { + if let Err(err) = token_info.check_can_be_used() { + return future::err(err).boxed(); + }; let additional_info = BTreeMap::from_iter([( PoolOrTokenId::TokenId(token_info.token_id()), UtxoAdditionalInfo::TokenInfo(TokenAdditionalInfo { @@ -967,15 +1014,17 @@ where ticker: token_info.token_ticker().to_vec(), }), )]); - wallet.create_transaction_to_addresses( - account_index, - [output], - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - current_fee_rate, - consolidate_fee_rate, - &additional_info, - ) + wallet + .create_transaction_to_addresses( + account_index, + [output], + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + current_fee_rate, + consolidate_fee_rate, + additional_info, + ) + .boxed() }, ) .await @@ -996,8 +1045,10 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31, - token_info: &UnconfirmedTokenInfo| { - token_info.check_can_be_used()?; + token_info: UnconfirmedTokenInfo| { + if let Err(err) = token_info.check_can_be_used() { + return future::err(err).boxed(); + }; let additional_info = BTreeMap::from_iter([( PoolOrTokenId::TokenId(token_info.token_id()), UtxoAdditionalInfo::TokenInfo(TokenAdditionalInfo { @@ -1005,16 +1056,18 @@ where ticker: token_info.token_ticker().to_vec(), }), )]); - wallet.create_transaction_to_addresses_with_intent( - account_index, - [output], - SelectedInputs::Utxos(vec![]), - BTreeMap::new(), - intent, - current_fee_rate, - consolidate_fee_rate, - &additional_info, - ) + wallet + .create_transaction_to_addresses_with_intent( + account_index, + [output], + SelectedInputs::Utxos(vec![]), + BTreeMap::new(), + intent, + current_fee_rate, + consolidate_fee_rate, + additional_info, + ) + .boxed() }, ) .await @@ -1033,17 +1086,52 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_stake_pool_tx( - account_index, - current_fee_rate, - consolidate_fee_rate, - StakePoolDataArguments { - amount, - margin_ratio_per_thousand, - cost_per_block, - decommission_key, - }, - ) + wallet + .create_stake_pool_tx( + account_index, + current_fee_rate, + consolidate_fee_rate, + StakePoolDataArguments { + amount, + margin_ratio_per_thousand, + cost_per_block, + decommission_key, + }, + ) + .boxed() + }, + ) + .await + } + + pub async fn async_decommission_stake_pool( + &mut self, + pool_id: PoolId, + output_address: Option, + ) -> Result> { + let staker_balance = self + .rpc_client + .get_staker_balance(pool_id) + .await + .map_err(ControllerError::NodeCallError)? + .ok_or(ControllerError::WalletError(WalletError::UnknownPoolId( + pool_id, + )))?; + + self.create_and_send_tx( + move |current_fee_rate: FeeRate, + _consolidate_fee_rate: FeeRate, + wallet: &mut RuntimeWallet, + account_index: U31| { + wallet + .decommission_stake_pool( + account_index, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .boxed() }, ) .await @@ -1069,13 +1157,15 @@ where _consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.decommission_stake_pool( - account_index, - pool_id, - staker_balance, - output_address, - current_fee_rate, - ) + wallet + .decommission_stake_pool( + account_index, + pool_id, + staker_balance, + output_address, + current_fee_rate, + ) + .boxed() }, ) .await @@ -1106,6 +1196,7 @@ where output_address, current_fee_rate, ) + .await .map_err(ControllerError::WalletError) } @@ -1118,14 +1209,17 @@ where let (current_fee_rate, consolidate_fee_rate) = self.get_current_and_consolidation_fee_rate().await?; - let result = self.wallet.create_htlc_tx( - self.account_index, - output_value, - htlc, - current_fee_rate, - consolidate_fee_rate, - additional_utxo_infos, - )?; + let result = self + .wallet + .create_htlc_tx( + self.account_index, + output_value, + htlc, + current_fee_rate, + consolidate_fee_rate, + additional_utxo_infos, + ) + .await?; Ok(result) } @@ -1143,15 +1237,17 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_order_tx( - account_index, - ask_value, - give_value, - conclude_key, - current_fee_rate, - consolidate_fee_rate, - &additional_info, - ) + wallet + .create_order_tx( + account_index, + ask_value, + give_value, + conclude_key, + current_fee_rate, + consolidate_fee_rate, + additional_info, + ) + .boxed() }, ) .await @@ -1170,15 +1266,17 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_conclude_order_tx( - account_index, - order_id, - order_info, - output_address, - current_fee_rate, - consolidate_fee_rate, - &additional_info, - ) + wallet + .create_conclude_order_tx( + account_index, + order_id, + order_info, + output_address, + current_fee_rate, + consolidate_fee_rate, + additional_info, + ) + .boxed() }, ) .await @@ -1198,16 +1296,18 @@ where consolidate_fee_rate: FeeRate, wallet: &mut RuntimeWallet, account_index: U31| { - wallet.create_fill_order_tx( - account_index, - order_id, - order_info, - fill_amount_in_ask_currency, - output_address, - current_fee_rate, - consolidate_fee_rate, - &additional_info, - ) + wallet + .create_fill_order_tx( + account_index, + order_id, + order_info, + fill_amount_in_ask_currency, + output_address, + current_fee_rate, + consolidate_fee_rate, + additional_info, + ) + .boxed() }, ) .await @@ -1266,16 +1366,18 @@ where self.wallet .sign_raw_transaction(self.account_index, ptx) + .await .map_err(ControllerError::WalletError) } - pub fn sign_challenge( + pub async fn sign_challenge( &mut self, challenge: &[u8], destination: &Destination, ) -> Result> { self.wallet .sign_challenge(self.account_index, challenge, destination) + .await .map_err(ControllerError::WalletError) } @@ -1329,12 +1431,19 @@ where } /// Create a transaction and broadcast it - async fn create_and_send_tx( + async fn create_and_send_tx( &mut self, - tx_maker: F, + tx_maker: Fun, ) -> Result> where - F: FnOnce(FeeRate, FeeRate, &mut RuntimeWallet, U31) -> Result, + Fun: FnOnce( + FeeRate, + FeeRate, + &mut RuntimeWallet, + U31, + ) -> BoxFuture> + + Send + + 'static, ControllerError: From, { let (current_fee_rate, consolidate_fee_rate) = @@ -1345,7 +1454,8 @@ where consolidate_fee_rate, self.wallet, self.account_index, - )?; + ) + .await?; self.broadcast_to_mempool_if_needed(tx).await } @@ -1358,12 +1468,14 @@ where ) -> Result> where F: FnOnce( - FeeRate, - FeeRate, - &mut RuntimeWallet, - U31, - &UnconfirmedTokenInfo, - ) -> WalletResult, + FeeRate, + FeeRate, + &mut RuntimeWallet, + U31, + UnconfirmedTokenInfo, + ) -> BoxFuture> + + Send + + 'static, { let token_freezable_info = self.unconfiremd_token_info(token_info)?; @@ -1375,8 +1487,9 @@ where consolidate_fee_rate, self.wallet, self.account_index, - &token_freezable_info, + token_freezable_info, ) + .await .map_err(ControllerError::WalletError)?; Ok(tx) @@ -1384,19 +1497,22 @@ where /// Create and broadcast a transaction that uses a token, /// check if that token can be used i.e. not frozen. - async fn create_and_send_token_tx< - F: FnOnce( - FeeRate, - FeeRate, - &mut RuntimeWallet, - U31, - &UnconfirmedTokenInfo, - ) -> WalletResult, - >( + async fn create_and_send_token_tx( &mut self, token_info: RPCTokenInfo, tx_maker: F, - ) -> Result> { + ) -> Result> + where + F: FnOnce( + FeeRate, + FeeRate, + &mut RuntimeWallet, + U31, + UnconfirmedTokenInfo, + ) -> BoxFuture> + + Send + + 'static, + { let tx = self.create_token_tx(token_info, tx_maker).await?; self.broadcast_to_mempool_if_needed(tx).await } @@ -1421,11 +1537,13 @@ where async fn create_and_send_tx_with_id< ID, F: FnOnce( - FeeRate, - FeeRate, - &mut RuntimeWallet, - U31, - ) -> WalletResult<(ID, SignedTransaction)>, + FeeRate, + FeeRate, + &mut RuntimeWallet, + U31, + ) -> BoxFuture> + + Send + + 'static, >( &mut self, tx_maker: F, @@ -1439,6 +1557,7 @@ where self.wallet, self.account_index, ) + .await .map_err(ControllerError::WalletError)?; let tx = self.broadcast_to_mempool_if_needed(tx).await?; diff --git a/wallet/wallet-rpc-lib/src/rpc/mod.rs b/wallet/wallet-rpc-lib/src/rpc/mod.rs index e6370156f..5c1628a95 100644 --- a/wallet/wallet-rpc-lib/src/rpc/mod.rs +++ b/wallet/wallet-rpc-lib/src/rpc/mod.rs @@ -874,6 +874,7 @@ where .synced_controller(account_index, config) .await? .sign_challenge(&challenge, &destination) + .await .map_err(RpcError::Controller) }) }) @@ -1303,7 +1304,8 @@ where controller .synced_controller(account_index, config) .await? - .decommission_stake_pool(pool_id, output_address) + // .decommission_stake_pool(pool_id, output_address) + .async_decommission_stake_pool(pool_id, output_address) .await .map_err(RpcError::Controller) })