From 37da81e50e828c767f1234d4b28df335124925bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Sat, 16 May 2026 22:57:37 +0200 Subject: [PATCH 01/12] uniffi: add missing APIs --- bindings/uniffi/src/lib.rs | 50 ++++++++++++++++++++++++--------- bindings/uniffi/src/rgb-lib.udl | 27 ++++++++++++++++++ src/database/enums.rs | 4 +++ src/lib.rs | 6 ++-- 4 files changed, 72 insertions(+), 15 deletions(-) diff --git a/bindings/uniffi/src/lib.rs b/bindings/uniffi/src/lib.rs index ae5069d2..cf201008 100644 --- a/bindings/uniffi/src/lib.rs +++ b/bindings/uniffi/src/lib.rs @@ -8,7 +8,7 @@ use std::{ use rgb_lib::{ AssetSchema, Assignment as RgbLibAssignment, CloseMethod, Error as RgbLibError, TransferStatus, - TransportType, + TransportType, WalletTransactionType, keys::{Keys, WitnessVersion}, utils::BitcoinNetwork, wallet::{ @@ -19,18 +19,19 @@ use rgb_lib::{ InvoiceData as RgbLibInvoiceData, Media, Metadata, MultisigKeys, MultisigOnlineOptions, MultisigVotingStatus as RgbLibMultisigVotingStatus, MultisigWallet as RgbLibMultisigWallet, Online, OnlineOptions, Operation as RgbLibOperation, OperationInfo as RgbLibOperationInfo, - OperationResult, Outpoint, ProofOfReserves, PsbtInputInfo, PsbtInspection, PsbtOutputInfo, - ReceiveData, Recipient as RgbLibRecipient, RecipientInfo as RgbLibRecipientInfo, - RecipientType, RefreshFilter, RefreshTransferStatus, RefreshedTransfer, - RespondToOperation as RgbLibRespondToOperation, RgbAllocation as RgbLibRgbAllocation, - RgbInputInfo as RgbLibRgbInputInfo, RgbInspection as RgbLibRgbInspection, - RgbOperationInfo as RgbLibRgbOperationInfo, RgbOutputInfo as RgbLibRgbOutputInfo, - RgbTransitionInfo as RgbLibRgbTransitionInfo, RgbWalletOpsOffline, RgbWalletOpsOnline, - SendBeginResult, SendDetails, SinglesigKeys, SyncKeychain as RgbLibSyncKeychain, - SyncOptions as RgbLibSyncOptions, SyncStrategy, Token, TokenLight, Transaction, - TransactionType, Transfer as RgbLibTransfer, TransferKind, TransferTransportEndpoint, - TransportEndpoint as RgbLibTransportEndpoint, TypeOfTransition, Unspent as RgbLibUnspent, - UserRole, Utxo, Wallet as RgbLibWallet, WalletData, WalletDescriptors, WitnessData, + OperationResult, Outpoint, PendingVanillaTx, ProofOfReserves, PsbtInputInfo, + PsbtInspection, PsbtOutputInfo, ReceiveData, Recipient as RgbLibRecipient, + RecipientInfo as RgbLibRecipientInfo, RecipientType, RefreshFilter, RefreshTransferStatus, + RefreshedTransfer, RespondToOperation as RgbLibRespondToOperation, + RgbAllocation as RgbLibRgbAllocation, RgbInputInfo as RgbLibRgbInputInfo, + RgbInspection as RgbLibRgbInspection, RgbOperationInfo as RgbLibRgbOperationInfo, + RgbOutputInfo as RgbLibRgbOutputInfo, RgbTransitionInfo as RgbLibRgbTransitionInfo, + RgbWalletOpsOffline, RgbWalletOpsOnline, SendBeginResult, SendDetails, SinglesigKeys, + SyncKeychain as RgbLibSyncKeychain, SyncOptions as RgbLibSyncOptions, SyncStrategy, Token, + TokenLight, Transaction, TransactionType, Transfer as RgbLibTransfer, TransferKind, + TransferTransportEndpoint, TransportEndpoint as RgbLibTransportEndpoint, TypeOfTransition, + Unspent as RgbLibUnspent, UserRole, Utxo, Wallet as RgbLibWallet, WalletData, + WalletDescriptors, WitnessData, }, }; @@ -1405,6 +1406,14 @@ impl Wallet { .inspect_rgb_transfer(psbt, fascia_path, entropy)? .into()) } + + fn list_pending_vanilla_txs(&self) -> Result, RgbLibError> { + self._get_wallet().list_pending_vanilla_txs() + } + + fn abort_pending_vanilla_tx(&self, txid: String) -> Result<(), RgbLibError> { + self._get_wallet().abort_pending_vanilla_tx(txid) + } } fn _convert_recipient_map( @@ -1448,6 +1457,10 @@ impl MultisigWallet { self._get_wallet().get_descriptors() } + fn get_local_last_processed_operation_idx(&self) -> Result { + self._get_wallet().get_local_last_processed_operation_idx() + } + fn get_wallet_dir(&self) -> String { self._get_wallet() .get_wallet_dir() @@ -1534,6 +1547,17 @@ impl MultisigWallet { .delete_transfers(batch_transfer_idx, no_asset_only) } + fn fail_transfers( + &self, + online: Online, + batch_transfer_idx: Option, + no_asset_only: bool, + skip_sync: bool, + ) -> Result { + self._get_wallet() + .fail_transfers(online, batch_transfer_idx, no_asset_only, skip_sync) + } + fn get_asset_balance(&self, asset_id: String) -> Result { self._get_wallet().get_asset_balance(asset_id) } diff --git a/bindings/uniffi/src/rgb-lib.udl b/bindings/uniffi/src/rgb-lib.udl index e761de73..cf5fafda 100644 --- a/bindings/uniffi/src/rgb-lib.udl +++ b/bindings/uniffi/src/rgb-lib.udl @@ -513,6 +513,19 @@ enum TransactionType { "Incoming", }; +[Remote] +enum WalletTransactionType { + "CreateUtxos", + "Drain", + "SendBtc", +}; + +[Remote] +dictionary PendingVanillaTx { + string txid; + WalletTransactionType type; +}; + [Remote] dictionary BlockTime { u32 height; @@ -965,6 +978,12 @@ interface Wallet { [Throws=RgbLibError] void sync(Online online, SyncOptions options); + + [Throws=RgbLibError] + sequence list_pending_vanilla_txs(); + + [Throws=RgbLibError] + void abort_pending_vanilla_tx(string txid); }; interface MultisigWallet { @@ -977,6 +996,9 @@ interface MultisigWallet { WalletDescriptors get_descriptors(); + [Throws=RgbLibError] + i32 get_local_last_processed_operation_idx(); + string get_wallet_dir(); string get_media_dir(); @@ -1015,6 +1037,11 @@ interface MultisigWallet { [Throws=RgbLibError] boolean delete_transfers(i32? batch_transfer_idx, boolean no_asset_only); + [Throws=RgbLibError] + boolean fail_transfers( + Online online, i32? batch_transfer_idx, boolean no_asset_only, + boolean skip_sync); + [Throws=RgbLibError] Balance get_asset_balance(string asset_id); diff --git a/src/database/enums.rs b/src/database/enums.rs index 47730d42..84ef37a0 100644 --- a/src/database/enums.rs +++ b/src/database/enums.rs @@ -311,13 +311,17 @@ impl TransferStatus { } } +/// The type of a pending vanilla wallet transaction. #[derive(Debug, Copy, Clone, PartialEq, Eq, EnumIter, DeriveActiveEnum, Deserialize, Serialize)] #[sea_orm(rs_type = "u8", db_type = "TinyUnsigned")] pub enum WalletTransactionType { + /// Transaction used to create UTXOs #[sea_orm(num_value = 1)] CreateUtxos = 1, + /// Transaction used to drain the RGB wallet #[sea_orm(num_value = 2)] Drain = 2, + /// Transaction used to perform a BTC send #[sea_orm(num_value = 3)] SendBtc = 3, } diff --git a/src/lib.rs b/src/lib.rs index 3f5b0230..cd330868 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,9 @@ pub use rgbstd::{ }; pub use crate::{ - database::enums::{AssetSchema, Assignment, TransferStatus, TransportType}, + database::enums::{ + AssetSchema, Assignment, TransferStatus, TransportType, WalletTransactionType, + }, error::Error, utils::{BitcoinNetwork, block_on}, }; @@ -297,7 +299,7 @@ use crate::{ txo::{ActiveModel as DbTxoActMod, Model as DbTxo}, wallet_transaction::Model as DbWalletTransaction, }, - enums::{ColoringType, RecipientTypeFull, WalletTransactionType}, + enums::{ColoringType, RecipientTypeFull}, }, error::InternalError, keys::{Keys, WitnessVersion}, From 78395ba2d36c7768331c51dce63ba784ae675edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Tue, 5 May 2026 19:02:23 +0200 Subject: [PATCH 02/12] add DB transactions --- bindings/uniffi/src/rgb-lib.udl | 1 + src/database/mod.rs | 295 ++++++----- src/error.rs | 18 +- src/lib.rs | 8 +- src/wallet/backup.rs | 53 +- src/wallet/core.rs | 38 +- src/wallet/mod.rs | 7 +- src/wallet/multisig.rs | 243 ++++++--- src/wallet/objects.rs | 44 +- src/wallet/offline.rs | 342 +++++++------ src/wallet/online.rs | 530 +++++++++++--------- src/wallet/rust_only.rs | 10 +- src/wallet/singlesig.rs | 234 +++++---- src/wallet/test/abort_pending_vanilla_tx.rs | 35 +- src/wallet/test/blind_receive.rs | 24 +- src/wallet/test/burn.rs | 13 +- src/wallet/test/create_utxos.rs | 22 +- src/wallet/test/delete_transfers.rs | 28 +- src/wallet/test/drain_to.rs | 20 +- src/wallet/test/fail_transfers.rs | 16 +- src/wallet/test/get_address.rs | 8 +- src/wallet/test/get_asset_balance.rs | 8 +- src/wallet/test/get_asset_metadata.rs | 8 +- src/wallet/test/get_btc_balance.rs | 8 +- src/wallet/test/go_online.rs | 8 +- src/wallet/test/inflate.rs | 13 +- src/wallet/test/issue_asset_cfa.rs | 8 +- src/wallet/test/issue_asset_ifa.rs | 8 +- src/wallet/test/issue_asset_nia.rs | 8 +- src/wallet/test/issue_asset_uda.rs | 8 +- src/wallet/test/list_assets.rs | 8 +- src/wallet/test/list_transactions.rs | 8 +- src/wallet/test/list_transfers.rs | 8 +- src/wallet/test/list_unspents.rs | 8 +- src/wallet/test/mod.rs | 4 +- src/wallet/test/multisig/mod.rs | 3 + src/wallet/test/multisig/utils.rs | 45 +- src/wallet/test/new.rs | 4 +- src/wallet/test/refresh.rs | 50 +- src/wallet/test/rust_only.rs | 53 +- src/wallet/test/send.rs | 145 +++--- src/wallet/test/send_btc.rs | 45 +- src/wallet/test/sync.rs | 22 + src/wallet/test/utils/api.rs | 9 + src/wallet/test/utils/helpers.rs | 71 +-- src/wallet/test/witness_receive.rs | 13 +- 46 files changed, 1528 insertions(+), 1034 deletions(-) create mode 100644 src/wallet/test/sync.rs diff --git a/bindings/uniffi/src/rgb-lib.udl b/bindings/uniffi/src/rgb-lib.udl index cf5fafda..1fbbc848 100644 --- a/bindings/uniffi/src/rgb-lib.udl +++ b/bindings/uniffi/src/rgb-lib.udl @@ -22,6 +22,7 @@ interface RgbLibError { CannotFailBatchTransfer(); CannotFinalizePsbt(); CannotUseIfaOnMainnet(); + Database(string details); EmptyFile(string file_path); FailedBdkSync(string details); FailedBroadcast(string details); diff --git a/src/database/mod.rs b/src/database/mod.rs index d4e65b90..e137e5b2 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -37,7 +37,7 @@ impl DbBatchTransfer { pub(crate) fn get_asset_transfers( &self, asset_transfers: &[DbAssetTransfer], - ) -> Result, InternalError> { + ) -> Result, Error> { Ok(asset_transfers .iter() .filter(|&t| t.batch_transfer_idx == self.idx) @@ -50,7 +50,7 @@ impl DbBatchTransfer { &self, asset_transfers: &[DbAssetTransfer], transfers: &[DbTransfer], - ) -> Result { + ) -> Result { let asset_transfers = self.get_asset_transfers(asset_transfers)?; let mut asset_transfers_data = vec![]; for asset_transfer in asset_transfers { @@ -136,7 +136,7 @@ impl DbTransfer { &self, asset_transfers: &[DbAssetTransfer], batch_transfers: &[DbBatchTransfer], - ) -> Result<(DbAssetTransfer, DbBatchTransfer), InternalError> { + ) -> Result<(DbAssetTransfer, DbBatchTransfer), Error> { let asset_transfer = asset_transfers .iter() .find(|t| t.idx == self.asset_transfer_idx) @@ -196,58 +196,81 @@ impl RgbLibDatabase { Self { connection } } - pub(crate) fn get_connection(&self) -> &DatabaseConnection { - &self.connection + pub(crate) fn begin_transaction(&self) -> Result { + Ok(DbTxn { + txn: Some(block_on(self.connection.begin())?), + }) + } +} + +pub struct DbTxn { + txn: Option, +} + +impl Drop for DbTxn { + fn drop(&mut self) { + if let Some(txn) = self.txn.take() { + // run the rollback inside our runtime so the async + // release has a tokio context (panics otherwise) + let _ = block_on(txn.rollback()); + } + } +} + +impl DbTxn { + fn inner(&self) -> &DatabaseTransaction { + self.txn.as_ref().expect("txn already consumed") + } + + pub(crate) fn commit(mut self) -> Result<(), Error> { + let txn = self.txn.take().expect("txn already consumed"); + Ok(block_on(txn.commit())?) } - pub(crate) fn set_asset(&self, asset: DbAssetActMod) -> Result { - let res = block_on(Asset::insert(asset).exec(self.get_connection()))?; + pub(crate) fn set_asset(&self, asset: DbAssetActMod) -> Result { + let res = block_on(Asset::insert(asset).exec(self.inner()))?; Ok(res.last_insert_id) } pub(crate) fn set_asset_transfer( &self, asset_transfer: DbAssetTransferActMod, - ) -> Result { - let res = block_on(AssetTransfer::insert(asset_transfer).exec(self.get_connection()))?; + ) -> Result { + let res = block_on(AssetTransfer::insert(asset_transfer).exec(self.inner()))?; Ok(res.last_insert_id) } - pub(crate) fn set_backup_info( - &self, - backup_info: DbBackupInfoActMod, - ) -> Result { - let res = block_on(BackupInfo::insert(backup_info).exec(self.get_connection()))?; + pub(crate) fn set_backup_info(&self, backup_info: DbBackupInfoActMod) -> Result { + let res = block_on(BackupInfo::insert(backup_info).exec(self.inner()))?; Ok(res.last_insert_id) } pub(crate) fn set_batch_transfer( &self, batch_transfer: DbBatchTransferActMod, - ) -> Result { + ) -> Result { let mut batch_transfer = batch_transfer; batch_transfer.updated_at = batch_transfer.created_at.clone(); - let res = block_on(BatchTransfer::insert(batch_transfer).exec(self.get_connection()))?; + let res = block_on(BatchTransfer::insert(batch_transfer).exec(self.inner()))?; Ok(res.last_insert_id) } - pub(crate) fn set_coloring(&self, coloring: DbColoringActMod) -> Result { - let res = block_on(Coloring::insert(coloring).exec(self.get_connection()))?; + pub(crate) fn set_coloring(&self, coloring: DbColoringActMod) -> Result { + let res = block_on(Coloring::insert(coloring).exec(self.inner()))?; Ok(res.last_insert_id) } - pub(crate) fn set_media(&self, media: DbMediaActMod) -> Result { - let res = block_on(Media::insert(media).exec(self.get_connection()))?; + pub(crate) fn set_media(&self, media: DbMediaActMod) -> Result { + let res = block_on(Media::insert(media).exec(self.inner()))?; Ok(res.last_insert_id) } pub(crate) fn set_pending_witness_script( &self, pending_witness_script: DbPendingWitnessScriptActMod, - ) -> Result { - let res = block_on( - PendingWitnessScript::insert(pending_witness_script).exec(self.get_connection()), - )?; + ) -> Result { + let res = + block_on(PendingWitnessScript::insert(pending_witness_script).exec(self.inner()))?; Ok(res.last_insert_id) } @@ -255,51 +278,46 @@ impl RgbLibDatabase { pub(crate) fn set_reserved_txos( &self, reserved_txos: Vec, - ) -> Result<(), InternalError> { - block_on(ReservedTxo::insert_many(reserved_txos).exec(self.get_connection()))?; + ) -> Result<(), Error> { + block_on(ReservedTxo::insert_many(reserved_txos).exec(self.inner()))?; Ok(()) } - pub(crate) fn set_token(&self, token: DbTokenActMod) -> Result { - let res = block_on(Token::insert(token).exec(self.get_connection()))?; + pub(crate) fn set_token(&self, token: DbTokenActMod) -> Result { + let res = block_on(Token::insert(token).exec(self.inner()))?; Ok(res.last_insert_id) } - pub(crate) fn set_token_media( - &self, - token_media: DbTokenMediaActMod, - ) -> Result { - let res = block_on(TokenMedia::insert(token_media).exec(self.get_connection()))?; + pub(crate) fn set_token_media(&self, token_media: DbTokenMediaActMod) -> Result { + let res = block_on(TokenMedia::insert(token_media).exec(self.inner()))?; Ok(res.last_insert_id) } pub(crate) fn set_transport_endpoint( &self, transport_endpoint: DbTransportEndpointActMod, - ) -> Result { - let res = - block_on(TransportEndpoint::insert(transport_endpoint).exec(self.get_connection()))?; + ) -> Result { + let res = block_on(TransportEndpoint::insert(transport_endpoint).exec(self.inner()))?; Ok(res.last_insert_id) } - pub(crate) fn set_transfer(&self, transfer: DbTransferActMod) -> Result { - let res = block_on(Transfer::insert(transfer).exec(self.get_connection()))?; + pub(crate) fn set_transfer(&self, transfer: DbTransferActMod) -> Result { + let res = block_on(Transfer::insert(transfer).exec(self.inner()))?; Ok(res.last_insert_id) } pub(crate) fn set_transfer_transport_endpoint( &self, transfer_transport_endpoint: DbTransferTransportEndpointActMod, - ) -> Result { + ) -> Result { let res = block_on( - TransferTransportEndpoint::insert(transfer_transport_endpoint) - .exec(self.get_connection()), + TransferTransportEndpoint::insert(transfer_transport_endpoint).exec(self.inner()), )?; Ok(res.last_insert_id) } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn set_txo(&self, txo: DbTxoActMod) -> Result { + pub(crate) fn set_txo(&self, txo: DbTxoActMod) -> Result { let mut on_conflict = sea_query::OnConflict::columns([txo::Column::Txid, txo::Column::Vout]); let mut update = false; @@ -317,7 +335,7 @@ impl RgbLibDatabase { on_conflict.do_nothing(); } // this returns RecordNotInserted if the TXO already exists and on_conflict is do_nothing - let conn = self.get_connection(); + let conn = self.inner(); let res = block_on( Txo::insert(txo.clone()) .on_conflict(on_conflict.to_owned()) @@ -347,9 +365,8 @@ impl RgbLibDatabase { pub(crate) fn set_wallet_transaction( &self, wallet_transaction: DbWalletTransactionActMod, - ) -> Result { - let res = - block_on(WalletTransaction::insert(wallet_transaction).exec(self.get_connection()))?; + ) -> Result { + let res = block_on(WalletTransaction::insert(wallet_transaction).exec(self.inner()))?; Ok(res.last_insert_id) } @@ -357,35 +374,33 @@ impl RgbLibDatabase { pub(crate) fn update_transfer( &self, transfer: &mut DbTransferActMod, - ) -> Result { + ) -> Result { Ok(block_on( - Transfer::update(transfer.clone()).exec(self.get_connection()), + Transfer::update(transfer.clone()).exec(self.inner()), )?) } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn update_asset(&self, asset: &mut DbAssetActMod) -> Result { - Ok(block_on( - Asset::update(asset.clone()).exec(self.get_connection()), - )?) + pub(crate) fn update_asset(&self, asset: &mut DbAssetActMod) -> Result { + Ok(block_on(Asset::update(asset.clone()).exec(self.inner()))?) } #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) fn update_asset_transfer( &self, asset_transfer: &mut DbAssetTransferActMod, - ) -> Result { + ) -> Result { Ok(block_on( - AssetTransfer::update(asset_transfer.clone()).exec(self.get_connection()), + AssetTransfer::update(asset_transfer.clone()).exec(self.inner()), )?) } pub(crate) fn update_backup_info( &self, backup_info: &mut DbBackupInfoActMod, - ) -> Result { + ) -> Result { Ok(block_on( - BackupInfo::update(backup_info.clone()).exec(self.get_connection()), + BackupInfo::update(backup_info.clone()).exec(self.inner()), )?) } @@ -393,11 +408,11 @@ impl RgbLibDatabase { pub(crate) fn update_batch_transfer( &self, batch_transfer: &mut DbBatchTransferActMod, - ) -> Result { + ) -> Result { let now = now().unix_timestamp(); batch_transfer.updated_at = ActiveValue::Set(now); Ok(block_on( - BatchTransfer::update(batch_transfer.clone()).exec(self.get_connection()), + BatchTransfer::update(batch_transfer.clone()).exec(self.inner()), )?) } @@ -405,238 +420,229 @@ impl RgbLibDatabase { pub(crate) fn update_transfer_transport_endpoint( &self, transfer_transport_endpoint: &mut DbTransferTransportEndpointActMod, - ) -> Result { + ) -> Result { Ok(block_on( TransferTransportEndpoint::update(transfer_transport_endpoint.clone()) - .exec(self.get_connection()), + .exec(self.inner()), )?) } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn update_txo(&self, txo: DbTxoActMod) -> Result<(), InternalError> { - block_on(Txo::update(txo).exec(self.get_connection()))?; + pub(crate) fn update_txo(&self, txo: DbTxoActMod) -> Result<(), Error> { + block_on(Txo::update(txo).exec(self.inner()))?; Ok(()) } - pub(crate) fn del_backup_info(&self) -> Result<(), InternalError> { - block_on(BackupInfo::delete_many().exec(self.get_connection()))?; + pub(crate) fn del_backup_info(&self) -> Result<(), Error> { + block_on(BackupInfo::delete_many().exec(self.inner()))?; Ok(()) } - pub(crate) fn del_batch_transfer( - &self, - batch_transfer: &DbBatchTransfer, - ) -> Result<(), InternalError> { - block_on(Transfer::delete_by_id(batch_transfer.idx).exec(self.get_connection()))?; + pub(crate) fn del_batch_transfer(&self, batch_transfer: &DbBatchTransfer) -> Result<(), Error> { + block_on(Transfer::delete_by_id(batch_transfer.idx).exec(self.inner()))?; Ok(()) } - pub(crate) fn del_coloring(&self, asset_transfer_idx: i32) -> Result<(), InternalError> { + pub(crate) fn del_coloring(&self, asset_transfer_idx: i32) -> Result<(), Error> { block_on( Coloring::delete_many() .filter(coloring::Column::AssetTransferIdx.eq(asset_transfer_idx)) - .exec(self.get_connection()), + .exec(self.inner()), )?; Ok(()) } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn del_pending_witness_script(&self, script: String) -> Result<(), InternalError> { + pub(crate) fn del_pending_witness_script(&self, script: String) -> Result<(), Error> { block_on( PendingWitnessScript::delete_many() .filter(pending_witness_script::Column::Script.eq(script)) - .exec(self.get_connection()), + .exec(self.inner()), )?; Ok(()) } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn del_reserved_txos( - &self, - reserved_txos: &[DbReservedTxo], - ) -> Result<(), InternalError> { + pub(crate) fn del_reserved_txos(&self, reserved_txos: &[DbReservedTxo]) -> Result<(), Error> { let idxs = reserved_txos.iter().map(|r| r.idx).collect::>(); block_on( ReservedTxo::delete_many() .filter(reserved_txo::Column::Idx.is_in(idxs)) - .exec(self.get_connection()), + .exec(self.inner()), )?; Ok(()) } - pub(crate) fn del_txo(&self, idx: i32) -> Result<(), InternalError> { - block_on(Coloring::delete_by_id(idx).exec(self.get_connection()))?; + #[cfg(test)] + pub(crate) fn del_transfer_transport_endpoint(&self, idx: i32) -> Result<(), Error> { + block_on(transfer_transport_endpoint::Entity::delete_by_id(idx).exec(self.inner()))?; + Ok(()) + } + + pub(crate) fn del_txo(&self, idx: i32) -> Result<(), Error> { + block_on(Coloring::delete_by_id(idx).exec(self.inner()))?; Ok(()) } - pub(crate) fn del_wallet_transaction(&self, idx: i32) -> Result<(), InternalError> { - block_on(WalletTransaction::delete_by_id(idx).exec(self.get_connection()))?; + pub(crate) fn del_wallet_transaction(&self, idx: i32) -> Result<(), Error> { + block_on(WalletTransaction::delete_by_id(idx).exec(self.inner()))?; Ok(()) } - pub(crate) fn get_asset(&self, asset_id: String) -> Result, InternalError> { + pub(crate) fn get_asset(&self, asset_id: String) -> Result, Error> { Ok(block_on( Asset::find() .filter(asset::Column::Id.eq(asset_id.clone())) - .one(self.get_connection()), + .one(self.inner()), )?) } - pub(crate) fn get_backup_info(&self) -> Result, InternalError> { - Ok(block_on(BackupInfo::find().one(self.get_connection()))?) + pub(crate) fn get_backup_info(&self) -> Result, Error> { + Ok(block_on(BackupInfo::find().one(self.inner()))?) } #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) fn get_batch_transfer_by_txid( &self, txid: &str, - ) -> Result, InternalError> { + ) -> Result, Error> { Ok(block_on( BatchTransfer::find() .filter(batch_transfer::Column::Txid.eq(txid)) - .one(self.get_connection()), + .one(self.inner()), )?) } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn get_media(&self, media_idx: i32) -> Result, InternalError> { + pub(crate) fn get_media(&self, media_idx: i32) -> Result, Error> { Ok(block_on( Media::find() .filter(media::Column::Idx.eq(media_idx)) - .one(self.get_connection()), + .one(self.inner()), )?) } - pub(crate) fn get_media_by_digest( - &self, - digest: String, - ) -> Result, InternalError> { + pub(crate) fn get_media_by_digest(&self, digest: String) -> Result, Error> { Ok(block_on( Media::find() .filter(media::Column::Digest.eq(digest)) - .one(self.get_connection()), + .one(self.inner()), )?) } pub(crate) fn get_transport_endpoint( &self, endpoint: String, - ) -> Result, InternalError> { + ) -> Result, Error> { Ok(block_on( TransportEndpoint::find() .filter(transport_endpoint::Column::Endpoint.eq(endpoint)) - .one(self.get_connection()), + .one(self.inner()), )?) } - pub(crate) fn get_txo(&self, outpoint: &Outpoint) -> Result, InternalError> { + pub(crate) fn get_txo(&self, outpoint: &Outpoint) -> Result, Error> { Ok(block_on( Txo::find() .filter(txo::Column::Txid.eq(outpoint.txid.clone())) .filter(txo::Column::Vout.eq(outpoint.vout)) - .one(self.get_connection()), + .one(self.inner()), )?) } pub(crate) fn get_wallet_transactions_by_idxs( &self, idxs: &[i32], - ) -> Result, InternalError> { + ) -> Result, Error> { Ok(block_on( WalletTransaction::find() .filter(wallet_transaction::Column::Idx.is_in(idxs.to_vec())) - .all(self.get_connection()), + .all(self.inner()), )?) } pub(crate) fn get_wallet_transaction_with_reserved_txos_by_txid( &self, txid: &str, - ) -> Result)>, InternalError> { + ) -> Result)>, Error> { Ok(block_on( WalletTransaction::find() .filter(wallet_transaction::Column::Txid.eq(txid)) .find_with_related(ReservedTxo) - .all(self.get_connection()), + .all(self.inner()), )? .into_iter() .next()) } - pub(crate) fn iter_assets(&self) -> Result, InternalError> { - Ok(block_on(Asset::find().all(self.get_connection()))?) + pub(crate) fn iter_assets(&self) -> Result, Error> { + Ok(block_on(Asset::find().all(self.inner()))?) } - pub(crate) fn iter_asset_transfers(&self) -> Result, InternalError> { - Ok(block_on(AssetTransfer::find().all(self.get_connection()))?) + pub(crate) fn iter_asset_transfers(&self) -> Result, Error> { + Ok(block_on(AssetTransfer::find().all(self.inner()))?) } - pub(crate) fn iter_batch_transfers(&self) -> Result, InternalError> { - Ok(block_on(BatchTransfer::find().all(self.get_connection()))?) + pub(crate) fn iter_batch_transfers(&self) -> Result, Error> { + Ok(block_on(BatchTransfer::find().all(self.inner()))?) } - pub(crate) fn iter_colorings(&self) -> Result, InternalError> { - Ok(block_on(Coloring::find().all(self.get_connection()))?) + pub(crate) fn iter_colorings(&self) -> Result, Error> { + Ok(block_on(Coloring::find().all(self.inner()))?) } - pub(crate) fn iter_media(&self) -> Result, InternalError> { - Ok(block_on(Media::find().all(self.get_connection()))?) + pub(crate) fn iter_media(&self) -> Result, Error> { + Ok(block_on(Media::find().all(self.inner()))?) } #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) fn iter_pending_witness_scripts( &self, - ) -> Result, InternalError> { - Ok(block_on( - PendingWitnessScript::find().all(self.get_connection()), - )?) + ) -> Result, Error> { + Ok(block_on(PendingWitnessScript::find().all(self.inner()))?) } - pub(crate) fn iter_reserved_txos(&self) -> Result, InternalError> { - Ok(block_on(ReservedTxo::find().all(self.get_connection()))?) + pub(crate) fn iter_reserved_txos(&self) -> Result, Error> { + Ok(block_on(ReservedTxo::find().all(self.inner()))?) } - pub(crate) fn iter_token_medias(&self) -> Result, InternalError> { - Ok(block_on(TokenMedia::find().all(self.get_connection()))?) + pub(crate) fn iter_token_medias(&self) -> Result, Error> { + Ok(block_on(TokenMedia::find().all(self.inner()))?) } - pub(crate) fn iter_tokens(&self) -> Result, InternalError> { - Ok(block_on(Token::find().all(self.get_connection()))?) + pub(crate) fn iter_tokens(&self) -> Result, Error> { + Ok(block_on(Token::find().all(self.inner()))?) } - pub(crate) fn iter_transfers(&self) -> Result, InternalError> { - Ok(block_on(Transfer::find().all(self.get_connection()))?) + pub(crate) fn iter_transfers(&self) -> Result, Error> { + Ok(block_on(Transfer::find().all(self.inner()))?) } - pub(crate) fn iter_txos(&self) -> Result, InternalError> { - Ok(block_on(Txo::find().all(self.get_connection()))?) + pub(crate) fn iter_txos(&self) -> Result, Error> { + Ok(block_on(Txo::find().all(self.inner()))?) } - pub(crate) fn iter_wallet_transactions( - &self, - ) -> Result, InternalError> { - Ok(block_on( - WalletTransaction::find().all(self.get_connection()), - )?) + pub(crate) fn iter_wallet_transactions(&self) -> Result, Error> { + Ok(block_on(WalletTransaction::find().all(self.inner()))?) } pub(crate) fn get_transfer_transport_endpoints_data( &self, transfer_idx: i32, - ) -> Result, InternalError> { + ) -> Result, Error> { Ok(block_on( TransferTransportEndpoint::find() .filter(transfer_transport_endpoint::Column::TransferIdx.eq(transfer_idx)) .find_also_related(TransportEndpoint) .order_by_asc(transfer_transport_endpoint::Column::Idx) - .all(self.get_connection()), + .all(self.inner()), )? .into_iter() .map(|(tte, ce)| (tte, ce.expect("should be connected"))) .collect()) } - pub(crate) fn get_db_data(&self, empty_transfers: bool) -> Result { + pub(crate) fn get_db_data(&self, empty_transfers: bool) -> Result { let batch_transfers = self.iter_batch_transfers()?; let asset_transfers = self.iter_asset_transfers()?; let colorings = self.iter_colorings()?; @@ -655,7 +661,7 @@ impl RgbLibDatabase { }) } - pub(crate) fn get_unspent_txos(&self, txos: Vec) -> Result, InternalError> { + pub(crate) fn get_unspent_txos(&self, txos: Vec) -> Result, Error> { let txos = if txos.is_empty() { self.iter_txos()? } else { @@ -752,7 +758,7 @@ impl RgbLibDatabase { Err(e) => Some(Err(e)), }, ) - .collect::, InternalError>>()? + .collect::, Error>>()? .iter() .sum(); ass_pending_incoming += witness_pending; @@ -805,7 +811,7 @@ impl RgbLibDatabase { } #[cfg(any(feature = "electrum", feature = "esplora"))] - pub(crate) fn get_asset_ids(&self) -> Result, InternalError> { + pub(crate) fn get_asset_ids(&self) -> Result, Error> { Ok(self.iter_assets()?.iter().map(|a| a.id.clone()).collect()) } @@ -828,6 +834,17 @@ impl RgbLibDatabase { } } + pub(crate) fn get_or_insert_media(&self, digest: String, mime: String) -> Result { + Ok(match self.get_media_by_digest(digest.clone())? { + Some(media) => media.idx, + None => self.set_media(DbMediaActMod { + digest: ActiveValue::Set(digest), + mime: ActiveValue::Set(mime), + ..Default::default() + })?, + }) + } + fn get_utxo_allocations( &self, utxo: &DbTxo, diff --git a/src/error.rs b/src/error.rs index 8603ebf6..49d08678 100644 --- a/src/error.rs +++ b/src/error.rs @@ -62,6 +62,13 @@ pub enum Error { #[error("Cannot use IFA schema on mainnet")] CannotUseIfaOnMainnet, + /// A database error has been encountered + #[error("Database error: {details}")] + Database { + /// Error details + details: String, + }, + /// The provided file is empty #[error("Empty file: {file_path}")] EmptyFile { @@ -661,9 +668,6 @@ pub(crate) enum InternalError { #[error("Confinement error: {0}")] Confinement(#[from] amplify::confinement::Error), - #[error("Database error: {0}")] - Database(#[from] sea_orm::DbErr), - #[error("Encode error: {0}")] Encode(#[from] bitcoin::consensus::encode::Error), @@ -901,6 +905,14 @@ impl From for Error { } } +impl From for Error { + fn from(e: sea_orm::DbErr) -> Self { + Error::Database { + details: e.to_string(), + } + } +} + impl From for Error { fn from(e: rgbstd::contract::BuilderError) -> Self { Error::Internal { diff --git a/src/lib.rs b/src/lib.rs index cd330868..df2ff99a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -220,9 +220,9 @@ use scrypt::{ password_hash::{PasswordHasher, Salt, SaltString, rand_core::OsRng}, }; use sea_orm::{ - ActiveValue, ColumnTrait, ConnectOptions, Database, DatabaseConnection, DbErr, - DeriveActiveEnum, EntityTrait, EnumIter, IntoActiveValue, JsonValue, QueryFilter, QueryOrder, - QueryResult, TryGetError, TryGetable, TryIntoModel, + ActiveValue, ColumnTrait, ConnectOptions, Database, DatabaseConnection, DatabaseTransaction, + DbErr, DeriveActiveEnum, EntityTrait, EnumIter, IntoActiveValue, JsonValue, QueryFilter, + QueryOrder, QueryResult, TransactionTrait, TryGetError, TryGetable, TryIntoModel, }; use serde::de::{self, Unexpected, Visitor}; use serde::{Deserialize, Deserializer, Serialize}; @@ -276,7 +276,7 @@ use crate::{ }; use crate::{ database::{ - RgbLibDatabase, + DbTxn, RgbLibDatabase, entities::{ asset::{ActiveModel as DbAssetActMod, Model as DbAsset}, asset_transfer::{ActiveModel as DbAssetTransferActMod, Model as DbAssetTransfer}, diff --git a/src/wallet/backup.rs b/src/wallet/backup.rs index 950c0fa3..116be140 100644 --- a/src/wallet/backup.rs +++ b/src/wallet/backup.rs @@ -80,17 +80,21 @@ pub trait WalletBackup: WalletCore { password: &str, scrypt_params: Option, ) -> Result<(), Error> { - let prev_backup_info = self.update_backup_info(true)?; + let txn = self.database().begin_transaction()?; + let prev_backup_info = self.update_backup_info(&txn, true)?; + txn.commit()?; match self.backup_raw(backup_path, password, scrypt_params) { Ok(()) => Ok(()), Err(e) => { error!(self.logger(), "Error during backup: {e:?}"); + let txn = self.database().begin_transaction()?; if let Some(prev_backup_info) = prev_backup_info { let mut prev_backup_info: DbBackupInfoActMod = prev_backup_info.into(); - self.database().update_backup_info(&mut prev_backup_info)?; + txn.update_backup_info(&mut prev_backup_info)?; } else { - self.database().del_backup_info()?; + txn.del_backup_info()?; } + txn.commit()?; Err(e) } } @@ -168,22 +172,21 @@ pub trait WalletBackup: WalletCore { Ok(()) } - fn get_backup_info(&self) -> Result { - Ok( - if let Some(backup_info) = self.database().get_backup_info()? { - backup_info - .last_operation_timestamp - .parse::() - .unwrap() - > backup_info.last_backup_timestamp.parse::().unwrap() - } else { - false - }, - ) + fn get_backup_info(&self, txn: &DbTxn) -> Result { + Ok(if let Some(backup_info) = txn.get_backup_info()? { + backup_info + .last_operation_timestamp + .parse::() + .unwrap() + > backup_info.last_backup_timestamp.parse::().unwrap() + } else { + false + }) } fn update_backup_info_with_op_idx( &self, + txn: &DbTxn, doing_backup: bool, last_processed_operation_idx: Option, ) -> Result, Error> { @@ -193,7 +196,7 @@ pub trait WalletBackup: WalletCore { } else { ActiveValue::NotSet }; - if let Some(backup_info) = self.database().get_backup_info()? { + Ok(if let Some(backup_info) = txn.get_backup_info()? { let prev_backup_info = backup_info.clone(); let mut backup_info: DbBackupInfoActMod = backup_info.into(); if doing_backup { @@ -202,8 +205,8 @@ pub trait WalletBackup: WalletCore { backup_info.last_operation_timestamp = now; } backup_info.last_processed_operation_idx = last_processed_operation_idx; - self.database().update_backup_info(&mut backup_info)?; - Ok(Some(prev_backup_info)) + txn.update_backup_info(&mut backup_info)?; + Some(prev_backup_info) } else { let (last_backup_timestamp, last_operation_timestamp) = if doing_backup { (now, ActiveValue::Set(s!("0"))) @@ -216,13 +219,17 @@ pub trait WalletBackup: WalletCore { last_processed_operation_idx, ..Default::default() }; - self.database().set_backup_info(backup_info)?; - Ok(None) - } + txn.set_backup_info(backup_info)?; + None + }) } - fn update_backup_info(&self, doing_backup: bool) -> Result, Error> { - self.update_backup_info_with_op_idx(doing_backup, None) + fn update_backup_info( + &self, + txn: &DbTxn, + doing_backup: bool, + ) -> Result, Error> { + self.update_backup_info_with_op_idx(txn, doing_backup, None) } } diff --git a/src/wallet/core.rs b/src/wallet/core.rs index 971b5c89..0c11905b 100644 --- a/src/wallet/core.rs +++ b/src/wallet/core.rs @@ -108,8 +108,8 @@ pub(crate) fn setup_db>(wallet_dir: P) -> Result Result, Error> { + fn fast_sync_colored_spks(&self, txn: &DbTxn) -> Result, Error> { let mut spks: HashSet = HashSet::new(); - for pws in self.database().iter_pending_witness_scripts()? { + for pws in txn.iter_pending_witness_scripts()? { spks.insert(ScriptBuf::from_hex(&pws.script).expect("valid script")); } Ok(spks) @@ -299,6 +299,7 @@ pub trait WalletCore { #[cfg(any(feature = "electrum", feature = "esplora"))] fn sync_bdk_and_db_txos( &mut self, + txn: &DbTxn, options: SyncOptions, include_spent: bool, ) -> Result<(), Error> { @@ -331,7 +332,7 @@ pub trait WalletCore { let mut spks: HashSet = HashSet::new(); match options.keychain { SyncKeychain::Colored => { - spks.extend(self.fast_sync_colored_spks()?); + spks.extend(self.fast_sync_colored_spks(txn)?); spks.extend(self.unconfirmed_colored_spks()); } SyncKeychain::Vanilla { lookback } => { @@ -353,7 +354,7 @@ pub trait WalletCore { bdk_wallet.persist(bdk_db)?; if matches!(options.keychain, SyncKeychain::Colored) { - self.update_db_colored_txos_from_bdk(include_spent)?; + self.update_db_colored_txos_from_bdk(txn, include_spent)?; } debug!(self.logger(), "Synced"); @@ -361,8 +362,12 @@ pub trait WalletCore { } #[cfg(any(feature = "electrum", feature = "esplora"))] - fn update_db_colored_txos_from_bdk(&mut self, include_spent: bool) -> Result<(), Error> { - let db_txos = self.database().iter_txos()?; + fn update_db_colored_txos_from_bdk( + &mut self, + txn: &DbTxn, + include_spent: bool, + ) -> Result<(), Error> { + let db_txos = txn.iter_txos()?; let db_outpoints: HashSet = db_txos .into_iter() @@ -370,8 +375,7 @@ pub trait WalletCore { .map(|u| u.outpoint().to_string()) .collect(); - let pending_witness_scripts: Vec = self - .database() + let pending_witness_scripts: Vec = txn .iter_pending_witness_scripts()? .into_iter() .map(|s| s.script) @@ -392,18 +396,22 @@ pub trait WalletCore { let pending_witness_script = new_utxo.txout.script_pubkey.to_hex_string(); if pending_witness_scripts.contains(&pending_witness_script) { new_db_utxo.pending_witness = ActiveValue::Set(true); - self.database() - .del_pending_witness_script(pending_witness_script)?; + txn.del_pending_witness_script(pending_witness_script)?; } } - self.database().set_txo(new_db_utxo.clone())?; + txn.set_txo(new_db_utxo.clone())?; } Ok(()) } #[cfg(any(feature = "electrum", feature = "esplora"))] - fn sync_wallet(&mut self, options: SyncOptions, include_spent: bool) -> Result<(), Error> { - self.sync_bdk_and_db_txos(options, include_spent) + fn sync_wallet( + &mut self, + txn: &DbTxn, + options: SyncOptions, + include_spent: bool, + ) -> Result<(), Error> { + self.sync_bdk_and_db_txos(txn, options, include_spent) } } diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 3500892c..24c9b926 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -55,9 +55,10 @@ pub use core::{SyncKeychain, SyncOptions, SyncStrategy}; pub(crate) use indexer::Indexer; #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) use objects::{ - AssetInfo, AssetSpend, BeginOperationData, BtcChange, LocalRecipient, LocalRecipientData, - LocalWitnessData, OnlineData, PrepareRgbPsbtResult, PrepareTransferPsbtResult, - ReceivedConsignmentMeta, RefreshResultTrait, + AssetInfo, AssetSpend, BeginOperationData, BtcChange, FailTransfersOutcome, LocalRecipient, + LocalRecipientData, LocalWitnessData, OnlineData, PrepareRgbPsbtResult, + PrepareTransferPsbtResult, ReceivedConsignmentMeta, RefreshResultTrait, + TryFailBatchTransferOutcome, }; pub(crate) use objects::{ InfoAssetTransfer, InfoBatchTransfer, IssueData, IssuedAssetDetails, LocalAssetData, diff --git a/src/wallet/multisig.rs b/src/wallet/multisig.rs index d1be66df..69547e38 100644 --- a/src/wallet/multisig.rs +++ b/src/wallet/multisig.rs @@ -213,7 +213,12 @@ impl WalletCore for MultisigWallet { } #[cfg(any(feature = "electrum", feature = "esplora"))] - fn sync_wallet(&mut self, options: SyncOptions, include_spent: bool) -> Result<(), Error> { + fn sync_wallet( + &mut self, + txn: &DbTxn, + options: SyncOptions, + include_spent: bool, + ) -> Result<(), Error> { // sync addresses let response = self.hub_client().get_current_address_indices()?; let (bdk_wallet, bdk_database) = self.bdk_wallet_db_mut(); @@ -238,7 +243,7 @@ impl WalletCore for MultisigWallet { bdk_wallet.persist(bdk_database)?; } // sync UTXOs - self.sync_bdk_and_db_txos(options, include_spent) + self.sync_bdk_and_db_txos(txn, options, include_spent) } } @@ -267,7 +272,7 @@ impl WalletOffline for MultisigWallet { #[cfg(any(feature = "electrum", feature = "esplora"))] impl WalletOnline for MultisigWallet { - fn wallet_specific_consistency_checks(&mut self) -> Result<(), Error> { + fn wallet_specific_consistency_checks(&mut self, _txn: &DbTxn) -> Result<(), Error> { Ok(()) } @@ -325,9 +330,18 @@ impl RgbWalletOpsOnline for MultisigWallet { "Failing batch transfer with idx {:?}...", batch_transfer_idx ); self.check_online(online)?; - let changed = self.fail_transfers_impl(batch_transfer_idx, no_asset_only, skip_sync)?; + let txn = self.database().begin_transaction()?; + let outcome = + self.fail_transfers_impl(&txn, batch_transfer_idx, no_asset_only, skip_sync)?; + if outcome.transfers_changed { + self.update_backup_info(&txn, false)?; + } + txn.commit()?; info!(self.logger(), "Fail transfers completed"); - Ok(changed) + if outcome.cannot_fail { + return Err(Error::CannotFailBatchTransfer); + } + Ok(outcome.transfers_changed) } } @@ -612,6 +626,7 @@ pub(crate) trait OperationHandler { fn discarded(details: Self::Details, status: MultisigVotingStatus) -> Operation; fn finalize_and_execute( + txn: &DbTxn, wallet: &mut MultisigWallet, combined_psbt: &Psbt, ) -> Result; @@ -653,10 +668,11 @@ impl OperationHandler for CreateUtxosHandler { } fn finalize_and_execute( + txn: &DbTxn, wallet: &mut MultisigWallet, combined_psbt: &Psbt, ) -> Result { - wallet.create_utxos_end_impl(combined_psbt)?; + wallet.create_utxos_end_impl(txn, combined_psbt)?; Ok(combined_psbt.unsigned_tx.compute_txid().to_string()) } } @@ -689,10 +705,11 @@ impl OperationHandler for SendBtcHandler { } fn finalize_and_execute( + txn: &DbTxn, wallet: &mut MultisigWallet, combined_psbt: &Psbt, ) -> Result { - wallet.send_btc_end_impl(combined_psbt)?; + wallet.send_btc_end_impl(txn, combined_psbt)?; Ok(combined_psbt.unsigned_tx.compute_txid().to_string()) } } @@ -740,10 +757,11 @@ impl OperationHandler for SendRgbHandler { } fn finalize_and_execute( + txn: &DbTxn, wallet: &mut MultisigWallet, combined_psbt: &Psbt, ) -> Result { - let res = wallet.send_end_impl(combined_psbt)?; + let res = wallet.send_end_impl(txn, combined_psbt)?; Ok(res.txid) } @@ -806,10 +824,11 @@ impl OperationHandler for InflateHandler { } fn finalize_and_execute( + txn: &DbTxn, wallet: &mut MultisigWallet, combined_psbt: &Psbt, ) -> Result { - let res = wallet.inflate_end_impl(combined_psbt)?; + let res = wallet.inflate_end_impl(txn, combined_psbt)?; Ok(res.txid) } @@ -872,10 +891,11 @@ impl OperationHandler for BurnHandler { } fn finalize_and_execute( + txn: &DbTxn, wallet: &mut MultisigWallet, combined_psbt: &Psbt, ) -> Result { - let res = wallet.burn_end_impl(combined_psbt)?; + let res = wallet.burn_end_impl(txn, combined_psbt)?; Ok(res.txid) } @@ -1042,17 +1062,22 @@ impl MultisigWallet { .expect("already succeeded at wallet creation") } + fn get_local_last_processed_operation_idx_impl(&self, txn: &DbTxn) -> Result { + Ok(txn + .get_backup_info()? + .and_then(|b| b.last_processed_operation_idx) + .unwrap_or(0)) + } + /// Get the last hub processed operation index that the wallet has stored in the database. pub fn get_local_last_processed_operation_idx(&self) -> Result { info!( self.logger(), "Getting local last processed operation IDX..." ); - let idx = self - .database() - .get_backup_info()? - .and_then(|b| b.last_processed_operation_idx) - .unwrap_or(0); + let txn = self.database().begin_transaction()?; + let idx = self.get_local_last_processed_operation_idx_impl(&txn)?; + txn.commit()?; info!( self.logger(), "Get local last processed operation IDX completed" @@ -1157,7 +1182,9 @@ impl MultisigWallet { self.check_online(online)?; self.check_is_cosigner()?; let address = self.get_new_addresses(KeychainKind::Internal, 1)?; - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Get address completed"); Ok(address.to_string()) } @@ -1225,7 +1252,7 @@ impl MultisigWallet { Ok(info) } - fn mark_operation_as_processed(&self, operation_idx: i32) -> Result<(), Error> { + fn mark_operation_as_processed(&self, txn: &DbTxn, operation_idx: i32) -> Result<(), Error> { if self.is_cosigner()? && let Err(e) = self.hub_client().mark_operation_processed(operation_idx) { @@ -1236,12 +1263,13 @@ impl MultisigWallet { return Err(e); } } - self.update_backup_info_with_op_idx(false, Some(operation_idx))?; + self.update_backup_info_with_op_idx(txn, false, Some(operation_idx))?; Ok(()) } fn upload_and_process_issuance( &self, + txn: &DbTxn, issue_data: &IssueData, mut additional_files: Vec<(FileType, FileSource)>, ) -> Result { @@ -1254,9 +1282,9 @@ impl MultisigWallet { .hub_client() .post_operation(files, OperationType::Issuance)?; let mut runtime = self.rgb_runtime()?; - let asset = self.import_and_save_contract(issue_data, &mut runtime)?; - self.mark_operation_as_processed(response.operation_idx)?; - T::from_issuance(self, &asset, issue_data) + let asset = self.import_and_save_contract(txn, issue_data, &mut runtime)?; + self.mark_operation_as_processed(txn, response.operation_idx)?; + T::from_issuance(txn, self, &asset, issue_data) } /// Issue a new RGB NIA asset with the provided `ticker`, `name`, `precision` and `amounts`, @@ -1277,9 +1305,13 @@ impl MultisigWallet { ) -> Result { self.check_online(online)?; self.check_is_cosigner()?; - self.issue_asset_nia_with_impl(ticker, name, precision, amounts, |issue_data| { - self.upload_and_process_issuance(&issue_data, vec![]) - }) + let txn = self.database().begin_transaction()?; + let res = + self.issue_asset_nia_with_impl(&txn, ticker, name, precision, amounts, |issue_data| { + self.upload_and_process_issuance(&txn, &issue_data, vec![]) + })?; + txn.commit()?; + Ok(res) } /// Issue a new RGB UDA asset with the provided `ticker`, `name`, optional `details` and @@ -1302,7 +1334,9 @@ impl MultisigWallet { ) -> Result { self.check_online(online)?; self.check_is_cosigner()?; - self.issue_asset_uda_with_impl( + let txn = self.database().begin_transaction()?; + let res = self.issue_asset_uda_with_impl( + &txn, ticker, name, details, @@ -1330,9 +1364,11 @@ impl MultisigWallet { FileSource::Path(media.file_path.clone().into()), )) } - self.upload_and_process_issuance(&issue_data, files) + self.upload_and_process_issuance(&txn, &issue_data, files) }, - ) + )?; + txn.commit()?; + Ok(res) } /// Issue a new RGB CFA asset with the provided `name`, optional `details`, `precision` and @@ -1357,16 +1393,27 @@ impl MultisigWallet { ) -> Result { self.check_online(online)?; self.check_is_cosigner()?; - self.issue_asset_cfa_with_impl(name, details, precision, amounts, file_path, |issue_data| { - let mut files = vec![]; - if let Some(media) = &issue_data.asset_data.media { - files.push(( - FileType::Media, - FileSource::Path(media.file_path.clone().into()), - )) - } - self.upload_and_process_issuance(&issue_data, files) - }) + let txn = self.database().begin_transaction()?; + let res = self.issue_asset_cfa_with_impl( + &txn, + name, + details, + precision, + amounts, + file_path, + |issue_data| { + let mut files = vec![]; + if let Some(media) = &issue_data.asset_data.media { + files.push(( + FileType::Media, + FileSource::Path(media.file_path.clone().into()), + )) + } + self.upload_and_process_issuance(&txn, &issue_data, files) + }, + )?; + txn.commit()?; + Ok(res) } /// Issue a new RGB IFA asset with the provided `ticker`, `name`, `precision`, `amounts` and @@ -1392,15 +1439,19 @@ impl MultisigWallet { ) -> Result { self.check_online(online)?; self.check_is_cosigner()?; - self.issue_asset_ifa_with_impl( + let txn = self.database().begin_transaction()?; + let res = self.issue_asset_ifa_with_impl( + &txn, ticker, name, precision, amounts, inflation_amounts, reject_list_url, - |issue_data| self.upload_and_process_issuance(&issue_data, vec![]), - ) + |issue_data| self.upload_and_process_issuance(&txn, &issue_data, vec![]), + )?; + txn.commit()?; + Ok(res) } fn receive_impl( @@ -1413,8 +1464,11 @@ impl MultisigWallet { recipient_type: RecipientType, operation_type: OperationType, ) -> Result { + let txn = self.database().begin_transaction()?; + // shared receive data creation logic let receive_data_internal = self.create_receive_data( + &txn, asset_id, assignment, expiration_timestamp.map(|t| t as i64), @@ -1436,11 +1490,13 @@ impl MultisigWallet { // store transfer let batch_transfer_idx = - self.store_receive_transfer(&receive_data_internal, min_confirmations)?; + self.store_receive_transfer(&txn, &receive_data_internal, min_confirmations)?; + + self.update_backup_info(&txn, false)?; - self.update_backup_info(false)?; + self.mark_operation_as_processed(&txn, response.operation_idx)?; - self.mark_operation_as_processed(response.operation_idx)?; + txn.commit()?; Ok(ReceiveData { invoice: receive_data_internal.invoice_string, @@ -1556,7 +1612,11 @@ impl MultisigWallet { Ok(receive_data) } - fn accept_issuance_consignment(&mut self, files: &[FileResponse]) -> Result { + fn accept_issuance_consignment( + &mut self, + files: &[FileResponse], + txn: &DbTxn, + ) -> Result { // get the validated contract let consignment_file = files .iter() @@ -1625,17 +1685,18 @@ impl MultisigWallet { .allocations(&FilterIncludeAll) { let outpoint = a.seal.to_outpoint().into(); - let txo = match self.database().get_txo(&outpoint)? { + let txo = match txn.get_txo(&outpoint)? { Some(txo) => txo, None => { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, }, true, )?; - self.database().get_txo(&outpoint)?.expect("should exist") + txn.get_txo(&outpoint)?.expect("should exist") } }; issue_utxos @@ -1651,15 +1712,15 @@ impl MultisigWallet { issue_utxos, }; - self.import_and_save_contract(&issue_data, &mut runtime)?; - - self.update_backup_info(false)?; + self.import_and_save_contract(txn, &issue_data, &mut runtime)?; + self.update_backup_info(txn, false)?; Ok(asset_id) } fn import_receive_data( &mut self, + txn: &DbTxn, files: &[FileResponse], operation_type: &OperationType, ) -> Result { @@ -1723,7 +1784,7 @@ impl MultisigWallet { script_pubkey, }; let batch_transfer_idx = - self.store_receive_transfer(&receive_data_internal, min_confirmations)?; + self.store_receive_transfer(txn, &receive_data_internal, min_confirmations)?; Ok(ReceiveData { invoice: receive_metadata.invoice, @@ -1743,8 +1804,11 @@ impl MultisigWallet { info!(self.logger(), "Syncing with hub..."); self.check_online(online)?; + let txn = self.database().begin_transaction()?; + // make sure the wallet is synced and transfers are up-to-date self.sync_wallet( + &txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FullSync, @@ -1752,6 +1816,7 @@ impl MultisigWallet { false, )?; self.sync_wallet( + &txn, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: self.vanilla_sync_lookback(), @@ -1760,10 +1825,11 @@ impl MultisigWallet { }, false, )?; - self.refresh_impl(None, vec![], true)?; - self.refresh_impl(None, vec![], true)?; + self.refresh_impl(&txn, None, vec![], true)?; + self.refresh_impl(&txn, None, vec![], true)?; - let op_idx = self.get_local_last_processed_operation_idx()?; + let op_idx = self.get_local_last_processed_operation_idx_impl(&txn)?; + txn.commit()?; let Some(op) = self.hub_client().get_operation_by_idx(op_idx + 1)? else { return Ok(None); }; @@ -1781,12 +1847,16 @@ impl MultisigWallet { | OperationType::BlindReceive ); if needs_refresh { - let _ = self.refresh_impl(None, vec![], true); + let txn = self.database().begin_transaction()?; + let _ = self.refresh_impl(&txn, None, vec![], true)?; + txn.commit()?; if !matches!( op.operation_type, OperationType::Inflation | OperationType::Burn ) { - let _ = self.refresh_impl(None, vec![], true); + let txn = self.database().begin_transaction()?; + let _ = self.refresh_impl(&txn, None, vec![], true); + txn.commit()?; } } @@ -1800,7 +1870,9 @@ impl MultisigWallet { } } - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Sync with hub completed"); Ok(Some(OperationInfo { operation_idx: op.operation_idx, @@ -1887,13 +1959,18 @@ impl MultisigWallet { self.finalize_psbt_impl(&mut combined_psbt, None)?; let txid = combined_psbt.unsigned_tx.compute_txid().to_string(); H::reconstruct_transfer_directory(self, &txid, files)?; - let txid = H::finalize_and_execute(self, &combined_psbt)?; - self.mark_operation_as_processed(op.operation_idx)?; + let txn = self.database().begin_transaction()?; + let txid = H::finalize_and_execute(&txn, self, &combined_psbt)?; + self.update_backup_info(&txn, false)?; + self.mark_operation_as_processed(&txn, op.operation_idx)?; + txn.commit()?; let status = Self::build_voting_status(op, op.my_response)?; Ok(H::completed(txid, details, status)) } (OperationStatus::Discarded, my_response) => { - self.mark_operation_as_processed(op.operation_idx)?; + let txn = self.database().begin_transaction()?; + self.mark_operation_as_processed(&txn, op.operation_idx)?; + txn.commit()?; let status = Self::build_voting_status(op, my_response)?; Ok(H::discarded(details, status)) } @@ -1912,8 +1989,10 @@ impl MultisigWallet { OperationType::Burn => self.handle_operation::(op, &files)?, OperationType::Issuance => match op.status { OperationStatus::Approved => { - let asset_id = self.accept_issuance_consignment(&files)?; - self.mark_operation_as_processed(op.operation_idx)?; + let txn = self.database().begin_transaction()?; + let asset_id = self.accept_issuance_consignment(&files, &txn)?; + self.mark_operation_as_processed(&txn, op.operation_idx)?; + txn.commit()?; Operation::IssuanceCompleted { asset_id } } _ => { @@ -1924,8 +2003,10 @@ impl MultisigWallet { }, OperationType::BlindReceive | OperationType::WitnessReceive => match op.status { OperationStatus::Approved => { - let details = self.import_receive_data(&files, &op.operation_type)?; - self.mark_operation_as_processed(op.operation_idx)?; + let txn = self.database().begin_transaction()?; + let details = self.import_receive_data(&txn, &files, &op.operation_type)?; + self.mark_operation_as_processed(&txn, op.operation_idx)?; + txn.commit()?; match op.operation_type { OperationType::BlindReceive => Operation::BlindReceiveCompleted { details }, _ => Operation::WitnessReceiveCompleted { details }, @@ -2007,7 +2088,9 @@ impl MultisigWallet { // process operation let operation = self.process_operation(&operation_response)?; - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Responding to operation..."); Ok(OperationInfo { operation_idx: operation_response.operation_idx, @@ -2078,9 +2161,12 @@ impl MultisigWallet { info!(self.logger(), "Initiate creating UTXOs..."); self.check_online(online)?; self.check_is_cosigner()?; - let psbt = self.create_utxos_begin_impl(up_to, num, size, fee_rate, skip_sync, true)?; + let txn = self.database().begin_transaction()?; + let psbt = + self.create_utxos_begin_impl(&txn, up_to, num, size, fee_rate, skip_sync, true)?; let res = self.post_operation(OperationType::CreateUtxos, PostData::Psbt(psbt))?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Initiate creating UTXOs completed"); Ok(res) } @@ -2101,9 +2187,11 @@ impl MultisigWallet { info!(self.logger(), "Initiate sending BTC..."); self.check_online(online)?; self.check_is_cosigner()?; - let psbt = self.send_btc_begin_impl(address, amount, fee_rate, skip_sync, true)?; + let txn = self.database().begin_transaction()?; + let psbt = self.send_btc_begin_impl(&txn, address, amount, fee_rate, skip_sync, true)?; let res = self.post_operation(OperationType::SendBtc, PostData::Psbt(psbt))?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Initiate sending BTC completed"); Ok(res) } @@ -2143,7 +2231,9 @@ impl MultisigWallet { info!(self.logger(), "Initiate sending..."); self.check_online(online)?; self.check_is_cosigner()?; + let txn = self.database().begin_transaction()?; let data = self.send_begin_impl( + &txn, recipient_map, donation, fee_rate, @@ -2155,7 +2245,8 @@ impl MultisigWallet { OperationType::SendRgb, PostData::BeginOperationData(Box::new(data)), )?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Initiate sending completed"); Ok(res) } @@ -2183,8 +2274,9 @@ impl MultisigWallet { info!(self.logger(), "Initiate inflating..."); self.check_online(online)?; self.check_is_cosigner()?; - + let txn = self.database().begin_transaction()?; let data = self.inflate_begin_impl( + &txn, asset_id, inflation_amounts, fee_rate, @@ -2195,7 +2287,8 @@ impl MultisigWallet { OperationType::Inflation, PostData::BeginOperationData(Box::new(data)), )?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Initiate inflating completed"); Ok(res) } @@ -2219,13 +2312,15 @@ impl MultisigWallet { info!(self.logger(), "Initiate burning amount: {}...", amount); self.check_online(online)?; self.check_is_cosigner()?; - - let data = self.burn_begin_impl(asset_id, amount, fee_rate, min_confirmations, true)?; + let txn = self.database().begin_transaction()?; + let data = + self.burn_begin_impl(&txn, asset_id, amount, fee_rate, min_confirmations, true)?; let res = self.post_operation( OperationType::Burn, PostData::BeginOperationData(Box::new(data)), )?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Initiate burning completed"); Ok(res) } diff --git a/src/wallet/objects.rs b/src/wallet/objects.rs index 7245c599..a0c2ea9a 100644 --- a/src/wallet/objects.rs +++ b/src/wallet/objects.rs @@ -407,6 +407,7 @@ pub struct AssetNIA { impl AssetNIA { pub(crate) fn get_asset_details( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, transfers: Option>, @@ -420,14 +421,14 @@ impl AssetNIA { let medias = if let Some(m) = medias { m } else { - wallet.database().iter_media()? + txn.iter_media()? }; medias .iter() .find(|m| Some(m.idx) == asset.media_idx) .map(|m| Media::from_db_media(m, wallet.media_dir())) }; - let balance = wallet.database().get_asset_balance( + let balance = txn.get_asset_balance( asset.id.clone(), transfers, asset_transfers, @@ -479,6 +480,7 @@ pub struct AssetUDA { impl AssetUDA { pub(crate) fn get_asset_details( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, token: Option, @@ -493,14 +495,14 @@ impl AssetUDA { let medias = if let Some(m) = medias { m } else { - wallet.database().iter_media()? + txn.iter_media()? }; medias .iter() .find(|m| Some(m.idx) == asset.media_idx) .map(|m| Media::from_db_media(m, wallet.media_dir())) }; - let balance = wallet.database().get_asset_balance( + let balance = txn.get_asset_balance( asset.id.clone(), transfers, asset_transfers, @@ -549,6 +551,7 @@ pub struct AssetCFA { impl AssetCFA { pub(crate) fn get_asset_details( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, transfers: Option>, @@ -562,14 +565,14 @@ impl AssetCFA { let medias = if let Some(m) = medias { m } else { - wallet.database().iter_media()? + txn.iter_media()? }; medias .iter() .find(|m| Some(m.idx) == asset.media_idx) .map(|m| Media::from_db_media(m, wallet.media_dir())) }; - let balance = wallet.database().get_asset_balance( + let balance = txn.get_asset_balance( asset.id.clone(), transfers, asset_transfers, @@ -626,6 +629,7 @@ pub struct AssetIFA { impl AssetIFA { pub(crate) fn get_asset_details( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, transfers: Option>, @@ -639,14 +643,14 @@ impl AssetIFA { let medias = if let Some(m) = medias { m } else { - wallet.database().iter_media()? + txn.iter_media()? }; medias .iter() .find(|m| Some(m.idx) == asset.media_idx) .map(|m| Media::from_db_media(m, wallet.media_dir())) }; - let balance = wallet.database().get_asset_balance( + let balance = txn.get_asset_balance( asset.id.clone(), transfers, asset_transfers, @@ -696,6 +700,7 @@ pub struct Assets { pub(crate) trait IssuedAssetDetails: Sized { fn from_issuance( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, issue_data: &IssueData, @@ -704,21 +709,24 @@ pub(crate) trait IssuedAssetDetails: Sized { impl IssuedAssetDetails for AssetNIA { fn from_issuance( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, _issue_data: &IssueData, ) -> Result { - Self::get_asset_details(wallet, asset, None, None, None, None, None, None) + Self::get_asset_details(txn, wallet, asset, None, None, None, None, None, None) } } impl IssuedAssetDetails for AssetUDA { fn from_issuance( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, issue_data: &IssueData, ) -> Result { Self::get_asset_details( + txn, wallet, asset, issue_data.asset_data.token.clone().map(|t| t.into()), @@ -734,21 +742,23 @@ impl IssuedAssetDetails for AssetUDA { impl IssuedAssetDetails for AssetCFA { fn from_issuance( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, _issue_data: &IssueData, ) -> Result { - Self::get_asset_details(wallet, asset, None, None, None, None, None, None) + Self::get_asset_details(txn, wallet, asset, None, None, None, None, None, None) } } impl IssuedAssetDetails for AssetIFA { fn from_issuance( + txn: &DbTxn, wallet: &(impl WalletOffline + ?Sized), asset: &DbAsset, _issue_data: &IssueData, ) -> Result { - Self::get_asset_details(wallet, asset, None, None, None, None, None, None) + Self::get_asset_details(txn, wallet, asset, None, None, None, None, None, None) } } @@ -1900,3 +1910,15 @@ pub struct ReceivedConsignmentMeta { pub txid: String, pub vout: Option, } + +#[cfg(any(feature = "electrum", feature = "esplora"))] +pub enum TryFailBatchTransferOutcome { + Failed, + Refreshed, +} + +#[cfg(any(feature = "electrum", feature = "esplora"))] +pub struct FailTransfersOutcome { + pub transfers_changed: bool, + pub cannot_fail: bool, +} diff --git a/src/wallet/offline.rs b/src/wallet/offline.rs index e0917ee3..b5e9b2e6 100644 --- a/src/wallet/offline.rs +++ b/src/wallet/offline.rs @@ -104,6 +104,7 @@ pub trait WalletOffline: WalletBackup { fn issue_asset_nia_with_impl( &self, + txn: &DbTxn, ticker: String, name: String, precision: u8, @@ -119,13 +120,14 @@ pub trait WalletOffline: WalletBackup { "ticker '{}' name '{}' precision '{}' amounts '{:?}'", ticker, name, precision, amounts ), - || self.create_nia_contract(ticker, name, precision, amounts), + || self.create_nia_contract(txn, ticker, name, precision, amounts), impl_fn, ) } fn issue_asset_uda_with_impl( &self, + txn: &DbTxn, ticker: String, name: String, details: Option, @@ -145,6 +147,7 @@ pub trait WalletOffline: WalletBackup { ), || { self.create_uda_contract( + txn, ticker, name, details, @@ -159,6 +162,7 @@ pub trait WalletOffline: WalletBackup { fn issue_asset_cfa_with_impl( &self, + txn: &DbTxn, name: String, details: Option, precision: u8, @@ -175,13 +179,14 @@ pub trait WalletOffline: WalletBackup { "name '{}' precision '{}' amounts '{:?}'", name, precision, amounts ), - || self.create_cfa_contract(name, details, precision, amounts, file_path), + || self.create_cfa_contract(txn, name, details, precision, amounts, file_path), impl_fn, ) } fn issue_asset_ifa_with_impl( &self, + txn: &DbTxn, ticker: String, name: String, precision: u8, @@ -201,6 +206,7 @@ pub trait WalletOffline: WalletBackup { ), || { self.creata_ifa_contract( + txn, ticker, name, precision, @@ -271,17 +277,15 @@ pub trait WalletOffline: WalletBackup { fn get_utxo( &self, + txn: &DbTxn, exclude_utxos: &[Outpoint], unspents: Option<&[LocalUnspent]>, pending_operation: bool, max_allocations: Option, ) -> Result { let rgb_allocations = if unspents.is_none() { - let unspent_txos = self.database().get_unspent_txos(vec![])?; - Some( - self.database() - .get_rgb_allocations(unspent_txos, None, None, None, None)?, - ) + let unspent_txos = txn.get_unspent_txos(vec![])?; + Some(txn.get_rgb_allocations(unspent_txos, None, None, None, None)?) } else { None }; @@ -319,30 +323,26 @@ pub trait WalletOffline: WalletBackup { fn save_transfer_transport_endpoint( &self, + txn: &DbTxn, transfer_idx: i32, transport_endpoint: &LocalTransportEndpoint, ) -> Result<(), Error> { - let transport_endpoint_idx = match self - .database() - .get_transport_endpoint(transport_endpoint.endpoint.clone())? - { - Some(ce) => ce.idx, - None => self - .database() - .set_transport_endpoint(DbTransportEndpointActMod { + let transport_endpoint_idx = + match txn.get_transport_endpoint(transport_endpoint.endpoint.clone())? { + Some(ce) => ce.idx, + None => txn.set_transport_endpoint(DbTransportEndpointActMod { transport_type: ActiveValue::Set(transport_endpoint.transport_type), endpoint: ActiveValue::Set(transport_endpoint.endpoint.clone()), ..Default::default() })?, - }; + }; - self.database() - .set_transfer_transport_endpoint(DbTransferTransportEndpointActMod { - transfer_idx: ActiveValue::Set(transfer_idx), - transport_endpoint_idx: ActiveValue::Set(transport_endpoint_idx), - used: ActiveValue::Set(transport_endpoint.used), - ..Default::default() - })?; + txn.set_transfer_transport_endpoint(DbTransferTransportEndpointActMod { + transfer_idx: ActiveValue::Set(transfer_idx), + transport_endpoint_idx: ActiveValue::Set(transport_endpoint_idx), + used: ActiveValue::Set(transport_endpoint.used), + ..Default::default() + })?; Ok(()) } @@ -490,6 +490,7 @@ pub trait WalletOffline: WalletBackup { fn import_and_save_contract( &self, + txn: &DbTxn, issue_data: &IssueData, runtime: &mut RgbRuntime, ) -> Result { @@ -497,27 +498,27 @@ pub trait WalletOffline: WalletBackup { .import_contract(issue_data.valid_contract.clone(), &DumbResolver) .expect("failure importing issued contract"); - let asset = self.add_asset_to_db(&issue_data.asset_data)?; + let asset = self.add_asset_to_db(txn, &issue_data.asset_data)?; let batch_transfer = DbBatchTransferActMod { status: ActiveValue::Set(TransferStatus::Settled), created_at: ActiveValue::Set(issue_data.asset_data.added_at), min_confirmations: ActiveValue::Set(0), ..Default::default() }; - let batch_transfer_idx = self.database().set_batch_transfer(batch_transfer)?; + let batch_transfer_idx = txn.set_batch_transfer(batch_transfer)?; let asset_transfer = DbAssetTransferActMod { user_driven: ActiveValue::Set(true), batch_transfer_idx: ActiveValue::Set(batch_transfer_idx), asset_id: ActiveValue::Set(Some(issue_data.asset_data.asset_id.clone())), ..Default::default() }; - let asset_transfer_idx = self.database().set_asset_transfer(asset_transfer)?; + let asset_transfer_idx = txn.set_asset_transfer(asset_transfer)?; let transfer = DbTransferActMod { asset_transfer_idx: ActiveValue::Set(asset_transfer_idx), incoming: ActiveValue::Set(true), ..Default::default() }; - self.database().set_transfer(transfer)?; + txn.set_transfer(transfer)?; for (utxo_idx, assignments) in &issue_data.issue_utxos { for assignment in assignments { let db_coloring = DbColoringActMod { @@ -527,7 +528,7 @@ pub trait WalletOffline: WalletBackup { assignment: ActiveValue::Set(assignment.clone()), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; } } @@ -547,6 +548,7 @@ pub trait WalletOffline: WalletBackup { fn create_nia_contract( &self, + txn: &DbTxn, ticker: String, name: String, precision: u8, @@ -558,10 +560,10 @@ pub trait WalletOffline: WalletBackup { let settled = self.get_total_issue_amount(&amounts, false)?; - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = self.database().get_rgb_allocations( - self.database().get_unspent_txos(db_data.txos.clone())?, + let mut unspents: Vec = txn.get_rgb_allocations( + txn.get_unspent_txos(db_data.txos.clone())?, None, None, None, @@ -607,7 +609,7 @@ pub trait WalletOffline: WalletBackup { let mut issue_utxos: HashMap> = HashMap::new(); let mut exclude_outpoints = vec![]; for amount in &amounts { - let utxo = self.get_utxo(&exclude_outpoints, Some(&unspents), false, None)?; + let utxo = self.get_utxo(txn, &exclude_outpoints, Some(&unspents), false, None)?; exclude_outpoints.push(utxo.outpoint()); issue_utxos .entry(utxo.idx) @@ -665,6 +667,7 @@ pub trait WalletOffline: WalletBackup { fn create_uda_contract( &self, + txn: &DbTxn, ticker: String, name: String, details: Option, @@ -682,10 +685,10 @@ pub trait WalletOffline: WalletBackup { }); } - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = self.database().get_rgb_allocations( - self.database().get_unspent_txos(db_data.txos.clone())?, + let mut unspents: Vec = txn.get_rgb_allocations( + txn.get_unspent_txos(db_data.txos.clone())?, None, None, None, @@ -717,7 +720,7 @@ pub trait WalletOffline: WalletBackup { precision: self.check_precision(precision)?, }; - let issue_utxo = self.get_utxo(&[], Some(&unspents), false, None)?; + let issue_utxo = self.get_utxo(txn, &[], Some(&unspents), false, None)?; let issue_utxos: HashMap> = HashMap::from([(issue_utxo.idx, vec![Assignment::NonFungible])]); @@ -799,6 +802,7 @@ pub trait WalletOffline: WalletBackup { fn create_cfa_contract( &self, + txn: &DbTxn, name: String, details: Option, precision: u8, @@ -811,10 +815,10 @@ pub trait WalletOffline: WalletBackup { let settled = self.get_total_issue_amount(&amounts, false)?; - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = self.database().get_rgb_allocations( - self.database().get_unspent_txos(db_data.txos.clone())?, + let mut unspents: Vec = txn.get_rgb_allocations( + txn.get_unspent_txos(db_data.txos.clone())?, None, None, None, @@ -867,7 +871,7 @@ pub trait WalletOffline: WalletBackup { let mut issue_utxos: HashMap> = HashMap::new(); let mut exclude_outpoints = vec![]; for amount in &amounts { - let utxo = self.get_utxo(&exclude_outpoints, Some(&unspents), false, None)?; + let utxo = self.get_utxo(txn, &exclude_outpoints, Some(&unspents), false, None)?; exclude_outpoints.push(utxo.outpoint()); issue_utxos .entry(utxo.idx) @@ -911,6 +915,7 @@ pub trait WalletOffline: WalletBackup { fn creata_ifa_contract( &self, + txn: &DbTxn, ticker: String, name: String, precision: u8, @@ -929,10 +934,10 @@ pub trait WalletOffline: WalletBackup { } let max_supply = settled + inflation_amt; - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = self.database().get_rgb_allocations( - self.database().get_unspent_txos(db_data.txos.clone())?, + let mut unspents: Vec = txn.get_rgb_allocations( + txn.get_unspent_txos(db_data.txos.clone())?, None, None, None, @@ -988,7 +993,7 @@ pub trait WalletOffline: WalletBackup { let mut issue_utxos: HashMap> = HashMap::new(); let mut exclude_outpoints: Vec = vec![]; for amount in &amounts { - let utxo = self.get_utxo(&exclude_outpoints, Some(&unspents), false, None)?; + let utxo = self.get_utxo(txn, &exclude_outpoints, Some(&unspents), false, None)?; exclude_outpoints.push(utxo.outpoint()); issue_utxos .entry(utxo.idx) @@ -1001,7 +1006,7 @@ pub trait WalletOffline: WalletBackup { } for amount in &inflation_amounts { - let utxo = self.get_utxo(&exclude_outpoints, Some(&unspents), false, Some(0))?; + let utxo = self.get_utxo(txn, &exclude_outpoints, Some(&unspents), false, Some(0))?; exclude_outpoints.push(utxo.outpoint()); issue_utxos .entry(utxo.idx) @@ -1076,6 +1081,7 @@ pub trait WalletOffline: WalletBackup { fn create_receive_data( &mut self, + txn: &DbTxn, asset_id: Option, assignment: Assignment, expiration_timestamp: Option, @@ -1084,19 +1090,14 @@ pub trait WalletOffline: WalletBackup { ) -> Result { let (beneficiary, recipient_type_full, blind_seal, script_pubkey) = match recipient_type { RecipientType::Blind => { - let mut unspents: Vec = self.database().get_rgb_allocations( - self.database().get_unspent_txos(vec![])?, - None, - None, - None, - None, - )?; + let mut unspents: Vec = + txn.get_rgb_allocations(txn.get_unspent_txos(vec![])?, None, None, None, None)?; unspents.retain(|u| { !(u.rgb_allocations .iter() .any(|a| !a.incoming && a.status.waiting_counterparty())) }); - let utxo = self.get_utxo(&[], Some(&unspents), true, None)?; + let utxo = self.get_utxo(txn, &[], Some(&unspents), true, None)?; let unblinded_utxo = utxo.outpoint(); debug!( self.logger(), @@ -1125,7 +1126,7 @@ pub trait WalletOffline: WalletBackup { let recipient_id = beneficiary.to_string(); debug!(self.logger(), "Recipient ID: {recipient_id}"); let (schema, contract_id) = if let Some(aid) = asset_id.clone() { - let asset = self.database().check_asset_exists(aid.clone())?; + let asset = txn.check_asset_exists(aid.clone())?; let contract_id = ContractId::from_str(&aid).expect("invalid contract ID"); (Some(asset.schema), Some(contract_id)) } else { @@ -1207,6 +1208,7 @@ pub trait WalletOffline: WalletBackup { fn store_receive_transfer( &self, + txn: &DbTxn, receive_data_internal: &ReceiveDataInternal, min_confirmations: u8, ) -> Result { @@ -1217,14 +1219,14 @@ pub trait WalletOffline: WalletBackup { min_confirmations: ActiveValue::Set(min_confirmations), ..Default::default() }; - let batch_transfer_idx = self.database().set_batch_transfer(batch_transfer)?; + let batch_transfer_idx = txn.set_batch_transfer(batch_transfer)?; let asset_transfer = DbAssetTransferActMod { user_driven: ActiveValue::Set(true), batch_transfer_idx: ActiveValue::Set(batch_transfer_idx), asset_id: ActiveValue::Set(receive_data_internal.asset_id.clone()), ..Default::default() }; - let asset_transfer_idx = self.database().set_asset_transfer(asset_transfer)?; + let asset_transfer_idx = txn.set_asset_transfer(asset_transfer)?; let transfer = DbTransferActMod { asset_transfer_idx: ActiveValue::Set(asset_transfer_idx), requested_assignment: ActiveValue::Set(Some( @@ -1238,9 +1240,10 @@ pub trait WalletOffline: WalletBackup { invoice_string: ActiveValue::Set(Some(receive_data_internal.invoice_string.clone())), ..Default::default() }; - let transfer_idx = self.database().set_transfer(transfer)?; + let transfer_idx = txn.set_transfer(transfer)?; for endpoint in &receive_data_internal.endpoints { self.save_transfer_transport_endpoint( + txn, transfer_idx, &LocalTransportEndpoint { endpoint: endpoint.clone(), @@ -1256,11 +1259,10 @@ pub trait WalletOffline: WalletBackup { } if let Some(script_pubkey) = &receive_data_internal.script_pubkey { - self.database() - .set_pending_witness_script(DbPendingWitnessScriptActMod { - script: ActiveValue::Set(script_pubkey.to_hex_string()), - ..Default::default() - })?; + txn.set_pending_witness_script(DbPendingWitnessScriptActMod { + script: ActiveValue::Set(script_pubkey.to_hex_string()), + ..Default::default() + })?; } Ok(batch_transfer_idx) @@ -1284,6 +1286,7 @@ pub trait WalletOffline: WalletBackup { fn delete_batch_transfer( &self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, asset_transfers: &Vec, colorings: &[DbColoring], @@ -1291,7 +1294,7 @@ pub trait WalletOffline: WalletBackup { ) -> Result<(), Error> { let mut txos_to_delete = HashSet::new(); for asset_transfer in asset_transfers { - self.database().del_coloring(asset_transfer.idx)?; + txn.del_coloring(asset_transfer.idx)?; colorings .iter() .filter(|c| c.asset_transfer_idx == asset_transfer.idx) @@ -1302,23 +1305,23 @@ pub trait WalletOffline: WalletBackup { }); } for txo in txos_to_delete { - self.database().del_txo(txo)?; + txn.del_txo(txo)?; } - Ok(self.database().del_batch_transfer(batch_transfer)?) + txn.del_batch_transfer(batch_transfer) } fn delete_transfers_impl( &self, + txn: &DbTxn, batch_transfer_idx: Option, no_asset_only: bool, ) -> Result { - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; let mut transfers_changed = false; if let Some(batch_transfer_idx) = batch_transfer_idx { - let batch_transfer = &self - .database() - .get_batch_transfer_or_fail(batch_transfer_idx, &db_data.batch_transfers)?; + let batch_transfer = + txn.get_batch_transfer_or_fail(batch_transfer_idx, &db_data.batch_transfers)?; if !batch_transfer.failed() { return Err(Error::CannotDeleteBatchTransfer); @@ -1335,7 +1338,8 @@ pub trait WalletOffline: WalletBackup { transfers_changed = true; self.delete_batch_transfer( - batch_transfer, + txn, + &batch_transfer, &asset_transfers, &db_data.colorings, &db_data.txos, @@ -1359,6 +1363,7 @@ pub trait WalletOffline: WalletBackup { } transfers_changed = true; self.delete_batch_transfer( + txn, batch_transfer, &asset_transfers, &db_data.colorings, @@ -1367,10 +1372,6 @@ pub trait WalletOffline: WalletBackup { } } - if transfers_changed { - self.update_backup_info(false)?; - } - Ok(transfers_changed) } @@ -1389,14 +1390,13 @@ pub trait WalletOffline: WalletBackup { self.get_new_addresses(KeychainKind::External, 1) } - fn get_asset_balance_impl(&self, asset_id: String) -> Result { - self.database().check_asset_exists(asset_id.clone())?; - self.database() - .get_asset_balance(asset_id, None, None, None, None, None) + fn get_asset_balance_impl(&self, txn: &DbTxn, asset_id: String) -> Result { + txn.check_asset_exists(asset_id.clone())?; + txn.get_asset_balance(asset_id, None, None, None, None, None) } - fn get_asset_metadata_impl(&self, asset_id: String) -> Result { - let asset = self.database().check_asset_exists(asset_id.clone())?; + fn get_asset_metadata_impl(&self, txn: &DbTxn, asset_id: String) -> Result { + let asset = txn.check_asset_exists(asset_id.clone())?; let initial_supply = asset.initial_supply.parse::().unwrap(); let max_supply = if let Some(max_supply) = asset.max_supply { @@ -1411,9 +1411,9 @@ pub trait WalletOffline: WalletBackup { initial_supply }; let token = if matches!(asset.schema, AssetSchema::Uda) { - let medias = self.database().iter_media()?; - let tokens = self.database().iter_tokens()?; - let token_medias = self.database().iter_token_medias()?; + let medias = txn.iter_media()?; + let tokens = txn.iter_tokens()?; + let token_medias = txn.iter_token_medias()?; if let Some(token_light) = self.get_asset_token(asset.idx, &medias, &tokens, &token_medias) { @@ -1459,27 +1459,17 @@ pub trait WalletOffline: WalletBackup { }) } - fn get_or_insert_media(&self, digest: String, mime: String) -> Result { - Ok(match self.database().get_media_by_digest(digest.clone())? { - Some(media) => media.idx, - None => self.database().set_media(DbMediaActMod { - digest: ActiveValue::Set(digest), - mime: ActiveValue::Set(mime), - ..Default::default() - })?, - }) - } - fn save_token_media( &self, + txn: &DbTxn, token_idx: i32, digest: String, mime: String, attachment_id: Option, ) -> Result<(), Error> { - let media_idx = self.get_or_insert_media(digest, mime)?; + let media_idx = txn.get_or_insert_media(digest, mime)?; - self.database().set_token_media(DbTokenMediaActMod { + txn.set_token_media(DbTokenMediaActMod { token_idx: ActiveValue::Set(token_idx), media_idx: ActiveValue::Set(media_idx), attachment_id: ActiveValue::Set(attachment_id), @@ -1489,9 +1479,9 @@ pub trait WalletOffline: WalletBackup { Ok(()) } - fn add_asset_to_db(&self, asset_data: &LocalAssetData) -> Result { + fn add_asset_to_db(&self, txn: &DbTxn, asset_data: &LocalAssetData) -> Result { let media_idx = if let Some(media) = &asset_data.media { - Some(self.get_or_insert_media(media.digest.clone(), media.mime.clone())?) + Some(txn.get_or_insert_media(media.digest.clone(), media.mime.clone())?) } else { None }; @@ -1513,7 +1503,7 @@ pub trait WalletOffline: WalletBackup { timestamp: ActiveValue::Set(asset_data.timestamp), reject_list_url: ActiveValue::Set(asset_data.reject_list_url.clone()), }; - let idx = self.database().set_asset(db_asset.clone())?; + let idx = txn.set_asset(db_asset.clone())?; db_asset.idx = ActiveValue::Set(idx); if let Some(ref token) = asset_data.token { @@ -1527,13 +1517,20 @@ pub trait WalletOffline: WalletBackup { reserves: ActiveValue::Set(token.reserves.is_some()), ..Default::default() }; - let token_idx = self.database().set_token(db_token)?; + let token_idx = txn.set_token(db_token)?; if let Some(media) = &token.media { - self.save_token_media(token_idx, media.get_digest(), media.mime.clone(), None)?; + self.save_token_media( + txn, + token_idx, + media.get_digest(), + media.mime.clone(), + None, + )?; } for (attachment_id, media) in token.attachments.clone() { self.save_token_media( + txn, token_idx, media.get_digest(), media.mime.clone(), @@ -1606,16 +1603,16 @@ pub trait WalletOffline: WalletBackup { fn get_btc_balance_impl( &mut self, + txn: &DbTxn, online: Option, skip_sync: bool, ) -> Result { - self.sync_if_requested(online, skip_sync, KeychainKind::External)?; - self.sync_if_requested(online, skip_sync, KeychainKind::Internal)?; + self.sync_if_requested(txn, online, skip_sync, KeychainKind::External)?; + self.sync_if_requested(txn, online, skip_sync, KeychainKind::Internal)?; let mut vanilla = self.get_btc_balance_for_keychain(KeychainKind::Internal)?; let colored = self.get_btc_balance_for_keychain(KeychainKind::External)?; - let reserved: HashSet = self - .database() + let reserved: HashSet = txn .iter_reserved_txos()? .into_iter() .map(BdkOutPoint::from) @@ -1773,6 +1770,7 @@ pub trait WalletOffline: WalletBackup { fn save_new_asset_internal( &self, + txn: &DbTxn, runtime: &RgbRuntime, contract_id: ContractId, asset_schema: AssetSchema, @@ -1787,28 +1785,26 @@ pub trait WalletOffline: WalletBackup { valid_transfer, )?; - let _ = self.add_asset_to_db(&local_asset_data)?; + let _ = self.add_asset_to_db(txn, &local_asset_data)?; Ok(local_asset_data) } - fn get_reserved_vanilla_outpoints(&self) -> Result, Error> { - Ok(self - .database() + fn get_reserved_vanilla_outpoints(&self, txn: &DbTxn) -> Result, Error> { + Ok(txn .iter_reserved_txos()? .into_iter() .map(BdkOutPoint::from) .collect()) } - fn get_unspendable_bdk_outpoints(&self) -> Result, Error> { - let mut outpoints: Vec = self - .database() + fn get_unspendable_bdk_outpoints(&self, txn: &DbTxn) -> Result, Error> { + let mut outpoints: Vec = txn .iter_txos()? .into_iter() .map(BdkOutPoint::from) .collect(); - outpoints.extend(self.get_reserved_vanilla_outpoints()?); + outpoints.extend(self.get_reserved_vanilla_outpoints(txn)?); Ok(outpoints) } @@ -1818,20 +1814,21 @@ pub trait WalletOffline: WalletBackup { fn list_assets_impl( &self, + txn: &DbTxn, mut filter_asset_schemas: Vec, ) -> Result { if filter_asset_schemas.is_empty() { filter_asset_schemas = AssetSchema::VALUES.to_vec() } - let batch_transfers = Some(self.database().iter_batch_transfers()?); - let colorings = Some(self.database().iter_colorings()?); - let txos = Some(self.database().iter_txos()?); - let asset_transfers = Some(self.database().iter_asset_transfers()?); - let transfers = Some(self.database().iter_transfers()?); - let medias = Some(self.database().iter_media()?); + let batch_transfers = Some(txn.iter_batch_transfers()?); + let colorings = Some(txn.iter_colorings()?); + let txos = Some(txn.iter_txos()?); + let asset_transfers = Some(txn.iter_asset_transfers()?); + let transfers = Some(txn.iter_transfers()?); + let medias = Some(txn.iter_media()?); - let assets = self.database().iter_assets()?; + let assets = txn.iter_assets()?; let mut nia = None; let mut uda = None; let mut cfa = None; @@ -1845,6 +1842,7 @@ pub trait WalletOffline: WalletBackup { .filter(|a| a.schema == schema) .map(|a| { AssetNIA::get_asset_details( + txn, self, a, transfers.clone(), @@ -1859,14 +1857,15 @@ pub trait WalletOffline: WalletBackup { ); } AssetSchema::Uda => { - let tokens = self.database().iter_tokens()?; - let token_medias = self.database().iter_token_medias()?; + let tokens = txn.iter_tokens()?; + let token_medias = txn.iter_token_medias()?; uda = Some( assets .iter() .filter(|a| a.schema == schema) .map(|a| { AssetUDA::get_asset_details( + txn, self, a, self.get_asset_token( @@ -1893,6 +1892,7 @@ pub trait WalletOffline: WalletBackup { .filter(|a| a.schema == schema) .map(|a| { AssetCFA::get_asset_details( + txn, self, a, transfers.clone(), @@ -1913,6 +1913,7 @@ pub trait WalletOffline: WalletBackup { .filter(|a| a.schema == schema) .map(|a| { AssetIFA::get_asset_details( + txn, self, a, transfers.clone(), @@ -1938,6 +1939,11 @@ pub trait WalletOffline: WalletBackup { not(any(feature = "electrum", feature = "esplora")), allow(unused_variables) )] + txn: &DbTxn, + #[cfg_attr( + not(any(feature = "electrum", feature = "esplora")), + allow(unused_variables) + )] online: Option, skip_sync: bool, #[cfg_attr( @@ -1963,6 +1969,7 @@ pub trait WalletOffline: WalletBackup { KeychainKind::External => SyncKeychain::Colored, }; self.sync_wallet( + txn, SyncOptions { keychain, strategy: SyncStrategy::FastSync, @@ -1976,16 +1983,17 @@ pub trait WalletOffline: WalletBackup { fn list_transactions_impl( &mut self, + txn: &DbTxn, online: Option, skip_sync: bool, ) -> Result, Error> { - self.sync_if_requested(online, skip_sync, KeychainKind::External)?; - self.sync_if_requested(online, skip_sync, KeychainKind::Internal)?; + self.sync_if_requested(txn, online, skip_sync, KeychainKind::External)?; + self.sync_if_requested(txn, online, skip_sync, KeychainKind::Internal)?; let mut create_utxos_txids = vec![]; let mut drain_txids = vec![]; let mut send_btc_txids = vec![]; - let wallet_transactions = self.database().iter_wallet_transactions()?; + let wallet_transactions = txn.iter_wallet_transactions()?; for tx in wallet_transactions { match tx.r#type { WalletTransactionType::CreateUtxos => create_utxos_txids.push(tx.txid), @@ -1993,8 +2001,7 @@ pub trait WalletOffline: WalletBackup { WalletTransactionType::SendBtc => send_btc_txids.push(tx.txid), } } - let rgb_send_txids: Vec = self - .database() + let rgb_send_txids: Vec = txn .iter_batch_transfers()? .into_iter() .filter_map(|t| t.txid) @@ -2187,8 +2194,12 @@ pub trait WalletOffline: WalletBackup { }) } - fn list_transfers_impl(&self, asset_id: Option) -> Result, Error> { - let db_data = self.database().get_db_data(false)?; + fn list_transfers_impl( + &self, + txn: &DbTxn, + asset_id: Option, + ) -> Result, Error> { + let db_data = txn.get_db_data(false)?; let asset_transfer_ids: Vec = db_data .asset_transfers .iter() @@ -2210,9 +2221,7 @@ pub trait WalletOffline: WalletBackup { &db_data.txos, &db_data.colorings, )?; - let tte_data = self - .database() - .get_transfer_transport_endpoints_data(t.idx)?; + let tte_data = txn.get_transfer_transport_endpoints_data(t.idx)?; let transport_endpoints = tte_data .iter() .map(|(tte, ce)| ce.to_transfer_transport_endpoint(tte)) @@ -2224,16 +2233,17 @@ pub trait WalletOffline: WalletBackup { fn list_unspents_impl( &mut self, + txn: &DbTxn, online: Option, settled_only: bool, skip_sync: bool, ) -> Result, Error> { - self.sync_if_requested(online, skip_sync, KeychainKind::External)?; - self.sync_if_requested(online, skip_sync, KeychainKind::Internal)?; + self.sync_if_requested(txn, online, skip_sync, KeychainKind::External)?; + self.sync_if_requested(txn, online, skip_sync, KeychainKind::Internal)?; - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; - let mut allocation_txos = self.database().get_unspent_txos(db_data.txos.clone())?; + let mut allocation_txos = txn.get_unspent_txos(db_data.txos.clone())?; let spent_txos_ids: Vec = db_data .txos .clone() @@ -2272,7 +2282,7 @@ pub trait WalletOffline: WalletBackup { .collect(); allocation_txos.append(&mut spent_txos); - let mut txos_allocations = self.database().get_rgb_allocations( + let mut txos_allocations = txn.get_rgb_allocations( allocation_txos, Some(db_data.colorings), Some(db_data.batch_transfers), @@ -2391,6 +2401,7 @@ pub trait WalletOffline: WalletBackup { fn inspect_rgb_transfer_impl( &self, + txn: &DbTxn, psbt: String, fascia_path: String, entropy: u64, @@ -2460,7 +2471,7 @@ pub trait WalletOffline: WalletBackup { txid: txid.to_string(), vout, }; - self.database().get_txo(&outpoint).unwrap_or(None).is_some() + txn.get_txo(&outpoint).unwrap_or(None).is_some() } }; for (contract_id, bundle) in fascia.bundles() { @@ -2750,7 +2761,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { /// Return the [`Balance`] for the RGB asset with the provided ID. fn get_asset_balance(&self, asset_id: String) -> Result { info!(self.logger(), "Getting balance for asset '{}'...", asset_id); - let balance = self.get_asset_balance_impl(asset_id)?; + let txn = self.database().begin_transaction()?; + let balance = self.get_asset_balance_impl(&txn, asset_id)?; + txn.commit()?; info!(self.logger(), "Get asset balance completed"); Ok(balance) } @@ -2761,7 +2774,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { self.logger(), "Getting metadata for asset '{}'...", asset_id ); - let metadata = self.get_asset_metadata_impl(asset_id)?; + let txn = self.database().begin_transaction()?; + let metadata = self.get_asset_metadata_impl(&txn, asset_id)?; + txn.commit()?; info!(self.logger(), "Get asset metadata completed"); Ok(metadata) } @@ -2773,7 +2788,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { skip_sync: bool, ) -> Result { info!(self.logger(), "Getting BTC balance..."); - let balance = self.get_btc_balance_impl(online, skip_sync)?; + let txn = self.database().begin_transaction()?; + let balance = self.get_btc_balance_impl(&txn, online, skip_sync)?; + txn.commit()?; info!(self.logger(), "Get BTC balance completed"); Ok(balance) } @@ -2787,7 +2804,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { /// requested. fn list_assets(&self, filter_asset_schemas: Vec) -> Result { info!(self.logger(), "Listing assets..."); - let assets = self.list_assets_impl(filter_asset_schemas)?; + let txn = self.database().begin_transaction()?; + let assets = self.list_assets_impl(&txn, filter_asset_schemas)?; + txn.commit()?; info!(self.logger(), "List assets completed"); Ok(assets) } @@ -2799,7 +2818,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { skip_sync: bool, ) -> Result, Error> { info!(self.logger(), "Listing transactions..."); - let transactions = self.list_transactions_impl(online, skip_sync)?; + let txn = self.database().begin_transaction()?; + let transactions = self.list_transactions_impl(&txn, online, skip_sync)?; + txn.commit()?; info!(self.logger(), "List transactions completed"); Ok(transactions) } @@ -2809,16 +2830,16 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { /// When an `asset_id` is not provided, return transfers that are not connected to a specific /// asset. fn list_transfers(&self, asset_id: Option) -> Result, Error> { + info!( + self.logger(), + "Listing transfers for asset '{:?}'...", asset_id + ); + let txn = self.database().begin_transaction()?; if let Some(asset_id) = &asset_id { - info!( - self.logger(), - "Listing transfers for asset '{}'...", asset_id - ); - self.database().check_asset_exists(asset_id.clone())?; - } else { - info!(self.logger(), "Listing transfers..."); + txn.check_asset_exists(asset_id.clone())?; } - let transfers = self.list_transfers_impl(asset_id)?; + let transfers = self.list_transfers_impl(&txn, asset_id)?; + txn.commit()?; info!(self.logger(), "List transfers completed"); Ok(transfers) } @@ -2834,7 +2855,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { skip_sync: bool, ) -> Result, Error> { info!(self.logger(), "Listing unspents..."); - let unspents = self.list_unspents_impl(online, settled_only, skip_sync)?; + let txn = self.database().begin_transaction()?; + let unspents = self.list_unspents_impl(&txn, online, settled_only, skip_sync)?; + txn.commit()?; info!(self.logger(), "List unspents completed"); Ok(unspents) } @@ -2874,7 +2897,12 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { self.logger(), "Deleting batch transfer with idx {:?}...", batch_transfer_idx ); - let changed = self.delete_transfers_impl(batch_transfer_idx, no_asset_only)?; + let txn = self.database().begin_transaction()?; + let changed = self.delete_transfers_impl(&txn, batch_transfer_idx, no_asset_only)?; + if changed { + self.update_backup_info(&txn, false)?; + } + txn.commit()?; info!(self.logger(), "Delete transfer completed"); Ok(changed) } @@ -2895,7 +2923,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { /// Return whether the wallet requires to perform a backup. fn backup_info(&self) -> Result { info!(self.logger(), "Getting backup info..."); - let backup_required = self.get_backup_info()?; + let txn = self.database().begin_transaction()?; + let backup_required = self.get_backup_info(&txn)?; + txn.commit()?; info!(self.logger(), "Get backup info completed"); Ok(backup_required) } @@ -2917,7 +2947,9 @@ pub trait RgbWalletOpsOffline: WalletOffline + WalletBackup { entropy: u64, ) -> Result { info!(self.logger(), "Inspecting RGB transfer..."); - let inspection = self.inspect_rgb_transfer_impl(psbt, fascia_path, entropy)?; + let txn = self.database().begin_transaction()?; + let inspection = self.inspect_rgb_transfer_impl(&txn, psbt, fascia_path, entropy)?; + txn.commit()?; info!(self.logger(), "RGB transfer inspection completed"); Ok(inspection) } diff --git a/src/wallet/online.rs b/src/wallet/online.rs index 6171768b..299a92c8 100644 --- a/src/wallet/online.rs +++ b/src/wallet/online.rs @@ -40,10 +40,8 @@ pub trait WalletOnline: WalletOffline { Ok(fee_rate) } - fn sync_impl(&mut self, online: Online, options: SyncOptions) -> Result<(), Error> { - self.check_online(online)?; - self.sync_bdk_and_db_txos(options, false)?; - Ok(()) + fn sync_impl(&mut self, txn: &DbTxn, options: SyncOptions) -> Result<(), Error> { + self.sync_bdk_and_db_txos(txn, options, false) } fn broadcast_tx(&self, tx: BdkTransaction) -> Result { @@ -88,7 +86,7 @@ pub trait WalletOnline: WalletOffline { } } - fn broadcast_psbt(&mut self, signed_psbt: &Psbt) -> Result { + fn broadcast_psbt(&mut self, txn: &DbTxn, signed_psbt: &Psbt) -> Result { let tx = self.broadcast_tx( signed_psbt .clone() @@ -105,15 +103,15 @@ pub trait WalletOnline: WalletOffline { // promote any newly-known colored UTXOs (e.g. the change output) from // exists=false to exists=true in the rgb_lib DB - self.update_db_colored_txos_from_bdk(false)?; + self.update_db_colored_txos_from_bdk(txn, false)?; for input in tx.clone().input { let txid = input.previous_output.txid.to_string(); let vout = input.previous_output.vout; - if let Some(db_txo) = self.database().get_txo(&Outpoint { txid, vout })? { + if let Some(db_txo) = txn.get_txo(&Outpoint { txid, vout })? { let mut db_txo: DbTxoActMod = db_txo.into(); db_txo.spent = ActiveValue::Set(true); - self.database().update_txo(db_txo)?; + txn.update_txo(db_txo)?; } } @@ -122,17 +120,16 @@ pub trait WalletOnline: WalletOffline { fn reserve_vanilla_txos( &self, + txn: &DbTxn, psbt: &Psbt, r#type: WalletTransactionType, ) -> Result<(), Error> { let txid = psbt.unsigned_tx.compute_txid().to_string(); - let wt_idx = self - .database() - .set_wallet_transaction(DbWalletTransactionActMod { - txid: ActiveValue::Set(txid), - r#type: ActiveValue::Set(r#type), - ..Default::default() - })?; + let wt_idx = txn.set_wallet_transaction(DbWalletTransactionActMod { + txid: ActiveValue::Set(txid), + r#type: ActiveValue::Set(r#type), + ..Default::default() + })?; let reservations: Vec = psbt .unsigned_tx .input @@ -144,30 +141,27 @@ pub trait WalletOnline: WalletOffline { ..Default::default() }) .collect(); - self.database().set_reserved_txos(reservations)?; + txn.set_reserved_txos(reservations)?; Ok(()) } fn finalize_vanilla_wallet_transaction( &self, + txn: &DbTxn, psbt: &Psbt, r#type: WalletTransactionType, ) -> Result<(), Error> { let txid = psbt.unsigned_tx.compute_txid().to_string(); - match self - .database() - .get_wallet_transaction_with_reserved_txos_by_txid(&txid)? - { + match txn.get_wallet_transaction_with_reserved_txos_by_txid(&txid)? { Some((_wt, reservations)) => { - self.database().del_reserved_txos(&reservations)?; + txn.del_reserved_txos(&reservations)?; } None => { - self.database() - .set_wallet_transaction(DbWalletTransactionActMod { - txid: ActiveValue::Set(txid), - r#type: ActiveValue::Set(r#type), - ..Default::default() - })?; + txn.set_wallet_transaction(DbWalletTransactionActMod { + txid: ActiveValue::Set(txid), + r#type: ActiveValue::Set(r#type), + ..Default::default() + })?; } } Ok(()) @@ -175,11 +169,12 @@ pub trait WalletOnline: WalletOffline { fn broadcast_and_update_rgb( &mut self, + txn: &DbTxn, runtime: &mut RgbRuntime, signed_psbt: &Psbt, fascia: Fascia, ) -> Result { - let tx = self.broadcast_psbt(signed_psbt)?; + let tx = self.broadcast_psbt(txn, signed_psbt)?; runtime.consume_fascia(fascia, None)?; Ok(tx) } @@ -205,6 +200,7 @@ pub trait WalletOnline: WalletOffline { fn create_utxos_begin_impl( &mut self, + txn: &DbTxn, up_to: bool, num: Option, size: Option, @@ -216,6 +212,7 @@ pub trait WalletOnline: WalletOffline { if !skip_sync { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: self.vanilla_sync_lookback(), @@ -226,10 +223,8 @@ pub trait WalletOnline: WalletOffline { )?; } - let unspent_txos = self.database().get_unspent_txos(vec![])?; - let unspents = self - .database() - .get_rgb_allocations(unspent_txos, None, None, None, None)?; + let unspent_txos = txn.get_unspent_txos(vec![])?; + let unspents = txn.get_rgb_allocations(unspent_txos, None, None, None, None)?; let mut utxos_to_create = num.unwrap_or(UTXO_NUM); if up_to { @@ -244,8 +239,10 @@ pub trait WalletOnline: WalletOffline { "Will try to create {} UTXOs", utxos_to_create ); - let reserved: HashSet = - self.get_reserved_vanilla_outpoints()?.into_iter().collect(); + let reserved: HashSet = self + .get_reserved_vanilla_outpoints(txn)? + .into_iter() + .collect(); let (inputs, usable_btc_amount) = self.internal_unspents().fold( (Vec::new(), 0u64), |(mut inputs, usable_btc_amount), u| { @@ -280,7 +277,7 @@ pub trait WalletOnline: WalletOffline { match self.create_split_tx(&inputs, &addresses, utxo_size, fee_rate_checked) { Ok(psbt) => { if !dry_run { - self.reserve_vanilla_txos(&psbt, WalletTransactionType::CreateUtxos)?; + self.reserve_vanilla_txos(txn, &psbt, WalletTransactionType::CreateUtxos)?; } return Ok(psbt); } @@ -309,10 +306,14 @@ pub trait WalletOnline: WalletOffline { }) } - fn create_utxos_end_impl(&mut self, signed_psbt: &Psbt) -> Result { - let tx = self.broadcast_psbt(signed_psbt)?; + fn create_utxos_end_impl(&mut self, txn: &DbTxn, signed_psbt: &Psbt) -> Result { + self.finalize_vanilla_wallet_transaction( + txn, + signed_psbt, + WalletTransactionType::CreateUtxos, + )?; - self.finalize_vanilla_wallet_transaction(signed_psbt, WalletTransactionType::CreateUtxos)?; + let tx = self.broadcast_psbt(txn, signed_psbt)?; let mut num_utxos_created = 0; let bdk_utxos: Vec = self.bdk_wallet().list_unspent().collect(); @@ -328,6 +329,7 @@ pub trait WalletOnline: WalletOffline { fn drain_to_begin_impl( &mut self, + txn: &DbTxn, address: String, fee_rate: u64, dry_run: bool, @@ -335,6 +337,7 @@ pub trait WalletOnline: WalletOffline { let fee_rate_checked = self.check_fee_rate(fee_rate)?; self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -342,6 +345,7 @@ pub trait WalletOnline: WalletOffline { false, )?; self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: self.vanilla_sync_lookback(), @@ -376,15 +380,19 @@ pub trait WalletOnline: WalletOffline { })?; if !dry_run { - self.reserve_vanilla_txos(&psbt, WalletTransactionType::Drain)?; + self.reserve_vanilla_txos(txn, &psbt, WalletTransactionType::Drain)?; } Ok(psbt) } - fn drain_to_end_impl(&mut self, signed_psbt: &Psbt) -> Result { - let tx = self.broadcast_psbt(signed_psbt)?; - self.finalize_vanilla_wallet_transaction(signed_psbt, WalletTransactionType::Drain)?; + fn drain_to_end_impl( + &mut self, + txn: &DbTxn, + signed_psbt: &Psbt, + ) -> Result { + self.finalize_vanilla_wallet_transaction(txn, signed_psbt, WalletTransactionType::Drain)?; + let tx = self.broadcast_psbt(txn, signed_psbt)?; Ok(tx) } @@ -402,48 +410,48 @@ pub trait WalletOnline: WalletOffline { fn fail_batch_transfer( &self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, ) -> Result { self.set_hub_fail_status(batch_transfer.idx)?; let mut updated_batch_transfer: DbBatchTransferActMod = batch_transfer.clone().into(); updated_batch_transfer.status = ActiveValue::Set(TransferStatus::Failed); - Ok(self - .database() - .update_batch_transfer(&mut updated_batch_transfer)?) + txn.update_batch_transfer(&mut updated_batch_transfer) } fn try_fail_batch_transfer( &mut self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, - throw_err: bool, db_data: &mut DbData, - ) -> Result<(), Error> { - let updated_batch_transfer = match self.refresh_transfer(batch_transfer, db_data, &[], true) - { - Err(Error::MinFeeNotMet { txid: _ }) | Err(Error::MaxFeeExceeded { txid: _ }) => { - Ok(None) - } - Err(e) => Err(e), - Ok(v) => Ok(v), - }?; + ) -> Result { + let updated_batch_transfer = + match self.refresh_transfer(txn, batch_transfer, db_data, &[], true) { + Err(Error::MinFeeNotMet { txid: _ }) | Err(Error::MaxFeeExceeded { txid: _ }) => { + Ok(None) + } + Err(e) => Err(e), + Ok(v) => Ok(v), + }?; // fail transfer if the status didn't change after a refresh if updated_batch_transfer.is_none() { - self.fail_batch_transfer(batch_transfer)?; - } else if throw_err { - return Err(Error::CannotFailBatchTransfer); + self.fail_batch_transfer(txn, batch_transfer)?; + Ok(TryFailBatchTransferOutcome::Failed) + } else { + Ok(TryFailBatchTransferOutcome::Refreshed) } - - Ok(()) } fn fail_transfers_impl( &mut self, + txn: &DbTxn, batch_transfer_idx: Option, no_asset_only: bool, skip_sync: bool, - ) -> Result { + ) -> Result { if !skip_sync { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -452,16 +460,19 @@ pub trait WalletOnline: WalletOffline { )?; } - let mut db_data = self.database().get_db_data(false)?; + let mut db_data = txn.get_db_data(false)?; let mut transfers_changed = false; + let mut cannot_fail = false; if let Some(batch_transfer_idx) = batch_transfer_idx { - let batch_transfer = &self - .database() - .get_batch_transfer_or_fail(batch_transfer_idx, &db_data.batch_transfers)?; + let batch_transfer = + txn.get_batch_transfer_or_fail(batch_transfer_idx, &db_data.batch_transfers)?; if !batch_transfer.is_fallible() { - return Err(Error::CannotFailBatchTransfer); + return Ok(FailTransfersOutcome { + transfers_changed: false, + cannot_fail: true, + }); } if no_asset_only { @@ -469,12 +480,19 @@ pub trait WalletOnline: WalletOffline { batch_transfer.get_asset_transfers(&db_data.asset_transfers)?; let connected_assets = asset_transfers.iter().any(|t| t.asset_id.is_some()); if connected_assets { - return Err(Error::CannotFailBatchTransfer); + return Ok(FailTransfersOutcome { + transfers_changed: false, + cannot_fail: true, + }); } } transfers_changed = true; - self.try_fail_batch_transfer(batch_transfer, true, &mut db_data)? + if let TryFailBatchTransferOutcome::Refreshed = + self.try_fail_batch_transfer(txn, &batch_transfer, &mut db_data)? + { + cannot_fail = true; + } } else { // fail all expired transfers that are in a fallible status let now = now().unix_timestamp(); @@ -493,37 +511,36 @@ pub trait WalletOnline: WalletOffline { } } transfers_changed = true; - self.try_fail_batch_transfer(&batch_transfer, false, &mut db_data)? + self.try_fail_batch_transfer(txn, &batch_transfer, &mut db_data)?; } } - if transfers_changed { - self.update_backup_info(false)?; - } - - Ok(transfers_changed) + Ok(FailTransfersOutcome { + transfers_changed, + cannot_fail, + }) } - fn wallet_specific_consistency_checks(&mut self) -> Result<(), Error>; + fn wallet_specific_consistency_checks(&mut self, _txn: &DbTxn) -> Result<(), Error>; - fn check_consistency(&mut self, runtime: &RgbRuntime) -> Result<(), Error> { + fn check_consistency(&mut self, txn: &DbTxn, runtime: &RgbRuntime) -> Result<(), Error> { info!(self.logger(), "Doing a consistency check..."); - self.wallet_specific_consistency_checks()?; + self.wallet_specific_consistency_checks(txn)?; let asset_ids: Vec = runtime .contracts()? .iter() .map(|c| c.id.to_string()) .collect(); - let db_asset_ids: Vec = self.database().get_asset_ids()?; + let db_asset_ids: Vec = txn.get_asset_ids()?; if !db_asset_ids.iter().all(|i| asset_ids.contains(i)) { return Err(Error::Inconsistency { details: s!("DB assets do not match with ones stored in RGB"), }); } - let medias = self.database().iter_media()?; + let medias = txn.iter_media()?; let media_dir = self.media_dir(); for media in medias { if !media_dir.join(media.digest).exists() { @@ -588,8 +605,10 @@ pub trait WalletOnline: WalletOffline { }; if !online_options.skip_consistency_check { + let txn = self.database().begin_transaction()?; let runtime = self.rgb_runtime()?; - self.check_consistency(&runtime)?; + self.check_consistency(&txn, &runtime)?; + txn.commit()?; } Ok(online) @@ -597,6 +616,7 @@ pub trait WalletOnline: WalletOffline { fn get_asset_medias( &self, + txn: &DbTxn, media_idx: Option, token: Option, ) -> Result, Error> { @@ -609,7 +629,7 @@ pub trait WalletOnline: WalletOffline { asset_medias.push(attachment_media); } } else if let Some(media_idx) = media_idx { - let db_media = self.database().get_media(media_idx)?.unwrap(); + let db_media = txn.get_media(media_idx)?.unwrap(); asset_medias.push(Media::from_db_media(&db_media, self.media_dir())) } Ok(asset_medias) @@ -623,11 +643,12 @@ pub trait WalletOnline: WalletOffline { fn fail_batch_transfer_if_no_endpoints( &self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, transfer_transport_endpoints_data: &[(DbTransferTransportEndpoint, DbTransportEndpoint)], ) -> Result, Error> { if transfer_transport_endpoints_data.is_empty() { - Ok(Some(self.fail_batch_transfer(batch_transfer)?)) + Ok(Some(self.fail_batch_transfer(txn, batch_transfer)?)) } else { Ok(None) } @@ -635,6 +656,7 @@ pub trait WalletOnline: WalletOffline { fn refuse_consignment( &self, + txn: &DbTxn, proxy_url: String, recipient_id: String, updated_batch_transfer: &mut DbBatchTransferActMod, @@ -657,10 +679,7 @@ pub trait WalletOnline: WalletOffline { } }; updated_batch_transfer.status = ActiveValue::Set(TransferStatus::Failed); - Ok(Some( - self.database() - .update_batch_transfer(updated_batch_transfer)?, - )) + Ok(Some(txn.update_batch_transfer(updated_batch_transfer)?)) } fn get_consignment( @@ -871,6 +890,7 @@ pub trait WalletOnline: WalletOffline { fn ack_consignment( &self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, recipient_id: String, updated_batch_transfer: &mut DbBatchTransferActMod, @@ -880,7 +900,7 @@ pub trait WalletOnline: WalletOffline { match self.set_hub_accept_status(batch_transfer.idx)? { Some(true) => {} - Some(false) => return Ok(Some(self.fail_batch_transfer(batch_transfer)?)), + Some(false) => return Ok(Some(self.fail_batch_transfer(txn, batch_transfer)?)), None => return Ok(None), } @@ -900,14 +920,12 @@ pub trait WalletOnline: WalletOffline { updated_batch_transfer.status = ActiveValue::Set(TransferStatus::WaitingConfirmations); - Ok(Some( - self.database() - .update_batch_transfer(updated_batch_transfer)?, - )) + Ok(Some(txn.update_batch_transfer(updated_batch_transfer)?)) } fn wait_consignment( &self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, db_data: &DbData, ) -> Result, Error> { @@ -921,11 +939,9 @@ pub trait WalletOnline: WalletOffline { .expect("transfer should have a recipient ID"); debug!(self.logger(), "Recipient ID: {recipient_id}"); - let tte_data = self - .database() - .get_transfer_transport_endpoints_data(transfer.idx)?; + let tte_data = txn.get_transfer_transport_endpoints_data(transfer.idx)?; if let Some(updated_transfer) = - self.fail_batch_transfer_if_no_endpoints(batch_transfer, &tte_data)? + self.fail_batch_transfer_if_no_endpoints(txn, batch_transfer, &tte_data)? { return Ok(Some(updated_transfer)); } @@ -980,8 +996,7 @@ pub trait WalletOnline: WalletOffline { let mut updated_transfer_transport_endpoint: DbTransferTransportEndpointActMod = transfer_transport_endpoint.into(); updated_transfer_transport_endpoint.used = ActiveValue::Set(true); - self.database() - .update_transfer_transport_endpoint(&mut updated_transfer_transport_endpoint)?; + txn.update_transfer_transport_endpoint(&mut updated_transfer_transport_endpoint)?; break; } let (consignment_b64, proxy_url, txid, vout) = if let Some(res) = proxy_res { @@ -998,6 +1013,7 @@ pub trait WalletOnline: WalletOffline { Err(e) => { error!(self.logger(), "Failed to decode consignment bytes: {e}"); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1023,6 +1039,7 @@ pub trait WalletOnline: WalletOffline { Err(e) => { error!(self.logger(), "Failed to load consignment file: {e}"); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1039,7 +1056,12 @@ pub trait WalletOnline: WalletOffline { self.logger(), "The wallet doesn't support the provided schema: {}", asset_schema ); - return self.refuse_consignment(proxy_url, recipient_id, &mut updated_batch_transfer); + return self.refuse_consignment( + txn, + proxy_url, + recipient_id, + &mut updated_batch_transfer, + ); } // check if DB transfer is connected to an asset @@ -1051,6 +1073,7 @@ pub trait WalletOnline: WalletOffline { "Received a different asset than the expected one" ); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1064,6 +1087,7 @@ pub trait WalletOnline: WalletOffline { Err(_) => { error!(self.logger(), "Received an invalid TXID from the proxy"); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1090,6 +1114,7 @@ pub trait WalletOnline: WalletOffline { Err(ValidationError::InvalidConsignment(e)) => { error!(self.logger(), "Consignment is invalid: {}", e); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1116,7 +1141,12 @@ pub trait WalletOnline: WalletOffline { self.logger(), "Cannot find the provided TXID in the consignment" ); - return self.refuse_consignment(proxy_url, recipient_id, &mut updated_batch_transfer); + return self.refuse_consignment( + txn, + proxy_url, + recipient_id, + &mut updated_batch_transfer, + ); }; // check the info provided via the proxy is correct @@ -1132,6 +1162,7 @@ pub trait WalletOnline: WalletOffline { "The provided vout pays an incorrect script pubkey" ); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1140,6 +1171,7 @@ pub trait WalletOnline: WalletOffline { } else { error!(self.logger(), "Cannot find the expected outpoint"); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1148,6 +1180,7 @@ pub trait WalletOnline: WalletOffline { } else { error!(self.logger(), "Consignment is missing the witness TX"); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1159,6 +1192,7 @@ pub trait WalletOnline: WalletOffline { "The vout should be provided when receiving via witness" ); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1181,11 +1215,16 @@ pub trait WalletOnline: WalletOffline { self.extract_received_assignments(&consignment, witness_id, vout, known_concealed); if receiving.is_empty() { error!(self.logger(), "Cannot find any receiving assignment"); - return self.refuse_consignment(proxy_url, recipient_id, &mut updated_batch_transfer); + return self.refuse_consignment( + txn, + proxy_url, + recipient_id, + &mut updated_batch_transfer, + ); }; if asset_schema == AssetSchema::Ifa { - let url = if let Ok(ass) = self.database().check_asset_exists(asset_id.clone()) { + let url = if let Ok(ass) = txn.check_asset_exists(asset_id.clone()) { ass.reject_list_url } else { let contract = IfaWrapper::with(valid_consignment.contract_data()); @@ -1211,6 +1250,7 @@ pub trait WalletOnline: WalletOffline { to_reject.len() ); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1225,11 +1265,7 @@ pub trait WalletOnline: WalletOffline { } if asset_transfer.asset_id.is_none() { - if self - .database() - .check_asset_exists(asset_id.clone()) - .is_err() - { + if txn.check_asset_exists(asset_id.clone()).is_err() { // unknown asset debug!(self.logger(), "Receiving unknown contract..."); let valid_contract = valid_consignment.clone().into_valid_contract(); @@ -1256,6 +1292,7 @@ pub trait WalletOnline: WalletOffline { "Attached file has a different hash than the one in the contract" ); return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1272,6 +1309,7 @@ pub trait WalletOnline: WalletOffline { fs::remove_file(path)?; } return self.refuse_consignment( + txn, proxy_url, recipient_id, &mut updated_batch_transfer, @@ -1285,6 +1323,7 @@ pub trait WalletOnline: WalletOffline { .expect("failure importing received contract"); debug!(self.logger(), "Contract registered"); self.save_new_asset_internal( + txn, &runtime, contract_id, asset_schema, @@ -1296,8 +1335,7 @@ pub trait WalletOnline: WalletOffline { // add asset info to transfer if missing let mut updated_asset_transfer: DbAssetTransferActMod = asset_transfer.clone().into(); updated_asset_transfer.asset_id = ActiveValue::Set(Some(asset_id.clone())); - self.database() - .update_asset_transfer(&mut updated_asset_transfer)?; + txn.update_asset_transfer(&mut updated_asset_transfer)?; } // save validated consignment @@ -1313,16 +1351,13 @@ pub trait WalletOnline: WalletOffline { let utxo_idx = match transfer.recipient_type { Some(RecipientTypeFull::Blind { ref unblinded_utxo }) => { - self.database() - .get_txo(unblinded_utxo)? - .expect("utxo must exist") - .idx + txn.get_txo(unblinded_utxo)?.expect("utxo must exist").idx } Some(RecipientTypeFull::Witness { .. }) => { let mut updated_transfer: DbTransferActMod = transfer.clone().into(); updated_transfer.recipient_type = ActiveValue::Set(Some(RecipientTypeFull::Witness { vout })); - self.database().update_transfer(&mut updated_transfer)?; + txn.update_transfer(&mut updated_transfer)?; let db_utxo = DbTxoActMod { txid: ActiveValue::Set(txid.clone()), vout: ActiveValue::Set(vout.unwrap()), @@ -1332,7 +1367,7 @@ pub trait WalletOnline: WalletOffline { pending_witness: ActiveValue::Set(true), ..Default::default() }; - self.database().set_txo(db_utxo)? + txn.set_txo(db_utxo)? } _ => return Err(InternalError::Unexpected.into()), }; @@ -1344,7 +1379,7 @@ pub trait WalletOnline: WalletOffline { assignment: ActiveValue::Set(assignment), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; } // if the consignment contains unsafe history set status to WaitingSafeHeight and stop here @@ -1358,13 +1393,13 @@ pub trait WalletOnline: WalletOffline { ); updated_batch_transfer.status = ActiveValue::Set(TransferStatus::WaitingSafeHeight); return Ok(Some( - self.database() - .update_batch_transfer(&mut updated_batch_transfer)?, + txn.update_batch_transfer(&mut updated_batch_transfer)?, )); } } self.ack_consignment( + txn, batch_transfer, recipient_id, &mut updated_batch_transfer, @@ -1374,6 +1409,7 @@ pub trait WalletOnline: WalletOffline { fn wait_safe_height( &mut self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, db_data: &mut DbData, ) -> Result, Error> { @@ -1409,14 +1445,13 @@ pub trait WalletOnline: WalletOffline { } let mut updated_batch_transfer: DbBatchTransferActMod = batch_transfer.clone().into(); - let tte_data = self - .database() - .get_transfer_transport_endpoints_data(transfer.idx)?; + let tte_data = txn.get_transfer_transport_endpoints_data(transfer.idx)?; let (_, transport_endpoint) = tte_data .into_iter() .find(|(tte, _)| tte.used) .expect("there should be 1 used TTE"); self.ack_consignment( + txn, batch_transfer, recipient_id, &mut updated_batch_transfer, @@ -1426,6 +1461,7 @@ pub trait WalletOnline: WalletOffline { fn wait_ack( &mut self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, db_data: &mut DbData, ) -> Result, Error> { @@ -1438,11 +1474,9 @@ pub trait WalletOnline: WalletOffline { if transfer.ack.is_some() { continue; } - let tte_data = self - .database() - .get_transfer_transport_endpoints_data(transfer.idx)?; + let tte_data = txn.get_transfer_transport_endpoints_data(transfer.idx)?; if let Some(updated_transfer) = - self.fail_batch_transfer_if_no_endpoints(batch_transfer, &tte_data)? + self.fail_batch_transfer_if_no_endpoints(txn, batch_transfer, &tte_data)? { return Ok(Some(updated_transfer)); } @@ -1467,7 +1501,7 @@ pub trait WalletOnline: WalletOffline { if ack_res.result.is_some() { let mut updated_transfer: DbTransferActMod = transfer.clone().into(); updated_transfer.ack = ActiveValue::Set(ack_res.result); - self.database().update_transfer(&mut updated_transfer)?; + txn.update_transfer(&mut updated_transfer)?; transfer.ack = ack_res.result; } } @@ -1483,18 +1517,19 @@ pub trait WalletOnline: WalletOffline { .iter() .any(|t| t.ack == Some(false)) { - return Ok(Some(self.fail_batch_transfer(batch_transfer).map_err( - |e| match e { - Error::MultisigTransferStatusMismatch => Error::MultisigUnexpectedData { - details: s!("hub reports accepted=true but recipient sent a NACK"), - }, - other => other, - }, - )?)); + return Ok(Some( + self.fail_batch_transfer(txn, batch_transfer) + .map_err(|e| match e { + Error::MultisigTransferStatusMismatch => Error::MultisigUnexpectedData { + details: s!("hub reports accepted=true but recipient sent a NACK"), + }, + other => other, + })?, + )); } else if batch_transfer_transfers.iter().all(|t| t.ack == Some(true)) { match self.set_hub_accept_status(batch_transfer.idx)? { Some(true) => {} - Some(false) => return Ok(Some(self.fail_batch_transfer(batch_transfer)?)), + Some(false) => return Ok(Some(self.fail_batch_transfer(txn, batch_transfer)?)), None => return Ok(None), } let txid = batch_transfer @@ -1507,15 +1542,14 @@ pub trait WalletOnline: WalletOffline { let fascia_path = transfer_dir.join(FASCIA_FILE); let fascia_str = fs::read_to_string(fascia_path)?; let fascia: Fascia = serde_json::from_str(&fascia_str).map_err(InternalError::from)?; - self.broadcast_and_update_rgb(&mut runtime, &signed_psbt, fascia)?; + self.broadcast_and_update_rgb(txn, &mut runtime, &signed_psbt, fascia)?; updated_batch_transfer.status = ActiveValue::Set(TransferStatus::WaitingConfirmations); } else { return Ok(None); } Ok(Some( - self.database() - .update_batch_transfer(&mut updated_batch_transfer)?, + txn.update_batch_transfer(&mut updated_batch_transfer)?, )) } @@ -1538,6 +1572,7 @@ pub trait WalletOnline: WalletOffline { fn wait_confirmations( &mut self, + txn: &DbTxn, batch_transfer: &DbBatchTransfer, db_data: &DbData, incoming: bool, @@ -1575,6 +1610,7 @@ pub trait WalletOnline: WalletOffline { if let Some(RecipientTypeFull::Witness { vout }) = transfer.recipient_type { if !skip_sync { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -1586,10 +1622,10 @@ pub trait WalletOnline: WalletOffline { txid: txid.clone(), vout: vout.unwrap(), }; - let txo = self.database().get_txo(&outpoint)?.expect("txo must exist"); + let txo = txn.get_txo(&outpoint)?.expect("txo must exist"); let mut txo: DbTxoActMod = txo.into(); txo.pending_witness = ActiveValue::Set(false); - self.database().update_txo(txo)?; + txn.update_txo(txo)?; } // accept consignment @@ -1606,7 +1642,7 @@ pub trait WalletOnline: WalletOffline { runtime.contract_wrapper::(contract_id)?; let known_circulating_supply = contract_wrapper.total_issued_supply().into(); let asset_id = asset_transfer.asset_id.unwrap(); - let db_asset = self.database().get_asset(asset_id).unwrap().unwrap(); + let db_asset = txn.get_asset(asset_id).unwrap().unwrap(); let db_known_circulating_supply = db_asset .known_circulating_supply .as_ref() @@ -1617,7 +1653,7 @@ pub trait WalletOnline: WalletOffline { let mut updated_asset: DbAssetActMod = db_asset.into(); updated_asset.known_circulating_supply = ActiveValue::Set(Some(known_circulating_supply.to_string())); - self.database().update_asset(&mut updated_asset)?; + txn.update_asset(&mut updated_asset)?; } } } @@ -1625,26 +1661,27 @@ pub trait WalletOnline: WalletOffline { let mut updated_batch_transfer: DbBatchTransferActMod = batch_transfer.clone().into(); updated_batch_transfer.status = ActiveValue::Set(TransferStatus::Settled); Ok(Some( - self.database() - .update_batch_transfer(&mut updated_batch_transfer)?, + txn.update_batch_transfer(&mut updated_batch_transfer)?, )) } fn wait_counterparty( &mut self, + txn: &DbTxn, transfer: &DbBatchTransfer, db_data: &mut DbData, incoming: bool, ) -> Result, Error> { if incoming { - self.wait_consignment(transfer, db_data) + self.wait_consignment(txn, transfer, db_data) } else { - self.wait_ack(transfer, db_data) + self.wait_ack(txn, transfer, db_data) } } fn refresh_transfer( &mut self, + txn: &DbTxn, transfer: &DbBatchTransfer, db_data: &mut DbData, filter: &[RefreshFilter], @@ -1664,13 +1701,13 @@ pub trait WalletOnline: WalletOffline { match transfer.status { TransferStatus::WaitingCounterparty => { if self.get_hub_fail_status(transfer.idx)? { - return Ok(Some(self.fail_batch_transfer(transfer)?)); + return Ok(Some(self.fail_batch_transfer(txn, transfer)?)); } - self.wait_counterparty(transfer, db_data, incoming) + self.wait_counterparty(txn, transfer, db_data, incoming) } - TransferStatus::WaitingSafeHeight => self.wait_safe_height(transfer, db_data), + TransferStatus::WaitingSafeHeight => self.wait_safe_height(txn, transfer, db_data), TransferStatus::WaitingConfirmations => { - self.wait_confirmations(transfer, db_data, incoming, skip_sync) + self.wait_confirmations(txn, transfer, db_data, incoming, skip_sync) } _ => Ok(None), } @@ -1678,11 +1715,12 @@ pub trait WalletOnline: WalletOffline { fn refresh_impl( &mut self, + txn: &DbTxn, asset_id: Option, filter: Vec, skip_sync: bool, ) -> Result { - let mut db_data = self.database().get_db_data(false)?; + let mut db_data = txn.get_db_data(false)?; if asset_id.is_some() { let batch_transfers_ids: Vec = db_data @@ -1701,7 +1739,7 @@ pub trait WalletOnline: WalletOffline { for transfer in db_data.batch_transfers.clone() { let mut failure = None; let mut updated_status = None; - match self.refresh_transfer(&transfer, &mut db_data, &filter, skip_sync) { + match self.refresh_transfer(txn, &transfer, &mut db_data, &filter, skip_sync) { Ok(Some(updated_transfer)) => updated_status = Some(updated_transfer.status), Err(e) => failure = Some(e), _ => {} @@ -1715,10 +1753,6 @@ pub trait WalletOnline: WalletOffline { ); } - if refresh_result.transfers_changed() { - self.update_backup_info(false)?; - } - Ok(refresh_result) } @@ -1958,6 +1992,7 @@ pub trait WalletOnline: WalletOffline { fn get_change_seal( &self, + txn: &DbTxn, btc_change: &Option, change_utxo_option: &mut Option, input_outpoints: &[Outpoint], @@ -1967,7 +2002,8 @@ pub trait WalletOnline: WalletOffline { GraphSeal::new_random_vout(btc_change.vout) } else { if change_utxo_option.is_none() { - let change_utxo = self.get_utxo(input_outpoints, Some(unspents), true, None)?; + let change_utxo = + self.get_utxo(txn, input_outpoints, Some(unspents), true, None)?; debug!( self.logger(), "Change outpoint '{}'", @@ -2024,6 +2060,7 @@ pub trait WalletOnline: WalletOffline { fn prepare_rgb_psbt( &self, + txn: &DbTxn, psbt: &mut Psbt, transfer_info_map: &mut BTreeMap, transfer_dir: PathBuf, @@ -2157,6 +2194,7 @@ pub trait WalletOnline: WalletOffline { if change != AssignmentsCollection::default() { transfer_info.change = change.clone(); let seal = self.get_change_seal( + txn, &btc_change, &mut change_utxo_option, &input_outpoints, @@ -2236,6 +2274,7 @@ pub trait WalletOnline: WalletOffline { let mut extra_builder = runtime.transition_builder_raw(cid, transition_type)?; let assignment = Assignment::from_opout_and_state(opout, &state); let seal = self.get_change_seal( + txn, &btc_change, &mut change_utxo_option, &input_outpoints, @@ -2492,6 +2531,7 @@ pub trait WalletOnline: WalletOffline { fn save_transfers( &mut self, + txn: &DbTxn, txid: String, info_contents: &InfoBatchTransfer, status: TransferStatus, @@ -2504,11 +2544,11 @@ pub trait WalletOnline: WalletOffline { min_confirmations: ActiveValue::Set(info_contents.min_confirmations), ..Default::default() }; - let batch_transfer_idx = self.database().set_batch_transfer(batch_transfer)?; + let batch_transfer_idx = txn.set_batch_transfer(batch_transfer)?; let change_utxo_idx = if let Some(btc_change) = &info_contents.btc_change { Some( - match self.database().get_txo(&Outpoint { + match txn.get_txo(&Outpoint { txid: txid.clone(), vout: btc_change.vout, })? { @@ -2523,17 +2563,12 @@ pub trait WalletOnline: WalletOffline { pending_witness: ActiveValue::Set(false), ..Default::default() }; - self.database().set_txo(db_utxo)? + txn.set_txo(db_utxo)? } }, ) } else if let Some(outpoint) = &info_contents.change_utxo_outpoint { - Some( - self.database() - .get_txo(outpoint)? - .expect("should exist") - .idx, - ) + Some(txn.get_txo(outpoint)?.expect("should exist").idx) } else { None }; @@ -2545,23 +2580,24 @@ pub trait WalletOnline: WalletOffline { asset_id: ActiveValue::Set(Some(asset_id.clone())), ..Default::default() }; - let asset_transfer_idx = self.database().set_asset_transfer(asset_transfer)?; + let asset_transfer_idx = txn.set_asset_transfer(asset_transfer)?; for (outpoint, assignments) in &transfer_info.assignments_spent { let outpoint: Outpoint = (*outpoint).into(); - let txo_idx = match self.database().get_txo(&outpoint)? { + let txo_idx = match txn.get_txo(&outpoint)? { Some(txo) => txo.idx, None => { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, }, true, )?; - let bdk_utxo = self.database().get_txo(&outpoint)?.expect("should exist"); + let bdk_utxo = txn.get_txo(&outpoint)?.expect("should exist"); let new_db_utxo: DbTxoActMod = bdk_utxo.clone().into(); - self.database().set_txo(new_db_utxo)? + txn.set_txo(new_db_utxo)? } }; @@ -2573,7 +2609,7 @@ pub trait WalletOnline: WalletOffline { assignment: ActiveValue::Set(assignment.clone()), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; } } if transfer_info.change.fungible > 0 { @@ -2586,7 +2622,7 @@ pub trait WalletOnline: WalletOffline { )), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; } if transfer_info.change.inflation > 0 { let db_coloring = DbColoringActMod { @@ -2598,7 +2634,7 @@ pub trait WalletOnline: WalletOffline { )), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; } for recipient in transfer_info.recipients.clone() { @@ -2612,7 +2648,7 @@ pub trait WalletOnline: WalletOffline { unreachable!("inflation uses witness recipients") }; let vout = local_witness_data.vout; - let txo_idx = match self.database().get_txo(&Outpoint { + let txo_idx = match txn.get_txo(&Outpoint { txid: txid.clone(), vout, })? { @@ -2629,7 +2665,7 @@ pub trait WalletOnline: WalletOffline { pending_witness: ActiveValue::Set(false), ..Default::default() }; - self.database().set_txo(db_utxo)? + txn.set_txo(db_utxo)? } }; let db_coloring = DbColoringActMod { @@ -2639,7 +2675,7 @@ pub trait WalletOnline: WalletOffline { assignment: ActiveValue::Set(recipient.assignment.clone()), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; ( Some(recipient.recipient_id.clone()), Some(RecipientTypeFull::Witness { vout: Some(vout) }), @@ -2666,9 +2702,9 @@ pub trait WalletOnline: WalletOffline { recipient_type: ActiveValue::Set(rcpt_type), ..Default::default() }; - let transfer_idx = self.database().set_transfer(transfer)?; + let transfer_idx = txn.set_transfer(transfer)?; for transport_endpoint in recipient.transport_endpoints { - self.save_transfer_transport_endpoint(transfer_idx, &transport_endpoint)?; + self.save_transfer_transport_endpoint(txn, transfer_idx, &transport_endpoint)?; } } } @@ -2680,22 +2716,23 @@ pub trait WalletOnline: WalletOffline { asset_id: ActiveValue::Set(Some(asset_id.clone())), ..Default::default() }; - let asset_transfer_idx = self.database().set_asset_transfer(asset_transfer)?; + let asset_transfer_idx = txn.set_asset_transfer(asset_transfer)?; for (outpoint, assignments) in txo_assignments { let outpoint: Outpoint = (*outpoint).into(); - let input_idx = match self.database().get_txo(&outpoint)? { + let input_idx = match txn.get_txo(&outpoint)? { Some(txo) => txo.idx, None => { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, }, true, )?; - let bdk_utxo = self.database().get_txo(&outpoint)?.expect("should exist"); + let bdk_utxo = txn.get_txo(&outpoint)?.expect("should exist"); let new_db_utxo: DbTxoActMod = bdk_utxo.clone().into(); - self.database().set_txo(new_db_utxo)? + txn.set_txo(new_db_utxo)? } }; for assignment in assignments { @@ -2706,7 +2743,7 @@ pub trait WalletOnline: WalletOffline { assignment: ActiveValue::Set(assignment.clone()), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; let db_coloring = DbColoringActMod { txo_idx: ActiveValue::Set(change_utxo_idx.unwrap()), asset_transfer_idx: ActiveValue::Set(asset_transfer_idx), @@ -2714,7 +2751,7 @@ pub trait WalletOnline: WalletOffline { assignment: ActiveValue::Set(assignment.clone()), ..Default::default() }; - self.database().set_coloring(db_coloring)?; + txn.set_coloring(db_coloring)?; } } } @@ -2724,18 +2761,19 @@ pub trait WalletOnline: WalletOffline { fn update_or_save_transfers( &mut self, + txn: &DbTxn, txid: String, info_contents: &InfoBatchTransfer, status: TransferStatus, sync_tte_used: bool, ) -> Result { - if let Some(existing) = self.database().get_batch_transfer_by_txid(&txid)? { + if let Some(existing) = txn.get_batch_transfer_by_txid(&txid)? { let mut updated: DbBatchTransferActMod = existing.clone().into(); updated.status = ActiveValue::Set(status); - self.database().update_batch_transfer(&mut updated)?; + txn.update_batch_transfer(&mut updated)?; if sync_tte_used { - let asset_transfers = self.database().iter_asset_transfers()?; - let transfers = self.database().iter_transfers()?; + let asset_transfers = txn.iter_asset_transfers()?; + let transfers = txn.iter_transfers()?; let batch_data = existing.get_transfers(&asset_transfers, &transfers)?; for asset_transfer_data in &batch_data.asset_transfers_data { let asset_id = asset_transfer_data @@ -2755,9 +2793,8 @@ pub trait WalletOnline: WalletOffline { db_transfer.recipient_id.as_deref() == Some(r.recipient_id.as_str()) }) .expect("recipient should be set"); - let tte_data = self - .database() - .get_transfer_transport_endpoints_data(db_transfer.idx)?; + let tte_data = + txn.get_transfer_transport_endpoints_data(db_transfer.idx)?; for (tte, te) in tte_data { let local_used = recipient .transport_endpoints @@ -2767,8 +2804,7 @@ pub trait WalletOnline: WalletOffline { if tte.used != local_used { let mut updated_tte: DbTransferTransportEndpointActMod = tte.into(); updated_tte.used = ActiveValue::Set(local_used); - self.database() - .update_transfer_transport_endpoint(&mut updated_tte)?; + txn.update_transfer_transport_endpoint(&mut updated_tte)?; } } } @@ -2776,7 +2812,7 @@ pub trait WalletOnline: WalletOffline { } Ok(existing.idx) } else { - self.save_transfers(txid, info_contents, status) + self.save_transfers(txn, txid, info_contents, status) } } @@ -2804,15 +2840,16 @@ pub trait WalletOnline: WalletOffline { fn get_transfer_begin_data( &mut self, + txn: &DbTxn, fee_rate: u64, ) -> Result<(FeeRate, Vec, Vec, RgbRuntime), Error> { let fee_rate_checked = self.check_fee_rate(fee_rate)?; - let db_data = self.database().get_db_data(false)?; + let db_data = txn.get_db_data(false)?; - let utxos = self.database().get_unspent_txos(db_data.txos.clone())?; + let utxos = txn.get_unspent_txos(db_data.txos.clone())?; - let unspents = self.database().get_rgb_allocations( + let unspents = txn.get_rgb_allocations( utxos, Some(db_data.colorings.clone()), Some(db_data.batch_transfers.clone()), @@ -2848,6 +2885,7 @@ pub trait WalletOnline: WalletOffline { fn prepare_transfer_psbt( &mut self, + txn: &DbTxn, transfer_info_map: &mut BTreeMap, transfer_dir: PathBuf, donation: bool, @@ -2881,6 +2919,7 @@ pub trait WalletOnline: WalletOffline { // prepare RGB PSBT let begin_operation_data = match self.prepare_rgb_psbt( + txn, &mut psbt, transfer_info_map, transfer_dir.clone(), @@ -2913,6 +2952,7 @@ pub trait WalletOnline: WalletOffline { if !dry_run { // save transfer to DB with Initiated status to reserve the UTXOs let batch_transfer_idx = self.save_transfers( + txn, txid, &begin_operation_data.info_batch_transfer, TransferStatus::Initiated, @@ -2925,6 +2965,7 @@ pub trait WalletOnline: WalletOffline { fn finalize_transfer_end( &mut self, + txn: &DbTxn, txid: String, psbt: &Psbt, info_contents: &InfoBatchTransfer, @@ -2933,12 +2974,13 @@ pub trait WalletOnline: WalletOffline { sync_tte_used: bool, ) -> Result { let mut runtime = self.rgb_runtime()?; - self.broadcast_and_update_rgb(&mut runtime, psbt, fascia)?; - self.update_or_save_transfers(txid, info_contents, status, sync_tte_used) + self.broadcast_and_update_rgb(txn, &mut runtime, psbt, fascia)?; + self.update_or_save_transfers(txn, txid, info_contents, status, sync_tte_used) } fn send_begin_impl( &mut self, + txn: &DbTxn, recipient_map: HashMap>, donation: bool, fee_rate: u64, @@ -2951,7 +2993,7 @@ pub trait WalletOnline: WalletOffline { } let (fee_rate_checked, unspents, input_unspents, mut runtime) = - self.get_transfer_begin_data(fee_rate)?; + self.get_transfer_begin_data(txn, fee_rate)?; let chainnet: ChainNet = self.bitcoin_network().into(); let mut witness_recipients: Vec<(ScriptBuf, u64)> = vec![]; @@ -2960,7 +3002,7 @@ pub trait WalletOnline: WalletOffline { let mut assets_data: BTreeMap = BTreeMap::new(); let mut local_recipients: BTreeMap> = BTreeMap::new(); for (asset_id, recipients) in &recipient_map { - let asset = self.database().check_asset_exists(asset_id.clone())?; + let asset = txn.check_asset_exists(asset_id.clone())?; let schema = asset.schema; self.check_schema_support(&schema)?; @@ -3116,6 +3158,7 @@ pub trait WalletOnline: WalletOffline { } match self.prepare_transfer_psbt( + txn, &mut transfer_info_map, transfer_dir.clone(), donation, @@ -3137,7 +3180,7 @@ pub trait WalletOnline: WalletOffline { }) } - fn send_end_impl(&mut self, signed_psbt: &Psbt) -> Result { + fn send_end_impl(&mut self, txn: &DbTxn, signed_psbt: &Psbt) -> Result { let (txid, transfer_dir, mut info_contents, fascia) = self.get_transfer_end_data(signed_psbt)?; @@ -3150,13 +3193,13 @@ pub trait WalletOnline: WalletOffline { let mut tokens = None; let mut token_medias = None; for (asset_id, info_contents_asset) in info_contents.transfers.iter_mut() { - let asset = self.database().get_asset(asset_id.clone())?.unwrap(); + let asset = txn.get_asset(asset_id.clone())?.unwrap(); let token = match asset.schema { AssetSchema::Uda => { if medias.clone().is_none() { - medias = Some(self.database().iter_media()?); - tokens = Some(self.database().iter_tokens()?); - token_medias = Some(self.database().iter_token_medias()?); + medias = Some(txn.iter_media()?); + tokens = Some(txn.iter_tokens()?); + token_medias = Some(txn.iter_token_medias()?); } self.get_asset_token( asset.idx, @@ -3174,13 +3217,14 @@ pub trait WalletOnline: WalletOffline { &mut info_contents_asset.recipients, asset_transfer_dir, txid.clone(), - self.get_asset_medias(asset.media_idx, token)?, + self.get_asset_medias(txn, asset.media_idx, token)?, )?; } let sync_tte_used = true; let batch_transfer_idx = if info_contents.donation { self.finalize_transfer_end( + txn, txid.clone(), signed_psbt, &info_contents, @@ -3190,6 +3234,7 @@ pub trait WalletOnline: WalletOffline { )? } else { self.update_or_save_transfers( + txn, txid.clone(), &info_contents, TransferStatus::WaitingCounterparty, @@ -3206,6 +3251,7 @@ pub trait WalletOnline: WalletOffline { fn send_btc_begin_impl( &mut self, + txn: &DbTxn, address: String, amount: u64, fee_rate: u64, @@ -3216,6 +3262,7 @@ pub trait WalletOnline: WalletOffline { if !skip_sync { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: self.vanilla_sync_lookback(), @@ -3228,7 +3275,7 @@ pub trait WalletOnline: WalletOffline { let script_pubkey = self.get_script_pubkey(&address)?; - let unspendable = self.get_unspendable_bdk_outpoints()?; + let unspendable = self.get_unspendable_bdk_outpoints(txn)?; let mut tx_builder = self.bdk_wallet_mut().build_tx(); tx_builder @@ -3252,27 +3299,28 @@ pub trait WalletOnline: WalletOffline { })?; if !dry_run { - self.reserve_vanilla_txos(&psbt, WalletTransactionType::SendBtc)?; + self.reserve_vanilla_txos(txn, &psbt, WalletTransactionType::SendBtc)?; } Ok(psbt) } - fn send_btc_end_impl(&mut self, signed_psbt: &Psbt) -> Result { - let tx = self.broadcast_psbt(signed_psbt)?; - self.finalize_vanilla_wallet_transaction(signed_psbt, WalletTransactionType::SendBtc)?; + fn send_btc_end_impl(&mut self, txn: &DbTxn, signed_psbt: &Psbt) -> Result { + let tx = self.broadcast_psbt(txn, signed_psbt)?; + self.finalize_vanilla_wallet_transaction(txn, signed_psbt, WalletTransactionType::SendBtc)?; Ok(tx.compute_txid().to_string()) } fn inflate_begin_impl( &mut self, + txn: &DbTxn, asset_id: String, inflation_amounts: Vec, fee_rate: u64, min_confirmations: u8, dry_run: bool, ) -> Result { - let asset = self.database().check_asset_exists(asset_id.clone())?; + let asset = txn.check_asset_exists(asset_id.clone())?; let schema = asset.schema; self.check_schema_support(&schema)?; if !SCHEMAS_SUPPORTING_INFLATION.contains(&schema) { @@ -3293,7 +3341,7 @@ pub trait WalletOnline: WalletOffline { } let (fee_rate_checked, unspents, input_unspents, mut runtime) = - self.get_transfer_begin_data(fee_rate)?; + self.get_transfer_begin_data(txn, fee_rate)?; let assignments_needed = AssignmentsCollection { inflation, @@ -3365,6 +3413,7 @@ pub trait WalletOnline: WalletOffline { let mut rejected = HashSet::new(); Ok( match self.prepare_transfer_psbt( + txn, &mut transfer_info_map, transfer_dir.clone(), false, @@ -3386,11 +3435,16 @@ pub trait WalletOnline: WalletOffline { ) } - fn inflate_end_impl(&mut self, signed_psbt: &Psbt) -> Result { + fn inflate_end_impl( + &mut self, + txn: &DbTxn, + signed_psbt: &Psbt, + ) -> Result { let (txid, _transfer_dir, info_contents, fascia) = self.get_transfer_end_data(signed_psbt)?; let batch_transfer_idx = self.finalize_transfer_end( + txn, txid.clone(), signed_psbt, &info_contents, @@ -3401,7 +3455,7 @@ pub trait WalletOnline: WalletOffline { let (asset_id, transfer_info) = info_contents.transfers.into_iter().next().unwrap(); let inflation = transfer_info.original_assignments_needed.inflation; - let db_asset = self.database().get_asset(asset_id).unwrap().unwrap(); + let db_asset = txn.get_asset(asset_id).unwrap().unwrap(); let updated_known_circulating_supply = db_asset .known_circulating_supply .as_ref() @@ -3412,7 +3466,7 @@ pub trait WalletOnline: WalletOffline { let mut updated_asset: DbAssetActMod = db_asset.into(); updated_asset.known_circulating_supply = ActiveValue::Set(Some(updated_known_circulating_supply.to_string())); - self.database().update_asset(&mut updated_asset)?; + txn.update_asset(&mut updated_asset)?; Ok(OperationResult { txid, @@ -3423,13 +3477,14 @@ pub trait WalletOnline: WalletOffline { fn burn_begin_impl( &mut self, + txn: &DbTxn, asset_id: String, amount: u64, fee_rate: u64, min_confirmations: u8, dry_run: bool, ) -> Result { - let asset = self.database().check_asset_exists(asset_id.clone())?; + let asset = txn.check_asset_exists(asset_id.clone())?; let schema = asset.schema; self.check_schema_support(&schema)?; if !SCHEMAS_SUPPORTING_BURN.contains(&schema) { @@ -3443,7 +3498,7 @@ pub trait WalletOnline: WalletOffline { } let (fee_rate_checked, unspents, input_unspents, mut runtime) = - self.get_transfer_begin_data(fee_rate)?; + self.get_transfer_begin_data(txn, fee_rate)?; let assignments_needed = AssignmentsCollection { fungible: amount, @@ -3508,6 +3563,7 @@ pub trait WalletOnline: WalletOffline { let mut rejected = HashSet::new(); Ok( match self.prepare_transfer_psbt( + txn, &mut transfer_info_map, transfer_dir.clone(), false, @@ -3529,11 +3585,12 @@ pub trait WalletOnline: WalletOffline { ) } - fn burn_end_impl(&mut self, signed_psbt: &Psbt) -> Result { + fn burn_end_impl(&mut self, txn: &DbTxn, signed_psbt: &Psbt) -> Result { let (txid, _transfer_dir, info_contents, fascia) = self.get_transfer_end_data(signed_psbt)?; let batch_transfer_idx = self.finalize_transfer_end( + txn, txid.clone(), signed_psbt, &info_contents, @@ -3578,9 +3635,18 @@ pub trait RgbWalletOpsOnline: RgbWalletOpsOffline + WalletOnline { "Failing batch transfer with idx {:?}...", batch_transfer_idx ); self.check_online(online)?; - let changed = self.fail_transfers_impl(batch_transfer_idx, no_asset_only, skip_sync)?; + let txn = self.database().begin_transaction()?; + let outcome = + self.fail_transfers_impl(&txn, batch_transfer_idx, no_asset_only, skip_sync)?; + if outcome.transfers_changed { + self.update_backup_info(&txn, false)?; + } + txn.commit()?; info!(self.logger(), "Fail transfers completed"); - Ok(changed) + if outcome.cannot_fail { + return Err(Error::CannotFailBatchTransfer); + } + Ok(outcome.transfers_changed) } /// Sync the wallet and save new colored UTXOs to the DB. @@ -3590,7 +3656,10 @@ pub trait RgbWalletOpsOnline: RgbWalletOpsOffline + WalletOnline { /// Callers that want both keychains synced must invoke this method once per keychain. fn sync(&mut self, online: Online, options: SyncOptions) -> Result<(), Error> { info!(self.logger(), "Syncing..."); - self.sync_impl(online, options)?; + self.check_online(online)?; + let txn = self.database().begin_transaction()?; + self.sync_impl(&txn, options)?; + txn.commit()?; info!(self.logger(), "Sync completed"); Ok(()) } @@ -3621,14 +3690,17 @@ pub trait RgbWalletOpsOnline: RgbWalletOpsOffline + WalletOnline { filter: Vec, skip_sync: bool, ) -> Result { - if let Some(aid) = asset_id.clone() { - info!(self.logger(), "Refreshing asset {}...", aid); - self.database().check_asset_exists(aid)?; - } else { - info!(self.logger(), "Refreshing assets..."); - } + info!(self.logger(), "Refreshing asset {:?}...", asset_id); self.check_online(online)?; - let res = self.refresh_impl(asset_id, filter, skip_sync)?; + let txn = self.database().begin_transaction()?; + if let Some(aid) = &asset_id { + txn.check_asset_exists(aid.clone())?; + } + let res = self.refresh_impl(&txn, asset_id, filter, skip_sync)?; + if res.transfers_changed() { + self.update_backup_info(&txn, false)?; + } + txn.commit()?; info!(self.logger(), "Refresh completed"); Ok(res) } diff --git a/src/wallet/rust_only.rs b/src/wallet/rust_only.rs index f18d78bc..56132f0d 100644 --- a/src/wallet/rust_only.rs +++ b/src/wallet/rust_only.rs @@ -500,15 +500,17 @@ impl Wallet { .expect("valid consignment"); let valid_contract = valid_transfer.clone().into_valid_contract(); + let txn = self.database().begin_transaction()?; self.save_new_asset_internal( + &txn, &runtime, contract_id, asset_schema, valid_contract, Some(valid_transfer), )?; - - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Save new asset completed"); Ok(()) @@ -527,7 +529,9 @@ impl Wallet { skip_sync: bool, ) -> Result, Error> { info!(self.logger(), "Listing unspents vanilla..."); - self.sync_if_requested(Some(online), skip_sync, KeychainKind::Internal)?; + let txn = self.database().begin_transaction()?; + self.sync_if_requested(&txn, Some(online), skip_sync, KeychainKind::Internal)?; + txn.commit()?; let unspents = self.internal_unspents(); diff --git a/src/wallet/singlesig.rs b/src/wallet/singlesig.rs index df6978ac..f6050bde 100644 --- a/src/wallet/singlesig.rs +++ b/src/wallet/singlesig.rs @@ -115,8 +115,9 @@ impl WalletOffline for Wallet {} #[cfg(any(feature = "electrum", feature = "esplora"))] impl WalletOnline for Wallet { - fn wallet_specific_consistency_checks(&mut self) -> Result<(), Error> { + fn wallet_specific_consistency_checks(&mut self, txn: &DbTxn) -> Result<(), Error> { self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FullScan, @@ -124,6 +125,7 @@ impl WalletOnline for Wallet { false, )?; self.sync_wallet( + txn, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: self.vanilla_sync_lookback(), @@ -138,8 +140,7 @@ impl WalletOnline for Wallet { .map(|u| u.outpoint.to_string()) .collect(); let bdk_utxos: HashSet = HashSet::from_iter(bdk_utxos); - let db_utxos: Vec = self - .database() + let db_utxos: Vec = txn .iter_txos()? .into_iter() .filter(|t| !t.spent && t.exists) @@ -251,11 +252,10 @@ impl Wallet { /// Return a new Bitcoin address from the vanilla wallet. pub fn get_address(&mut self) -> Result { info!(self.logger(), "Getting address..."); - let address = self.get_new_addresses(KeychainKind::Internal, 1)?; - - self.update_backup_info(false)?; - + let txn = self.database().begin_transaction()?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Get address completed"); Ok(address.to_string()) } @@ -268,26 +268,26 @@ impl Wallet { /// [`abort_pending_vanilla_tx`](Wallet::abort_pending_vanilla_tx). pub fn list_pending_vanilla_txs(&self) -> Result, Error> { info!(self.logger(), "Listing pending vanilla TXs..."); - let reserved_idxs: Vec = self - .database() + let txn = self.database().begin_transaction()?; + let reserved_idxs: Vec = txn .iter_reserved_txos()? .into_iter() .filter_map(|r| r.reserved_for) .collect::>() .into_iter() .collect(); - if reserved_idxs.is_empty() { - return Ok(vec![]); - } - let result = self - .database() - .get_wallet_transactions_by_idxs(&reserved_idxs)? - .into_iter() - .map(|wt| PendingVanillaTx { - txid: wt.txid, - r#type: wt.r#type, - }) - .collect(); + let result = if reserved_idxs.is_empty() { + vec![] + } else { + txn.get_wallet_transactions_by_idxs(&reserved_idxs)? + .into_iter() + .map(|wt| PendingVanillaTx { + txid: wt.txid, + r#type: wt.r#type, + }) + .collect() + }; + txn.commit()?; info!(self.logger(), "List pending vanilla TXs completed"); Ok(result) } @@ -299,26 +299,29 @@ impl Wallet { /// aborted or has been broadcast). pub fn abort_pending_vanilla_tx(&self, txid: String) -> Result<(), Error> { info!(self.logger(), "Aborting pending vanilla TX {}...", txid); - let (wt, reservations) = self - .database() + let txn = self.database().begin_transaction()?; + let (wt, reservations) = txn .get_wallet_transaction_with_reserved_txos_by_txid(&txid)? .ok_or(Error::CannotAbortPendingVanillaTx)?; if reservations.is_empty() { return Err(Error::CannotAbortPendingVanillaTx); } - self.database().del_wallet_transaction(wt.idx)?; // relies on cascade to delete reserved txos + txn.del_wallet_transaction(wt.idx)?; // relies on cascade to delete reserved txos + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Abort pending vanilla TX completed"); Ok(()) } fn finalize_offline_issuance( &self, + txn: &DbTxn, issue_data: &IssueData, ) -> Result { let mut runtime = self.rgb_runtime()?; - let asset = self.import_and_save_contract(issue_data, &mut runtime)?; - let result = T::from_issuance(self, &asset, issue_data)?; - self.update_backup_info(false)?; + let asset = self.import_and_save_contract(txn, issue_data, &mut runtime)?; + let result = T::from_issuance(txn, self, &asset, issue_data)?; + self.update_backup_info(txn, false)?; Ok(result) } @@ -337,9 +340,13 @@ impl Wallet { precision: u8, amounts: Vec, ) -> Result { - self.issue_asset_nia_with_impl(ticker, name, precision, amounts, |issue_data| { - self.finalize_offline_issuance(&issue_data) - }) + let txn = self.database().begin_transaction()?; + let res = + self.issue_asset_nia_with_impl(&txn, ticker, name, precision, amounts, |issue_data| { + self.finalize_offline_issuance(&txn, &issue_data) + })?; + txn.commit()?; + Ok(res) } /// Issue a new RGB UDA asset with the provided `ticker`, `name`, optional `details` and @@ -359,7 +366,9 @@ impl Wallet { media_file_path: Option, attachments_file_paths: Vec, ) -> Result { - self.issue_asset_uda_with_impl( + let txn = self.database().begin_transaction()?; + let res = self.issue_asset_uda_with_impl( + &txn, ticker, name, details, @@ -368,8 +377,9 @@ impl Wallet { attachments_file_paths, |issue_data| { let mut runtime = self.rgb_runtime()?; - let asset = self.import_and_save_contract(&issue_data, &mut runtime)?; + let asset = self.import_and_save_contract(&txn, &issue_data, &mut runtime)?; let asset_uda = AssetUDA::get_asset_details( + &txn, self, &asset, issue_data.asset_data.token.map(|t| t.into()), @@ -380,10 +390,12 @@ impl Wallet { None, None, )?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; Ok(asset_uda) }, - ) + )?; + txn.commit()?; + Ok(res) } /// Issue a new RGB CFA asset with the provided `name`, optional `details`, `precision` and @@ -405,9 +417,18 @@ impl Wallet { amounts: Vec, file_path: Option, ) -> Result { - self.issue_asset_cfa_with_impl(name, details, precision, amounts, file_path, |issue_data| { - self.finalize_offline_issuance(&issue_data) - }) + let txn = self.database().begin_transaction()?; + let res = self.issue_asset_cfa_with_impl( + &txn, + name, + details, + precision, + amounts, + file_path, + |issue_data| self.finalize_offline_issuance(&txn, &issue_data), + )?; + txn.commit()?; + Ok(res) } /// Issue a new RGB IFA asset with the provided `ticker`, `name`, `precision`, `amounts` and @@ -430,15 +451,19 @@ impl Wallet { inflation_amounts: Vec, reject_list_url: Option, ) -> Result { - self.issue_asset_ifa_with_impl( + let txn = self.database().begin_transaction()?; + let res = self.issue_asset_ifa_with_impl( + &txn, ticker, name, precision, amounts, inflation_amounts, reject_list_url, - |issue_data| self.finalize_offline_issuance(&issue_data), - ) + |issue_data| self.finalize_offline_issuance(&txn, &issue_data), + )?; + txn.commit()?; + Ok(res) } /// Blind an UTXO to receive RGB assets and return the resulting [`ReceiveData`]. @@ -477,20 +502,19 @@ impl Wallet { asset_id, expiration_timestamp, ); - + let txn = self.database().begin_transaction()?; let receive_data_internal = self.create_receive_data( + &txn, asset_id, assignment, expiration_timestamp.map(|t| t as i64), transport_endpoints, RecipientType::Blind, )?; - let batch_transfer_idx = - self.store_receive_transfer(&receive_data_internal, min_confirmations)?; - - self.update_backup_info(false)?; - + self.store_receive_transfer(&txn, &receive_data_internal, min_confirmations)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Blind receive completed"); Ok(ReceiveData { invoice: receive_data_internal.invoice_string, @@ -536,20 +560,19 @@ impl Wallet { asset_id, expiration_timestamp, ); - + let txn = self.database().begin_transaction()?; let receive_data_internal = self.create_receive_data( + &txn, asset_id, assignment, expiration_timestamp.map(|t| t as i64), transport_endpoints, RecipientType::Witness, )?; - let batch_transfer_idx = - self.store_receive_transfer(&receive_data_internal, min_confirmations)?; - - self.update_backup_info(false)?; - + self.store_receive_transfer(&txn, &receive_data_internal, min_confirmations)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Witness receive completed"); Ok(ReceiveData { invoice: receive_data_internal.invoice_string, @@ -593,10 +616,13 @@ impl Wallet { info!(self.logger(), "Creating UTXOs..."); self.check_xprv()?; self.check_online(online)?; - let mut psbt = self.create_utxos_begin_impl(up_to, num, size, fee_rate, skip_sync, true)?; + let txn = self.database().begin_transaction()?; + let mut psbt = + self.create_utxos_begin_impl(&txn, up_to, num, size, fee_rate, skip_sync, true)?; self.sign_psbt_impl(&mut psbt, None)?; - let res = self.create_utxos_end_impl(&psbt)?; - self.update_backup_info(false)?; + let res = self.create_utxos_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Create UTXOs completed"); Ok(res) } @@ -640,7 +666,10 @@ impl Wallet { ) -> Result { info!(self.logger(), "Creating UTXOs (begin)..."); self.check_online(online)?; - let res = self.create_utxos_begin_impl(up_to, num, size, fee_rate, skip_sync, dry_run)?; + let txn = self.database().begin_transaction()?; + let res = + self.create_utxos_begin_impl(&txn, up_to, num, size, fee_rate, skip_sync, dry_run)?; + txn.commit()?; info!(self.logger(), "Create UTXOs (begin) completed"); Ok(res.to_string()) } @@ -657,7 +686,9 @@ impl Wallet { info!(self.logger(), "Creating UTXOs (end)..."); self.check_online(online)?; let psbt = Psbt::from_str(&signed_psbt)?; - let res = self.create_utxos_end_impl(&psbt)?; + let txn = self.database().begin_transaction()?; + let res = self.create_utxos_end_impl(&txn, &psbt)?; + txn.commit()?; info!(self.logger(), "Create UTXOs (end) completed"); Ok(res) } @@ -687,10 +718,12 @@ impl Wallet { info!(self.logger(), "Draining to '{}'...", address); self.check_xprv()?; self.check_online(online)?; - let mut psbt = self.drain_to_begin_impl(address, fee_rate, true)?; + let txn = self.database().begin_transaction()?; + let mut psbt = self.drain_to_begin_impl(&txn, address, fee_rate, true)?; self.sign_psbt_impl(&mut psbt, None)?; - let tx = self.drain_to_end_impl(&psbt)?; - self.update_backup_info(false)?; + let tx = self.drain_to_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Drain completed"); Ok(tx.compute_txid().to_string()) } @@ -721,7 +754,9 @@ impl Wallet { ) -> Result { info!(self.logger(), "Draining (begin) to '{}'...", address); self.check_online(online)?; - let psbt = self.drain_to_begin_impl(address, fee_rate, dry_run)?; + let txn = self.database().begin_transaction()?; + let psbt = self.drain_to_begin_impl(&txn, address, fee_rate, dry_run)?; + txn.commit()?; info!(self.logger(), "Drain (begin) completed"); Ok(psbt.to_string()) } @@ -738,8 +773,10 @@ impl Wallet { info!(self.logger(), "Draining (end)..."); self.check_online(online)?; let psbt = Psbt::from_str(&signed_psbt)?; - let tx = self.drain_to_end_impl(&psbt)?; - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + let tx = self.drain_to_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Drain (end) completed"); Ok(tx.compute_txid().to_string()) } @@ -762,7 +799,9 @@ impl Wallet { info!(self.logger(), "Sending to: {:?}...", recipient_map); self.check_xprv()?; self.check_online(online)?; + let txn = self.database().begin_transaction()?; let mut begin_op_data = self.send_begin_impl( + &txn, recipient_map, donation, fee_rate, @@ -771,8 +810,9 @@ impl Wallet { true, )?; self.sign_psbt_impl(&mut begin_op_data.psbt, None)?; - let res = self.send_end_impl(&begin_op_data.psbt)?; - self.update_backup_info(false)?; + let res = self.send_end_impl(&txn, &begin_op_data.psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Send completed"); Ok(res) } @@ -826,7 +866,9 @@ impl Wallet { ) -> Result { info!(self.logger(), "Sending (begin) to: {:?}...", recipient_map); self.check_online(online)?; + let txn = self.database().begin_transaction()?; let begin_op_data = self.send_begin_impl( + &txn, recipient_map, donation, fee_rate, @@ -834,7 +876,8 @@ impl Wallet { expiration_timestamp.map(|t| t as i64), dry_run, )?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Send (begin) completed"); Ok(SendBeginResult { psbt: begin_op_data.psbt.to_string(), @@ -869,8 +912,10 @@ impl Wallet { info!(self.logger(), "Sending (end)..."); self.check_online(online)?; let psbt = Psbt::from_str(&signed_psbt)?; - let res = self.send_end_impl(&psbt)?; - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + let res = self.send_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Send (end) completed"); Ok(res) } @@ -892,9 +937,12 @@ impl Wallet { info!(self.logger(), "Sending BTC..."); self.check_xprv()?; self.check_online(online)?; - let mut psbt = self.send_btc_begin_impl(address, amount, fee_rate, skip_sync, true)?; + let txn = self.database().begin_transaction()?; + let mut psbt = + self.send_btc_begin_impl(&txn, address, amount, fee_rate, skip_sync, true)?; self.sign_psbt_impl(&mut psbt, None)?; - let res = self.send_btc_end_impl(&psbt)?; + let res = self.send_btc_end_impl(&txn, &psbt)?; + txn.commit()?; info!(self.logger(), "Send BTC completed"); Ok(res) } @@ -923,7 +971,9 @@ impl Wallet { ) -> Result { info!(self.logger(), "Sending BTC (begin)..."); self.check_online(online)?; - let res = self.send_btc_begin_impl(address, amount, fee_rate, skip_sync, dry_run)?; + let txn = self.database().begin_transaction()?; + let res = self.send_btc_begin_impl(&txn, address, amount, fee_rate, skip_sync, dry_run)?; + txn.commit()?; info!(self.logger(), "Send BTC (begin) completed"); Ok(res.to_string()) } @@ -940,7 +990,9 @@ impl Wallet { info!(self.logger(), "Sending BTC (end)..."); self.check_online(online)?; let psbt = Psbt::from_str(&signed_psbt)?; - let res = self.send_btc_end_impl(&psbt)?; + let txn = self.database().begin_transaction()?; + let res = self.send_btc_end_impl(&txn, &psbt)?; + txn.commit()?; info!(self.logger(), "Send BTC (end) completed"); Ok(res) } @@ -965,7 +1017,9 @@ impl Wallet { ); self.check_xprv()?; self.check_online(online)?; + let txn = self.database().begin_transaction()?; let mut begin_op_data = self.inflate_begin_impl( + &txn, asset_id, inflation_amounts, fee_rate, @@ -973,8 +1027,9 @@ impl Wallet { true, )?; self.sign_psbt_impl(&mut begin_op_data.psbt, None)?; - let res = self.inflate_end_impl(&begin_op_data.psbt)?; - self.update_backup_info(false)?; + let res = self.inflate_end_impl(&txn, &begin_op_data.psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Inflate completed"); Ok(res) } @@ -1016,14 +1071,17 @@ impl Wallet { "Inflating (begin) amounts: {:?}...", inflation_amounts ); self.check_online(online)?; + let txn = self.database().begin_transaction()?; let begin_operation_data = self.inflate_begin_impl( + &txn, asset_id, inflation_amounts, fee_rate, min_confirmations, dry_run, )?; - self.update_backup_info(false)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Inflate (begin) completed"); Ok(InflateBeginResult { psbt: begin_operation_data.psbt.to_string(), @@ -1057,8 +1115,10 @@ impl Wallet { info!(self.logger(), "Inflating (end)..."); self.check_online(online)?; let psbt = Psbt::from_str(&signed_psbt)?; - let res = self.inflate_end_impl(&psbt)?; - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + let res = self.inflate_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Inflate (end) completed"); Ok(res) } @@ -1080,11 +1140,13 @@ impl Wallet { info!(self.logger(), "Burning amount: {}...", amount); self.check_xprv()?; self.check_online(online)?; + let txn = self.database().begin_transaction()?; let mut begin_op_data = - self.burn_begin_impl(asset_id, amount, fee_rate, min_confirmations, true)?; + self.burn_begin_impl(&txn, asset_id, amount, fee_rate, min_confirmations, true)?; self.sign_psbt_impl(&mut begin_op_data.psbt, None)?; - let res = self.burn_end_impl(&begin_op_data.psbt)?; - self.update_backup_info(false)?; + let res = self.burn_end_impl(&txn, &begin_op_data.psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Burn completed"); Ok(res) } @@ -1117,9 +1179,11 @@ impl Wallet { ) -> Result { info!(self.logger(), "Burning (begin) amount: {}...", amount); self.check_online(online)?; + let txn = self.database().begin_transaction()?; let begin_operation_data = - self.burn_begin_impl(asset_id, amount, fee_rate, min_confirmations, dry_run)?; - self.update_backup_info(false)?; + self.burn_begin_impl(&txn, asset_id, amount, fee_rate, min_confirmations, dry_run)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Burn (begin) completed"); Ok(BurnBeginResult { psbt: begin_operation_data.psbt.to_string(), @@ -1152,8 +1216,10 @@ impl Wallet { info!(self.logger(), "Burning (end)..."); self.check_online(online)?; let psbt = Psbt::from_str(&signed_psbt)?; - let res = self.burn_end_impl(&psbt)?; - self.update_backup_info(false)?; + let txn = self.database().begin_transaction()?; + let res = self.burn_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; + txn.commit()?; info!(self.logger(), "Burn (end) completed"); Ok(res) } diff --git a/src/wallet/test/abort_pending_vanilla_tx.rs b/src/wallet/test/abort_pending_vanilla_tx.rs index c4338e3d..bbc51cd7 100644 --- a/src/wallet/test/abort_pending_vanilla_tx.rs +++ b/src/wallet/test/abort_pending_vanilla_tx.rs @@ -24,21 +24,33 @@ fn success() { // pre-abort: reservation + wallet_transaction exist assert_eq!(wallet.list_pending_vanilla_txs().unwrap().len(), 1); - assert!(!wallet.database().iter_reserved_txos().unwrap().is_empty()); + let txn = wallet.database().begin_transaction().unwrap(); + let reserved_txos = txn.iter_reserved_txos().unwrap(); + txn.commit().unwrap(); + assert!(!reserved_txos.is_empty()); // abort + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); wallet.abort_pending_vanilla_tx(psbt_txid.clone()).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // post-abort: reservation + wallet_transaction row both gone assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); - assert!(wallet.database().iter_reserved_txos().unwrap().is_empty()); - assert!( - wallet - .database() - .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) - .unwrap() - .is_none() - ); + let txn = wallet.database().begin_transaction().unwrap(); + let reserved_txos = txn.iter_reserved_txos().unwrap(); + txn.commit().unwrap(); + assert!(reserved_txos.is_empty()); + let txn = wallet.database().begin_transaction().unwrap(); + let maybe_wallet_tx = txn + .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) + .unwrap(); + txn.commit().unwrap(); + assert!(maybe_wallet_tx.is_none()); // the previously-reserved UTXOs are now available again: a fresh send_btc_begin // re-selects them @@ -79,11 +91,12 @@ fn fail() { &test_get_address(&mut rcv_wallet), 1000, ); - let (_wt, reservations) = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let (_wt, reservations) = txn .get_wallet_transaction_with_reserved_txos_by_txid(&txid) .unwrap() .expect("SendBtc wallet_transaction should exist after send_btc"); + txn.commit().unwrap(); assert!(reservations.is_empty()); let result = wallet.abort_pending_vanilla_tx(txid); assert!(matches!(result, Err(Error::CannotAbortPendingVanillaTx))); diff --git a/src/wallet/test/blind_receive.rs b/src/wallet/test/blind_receive.rs index 8e3b813d..86dec3f1 100644 --- a/src/wallet/test/blind_receive.rs +++ b/src/wallet/test/blind_receive.rs @@ -11,7 +11,9 @@ fn success() { let (mut wallet, online) = get_funded_wallet!(); // only mandatory fields - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let receive_data = wallet .blind_receive( None, @@ -21,7 +23,9 @@ fn success() { MIN_CONFIRMATIONS, ) .unwrap(); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(receive_data.expiration_timestamp.is_none()); let decoded_invoice = Invoice::new(receive_data.invoice).unwrap(); @@ -297,10 +301,11 @@ fn success() { ); assert!(result.is_ok()); let transfer = get_test_transfer_recipient(&wallet, &result.unwrap().recipient_id); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), transport_endpoints.len()); } @@ -510,17 +515,14 @@ fn fail() { let receive_data = blind_receive_withte(&mut wallet, transport_endpoints).unwrap(); let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); for (tte, _) in tte_data { - block_on( - transfer_transport_endpoint::Entity::delete_by_id(tte.idx) - .exec(wallet.database().get_connection()), - ) - .unwrap(); + txn.del_transfer_transport_endpoint(tte.idx).unwrap(); } + txn.commit().unwrap(); assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); wait_for_refresh(&mut wallet, online, None, None); let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); diff --git a/src/wallet/test/burn.rs b/src/wallet/test/burn.rs index 71c73b45..e90be08b 100644 --- a/src/wallet/test/burn.rs +++ b/src/wallet/test/burn.rs @@ -64,9 +64,13 @@ fn success() { // burn test_create_utxos_default(&mut wallet, online); let burn_amount = 199; - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let res = test_burn(&mut wallet, online, &asset.asset_id, burn_amount); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); show_unspent_colorings(&mut wallet, "after burn"); @@ -240,10 +244,11 @@ fn success() { assert!(!txid.is_empty()); show_unspent_colorings(&mut wallet, "after send"); let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), 1); let ce = tte_data.first().unwrap(); assert_eq!(ce.1.endpoint, PROXY_URL); diff --git a/src/wallet/test/create_utxos.rs b/src/wallet/test/create_utxos.rs index c2d055df..4fc928db 100644 --- a/src/wallet/test/create_utxos.rs +++ b/src/wallet/test/create_utxos.rs @@ -9,9 +9,13 @@ fn success() { // up_to version with 0 allocatable UTXOs println!("\n=== up_to true, 0 allocatable"); let (mut wallet, online) = get_funded_noutxo_wallet!(); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); test_create_utxos(&mut wallet, online, true, None, None, FEE_RATE, None); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); let unspents = test_list_unspents(&mut wallet, None, false); assert_eq!(unspents.len(), (UTXO_NUM + 1) as usize); @@ -346,11 +350,12 @@ fn begin_reservation_interactions() { assert!(!psbt_inputs.is_empty()); // wallet_transaction(CreateUtxos) row exists with reservations matching inputs - let (wt, reservations) = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let (wt, reservations) = txn .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) .unwrap() .expect("wallet_transaction should exist after dry_run=false begin"); + txn.commit().unwrap(); assert_eq!(wt.r#type, WalletTransactionType::CreateUtxos); assert!(reservations.iter().all(|r| r.reserved_for == Some(wt.idx))); let reserved_set: HashSet<(String, u32)> = reservations @@ -366,7 +371,9 @@ fn begin_reservation_interactions() { assert_eq!(pending[0].r#type, WalletTransactionType::CreateUtxos); // clear this in-flight create_utxos reservation wallet.abort_pending_vanilla_tx(psbt_txid).unwrap(); - assert!(wallet.database().iter_reserved_txos().unwrap().is_empty()); + let txn = wallet.database().begin_transaction().unwrap(); + assert!(txn.iter_reserved_txos().unwrap().is_empty()); + txn.commit().unwrap(); // reserve (at least) one vanilla UTXO via send_btc_begin(dry_run=false). BDK's // coin selection only picks the minimum inputs for amount + fee, so one of the @@ -381,13 +388,14 @@ fn begin_reservation_interactions() { false, ) .unwrap(); - let reserved_set: HashSet<(String, u32)> = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let reserved_set: HashSet<(String, u32)> = txn .iter_reserved_txos() .unwrap() .iter() .map(|r| (r.txid.clone(), r.vout)) .collect(); + txn.commit().unwrap(); assert_eq!(reserved_set.len(), 1); // create_utxos_begin(dry_run=true) must not select any reserved outpoint diff --git a/src/wallet/test/delete_transfers.rs b/src/wallet/test/delete_transfers.rs index 9dbbcc96..49c13fee 100644 --- a/src/wallet/test/delete_transfers.rs +++ b/src/wallet/test/delete_transfers.rs @@ -9,9 +9,13 @@ fn success() { let (mut wallet, online) = get_funded_wallet!(); // return false if no transfer has changed - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(!test_delete_transfers(&wallet, None, false)); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -25,13 +29,17 @@ fn success() { &receive_data.recipient_id, TransferStatus::Failed )); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(test_delete_transfers( &wallet, Some(receive_data.batch_transfer_idx), false )); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // delete all Failed transfers @@ -53,7 +61,9 @@ fn success() { show_unspent_colorings(&mut wallet, "run 1 before delete"); test_delete_transfers(&wallet, None, false); show_unspent_colorings(&mut wallet, "run 1 after delete"); - let transfers = wallet.database().iter_transfers().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); assert_eq!(transfers.len(), 1); assert!(check_test_transfer_status_recipient( &wallet, @@ -72,7 +82,9 @@ fn success() { Some(receive_data_3.batch_transfer_idx), false )); - let transfers = wallet.database().iter_transfers().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); assert_eq!(transfers.len(), 0); // issue @@ -112,7 +124,9 @@ fn success() { show_unspent_colorings(&mut wallet, "run 2 before delete"); assert!(test_delete_transfers(&wallet, None, true)); show_unspent_colorings(&mut wallet, "run 2 after delete"); - let transfers = wallet.database().iter_transfers().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); assert_eq!(transfers.len(), 2); assert!(check_test_transfer_status_recipient( &wallet, diff --git a/src/wallet/test/drain_to.rs b/src/wallet/test/drain_to.rs index be9eacce..710e761b 100644 --- a/src/wallet/test/drain_to.rs +++ b/src/wallet/test/drain_to.rs @@ -25,9 +25,13 @@ fn success() { }; wait_for_btc_balance(&mut wallet, online, &expected_balance); let address = test_get_address(&mut rcv_wallet); // also updates backup_info - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); test_drain_to(&mut wallet, online, &address); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); mine(false); wait_for_unspents(&mut wallet, Some(online), false, 0); @@ -123,13 +127,17 @@ fn drain_to_begin_and_end_success() { let mut rcv_wallet = get_test_wallet(true, None); let address = test_get_address(&mut rcv_wallet); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); // drain_to_begin does not update backup_info let unsigned_psbt = wallet .drain_to_begin(online, address, FEE_RATE, true) .unwrap(); - let bak_info_after_begin = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after_begin = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after_begin.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -141,7 +149,9 @@ fn drain_to_begin_and_end_success() { assert!(!txid.is_empty()); // drain_to_end updates backup_info - let bak_info_after_end = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after_end = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after_end.last_operation_timestamp > bak_info_before.last_operation_timestamp); // verify the drain was effective diff --git a/src/wallet/test/fail_transfers.rs b/src/wallet/test/fail_transfers.rs index f67e3434..e6d6e686 100644 --- a/src/wallet/test/fail_transfers.rs +++ b/src/wallet/test/fail_transfers.rs @@ -13,9 +13,13 @@ fn success() { let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); // return false if no transfer has changed - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(!test_fail_transfers_all(&mut wallet, online)); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -31,13 +35,17 @@ fn success() { &receive_data.recipient_id, TransferStatus::WaitingCounterparty )); - let bak_info_before = rcv_wallet.database().get_backup_info().unwrap().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(test_fail_transfers_single( &mut rcv_wallet, rcv_online, receive_data.batch_transfer_idx )); - let bak_info_after = rcv_wallet.database().get_backup_info().unwrap().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // fail all expired WaitingCounterparty transfers diff --git a/src/wallet/test/get_address.rs b/src/wallet/test/get_address.rs index d55917e9..6c0462cc 100644 --- a/src/wallet/test/get_address.rs +++ b/src/wallet/test/get_address.rs @@ -4,10 +4,14 @@ use super::*; #[parallel] fn success() { let mut wallet = get_test_wallet(false, None); - let bak_info_before = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_before.is_none()); let address = test_get_address(&mut wallet); - let bak_info_after = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.is_some()); assert!( bak_info_after diff --git a/src/wallet/test/get_asset_balance.rs b/src/wallet/test/get_asset_balance.rs index 82b600b3..126ecd58 100644 --- a/src/wallet/test/get_asset_balance.rs +++ b/src/wallet/test/get_asset_balance.rs @@ -12,9 +12,13 @@ fn success() { let asset = test_issue_asset_nia(&mut wallet, online, None); // balances after issuance - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let asset_balance = test_get_asset_balance(&wallet, &asset.asset_id); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp diff --git a/src/wallet/test/get_asset_metadata.rs b/src/wallet/test/get_asset_metadata.rs index a21d3b19..70236ef3 100644 --- a/src/wallet/test/get_asset_metadata.rs +++ b/src/wallet/test/get_asset_metadata.rs @@ -26,9 +26,13 @@ fn success() { )]); test_send(&mut wallet, online, &recipient_map); wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let nia_metadata = test_get_asset_metadata(&rcv_wallet, &asset_nia.asset_id); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp diff --git a/src/wallet/test/get_btc_balance.rs b/src/wallet/test/get_btc_balance.rs index 1c058092..01edb8b6 100644 --- a/src/wallet/test/get_btc_balance.rs +++ b/src/wallet/test/get_btc_balance.rs @@ -9,10 +9,14 @@ fn success() { let (mut wallet, online) = get_empty_wallet!(); // empty balance - let bak_info_before = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_before.is_none()); let balance = test_get_btc_balance(&mut wallet, online); - let bak_info_after = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.is_none()); let expected_balance = BtcBalance { vanilla: Balance { diff --git a/src/wallet/test/go_online.rs b/src/wallet/test/go_online.rs index ec8ed8c6..6932b0e8 100644 --- a/src/wallet/test/go_online.rs +++ b/src/wallet/test/go_online.rs @@ -9,10 +9,14 @@ fn success() { let mut wallet = get_test_wallet(true, None); // go online - let bak_info_before = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_before.is_none()); let result_1 = test_go_online_result(&mut wallet, false, None); - let bak_info_after = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.is_none()); assert!(result_1.is_ok()); diff --git a/src/wallet/test/inflate.rs b/src/wallet/test/inflate.rs index 95bd2c48..089093e6 100644 --- a/src/wallet/test/inflate.rs +++ b/src/wallet/test/inflate.rs @@ -40,9 +40,13 @@ fn success() { // inflate test_create_utxos_default(&mut wallet, online); let inflation_amounts = [199, 42]; - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let res = test_inflate(&mut wallet, online, &asset.asset_id, &inflation_amounts); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); show_unspent_colorings(&mut wallet, "after inflate"); let total_inflated = inflation_amounts.iter().sum::(); @@ -155,10 +159,11 @@ fn success() { assert!(!txid.is_empty()); show_unspent_colorings(&mut wallet, "after send"); let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), 1); let ce = tte_data.first().unwrap(); assert_eq!(ce.1.endpoint, PROXY_URL); diff --git a/src/wallet/test/issue_asset_cfa.rs b/src/wallet/test/issue_asset_cfa.rs index 6862170f..86af794d 100644 --- a/src/wallet/test/issue_asset_cfa.rs +++ b/src/wallet/test/issue_asset_cfa.rs @@ -24,7 +24,9 @@ fn success() { // required fields only println!("\nasset 1"); let before_timestamp = now().unix_timestamp(); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let asset_1 = wallet .issue_asset_cfa( NAME.to_string(), @@ -34,7 +36,9 @@ fn success() { None, ) .unwrap(); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema diff --git a/src/wallet/test/issue_asset_ifa.rs b/src/wallet/test/issue_asset_ifa.rs index ba971e81..1e9ff1a0 100644 --- a/src/wallet/test/issue_asset_ifa.rs +++ b/src/wallet/test/issue_asset_ifa.rs @@ -9,7 +9,9 @@ fn success() { let (mut wallet, online) = get_funded_wallet!(); let before_timestamp = now().unix_timestamp(); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let asset = test_issue_asset_ifa( &mut wallet, online, @@ -17,7 +19,9 @@ fn success() { Some(&[AMOUNT, AMOUNT, AMOUNT]), None, ); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema diff --git a/src/wallet/test/issue_asset_nia.rs b/src/wallet/test/issue_asset_nia.rs index 333bad76..0090b275 100644 --- a/src/wallet/test/issue_asset_nia.rs +++ b/src/wallet/test/issue_asset_nia.rs @@ -20,9 +20,13 @@ fn success() { ); let before_timestamp = now().unix_timestamp(); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let asset = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT, AMOUNT])); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema diff --git a/src/wallet/test/issue_asset_uda.rs b/src/wallet/test/issue_asset_uda.rs index 6c32d389..89cc27a1 100644 --- a/src/wallet/test/issue_asset_uda.rs +++ b/src/wallet/test/issue_asset_uda.rs @@ -25,9 +25,13 @@ fn success() { // required fields only println!("\nasset 1"); let before_timestamp = now().unix_timestamp(); - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let asset_1 = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema diff --git a/src/wallet/test/list_assets.rs b/src/wallet/test/list_assets.rs index 96486ed4..847fa594 100644 --- a/src/wallet/test/list_assets.rs +++ b/src/wallet/test/list_assets.rs @@ -9,9 +9,13 @@ fn success() { let (mut wallet, online) = get_funded_wallet!(); // no assets - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let assets = test_list_assets(&wallet, &[]); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp diff --git a/src/wallet/test/list_transactions.rs b/src/wallet/test/list_transactions.rs index 891e2571..4d223c2a 100644 --- a/src/wallet/test/list_transactions.rs +++ b/src/wallet/test/list_transactions.rs @@ -20,9 +20,13 @@ fn success() { force_mine_no_resume_when_alone(false); // don't sync wallet without online - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let transactions = test_list_transactions(&mut wallet, None); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp diff --git a/src/wallet/test/list_transfers.rs b/src/wallet/test/list_transfers.rs index 0dd406e1..5508d568 100644 --- a/src/wallet/test/list_transfers.rs +++ b/src/wallet/test/list_transfers.rs @@ -16,9 +16,13 @@ fn success() { let asset = test_issue_asset_nia(&mut wallet, online, None); // single transfer (issuance) - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let transfer_list = test_list_transfers(&wallet, Some(&asset.asset_id)); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp diff --git a/src/wallet/test/list_unspents.rs b/src/wallet/test/list_unspents.rs index d5d902c6..7c94c8c8 100644 --- a/src/wallet/test/list_unspents.rs +++ b/src/wallet/test/list_unspents.rs @@ -13,10 +13,14 @@ fn success() { let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); // no unspents - let bak_info_before = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_before.is_none()); let unspent_list_settled = test_list_unspents(&mut wallet, None, true); - let bak_info_after = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.is_none()); assert_eq!(unspent_list_settled.len(), 0); let unspent_list_all = test_list_unspents(&mut wallet, None, false); diff --git a/src/wallet/test/mod.rs b/src/wallet/test/mod.rs index 049eff0b..20c9413d 100644 --- a/src/wallet/test/mod.rs +++ b/src/wallet/test/mod.rs @@ -30,10 +30,9 @@ use crate::wallet::{ utils::build_indexer, }; use crate::{ - database::entities::transfer_transport_endpoint, keys::{Keys, generate_keys}, utils::{ - KEYCHAIN_BTC, KEYCHAIN_RGB, RGB_RUNTIME_DIR, block_on, get_account_data, + KEYCHAIN_BTC, KEYCHAIN_RGB, RGB_RUNTIME_DIR, get_account_data, get_account_derivation_children, get_coin_type, get_extended_derivation_path, recipient_id_from_script_buf, script_buf_from_recipient_id, }, @@ -337,4 +336,5 @@ mod rust_only; mod send; mod send_btc; mod sign_psbt; +mod sync; mod witness_receive; diff --git a/src/wallet/test/multisig/mod.rs b/src/wallet/test/multisig/mod.rs index e813939b..82a79aa3 100644 --- a/src/wallet/test/multisig/mod.rs +++ b/src/wallet/test/multisig/mod.rs @@ -1222,9 +1222,11 @@ fn fail() { let signed_psbt = wlt_2_singlesig .sign_psbt(unsigned_psbt.clone(), None) .unwrap(); + let txn = wlt_2.multisig.database().begin_transaction().unwrap(); wlt_2 .multisig_mut() .sync_wallet( + &txn, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -1232,6 +1234,7 @@ fn fail() { false, ) .unwrap(); + txn.commit().unwrap(); wlt_2.respond_to_operation(op_idx_1, RespondToOperation::Ack(signed_psbt.clone())); let err = wlt_3 .respond_to_operation_res(op_idx_1, RespondToOperation::Nack) diff --git a/src/wallet/test/multisig/utils.rs b/src/wallet/test/multisig/utils.rs index fd46ff1b..990fd21c 100644 --- a/src/wallet/test/multisig/utils.rs +++ b/src/wallet/test/multisig/utils.rs @@ -406,7 +406,10 @@ pub(super) trait MultisigOps { } fn bak_info_opt(&mut self) -> Option> { - self.multisig_ref().database().get_backup_info().ok() + let txn = self.multisig_ref().database().begin_transaction().ok()?; + let bak_info = txn.get_backup_info().ok()?; + txn.commit().ok()?; + Some(bak_info) } fn bak_ts(&mut self) -> String { @@ -1044,17 +1047,11 @@ fn check_asset_metadata( match schema { AssetSchema::Cfa => { - let asset_db = wallet - .database() - .get_asset(asset_id.to_string()) - .unwrap() - .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let asset_db = txn.get_asset(asset_id.to_string()).unwrap().unwrap(); assert!(asset_db.media_idx.is_some()); - let media = wallet - .database() - .get_media(asset_db.media_idx.unwrap()) - .unwrap() - .unwrap(); + let media = txn.get_media(asset_db.media_idx.unwrap()).unwrap().unwrap(); + txn.commit().unwrap(); if let Some(ref media_1) = media_1 { assert_eq!(media_1.digest, media.digest); } else { @@ -1080,11 +1077,6 @@ fn check_asset_metadata( assert!(!meta_token.attachments.is_empty()); assert_eq!(meta_token.reserves, None); - let asset_db = wallet - .database() - .get_asset(asset_id.to_string()) - .unwrap() - .unwrap(); let assets_uda = wallet .list_assets(vec![AssetSchema::Uda]) .unwrap() @@ -1093,20 +1085,22 @@ fn check_asset_metadata( let asset_uda = assets_uda.iter().find(|a| a.asset_id == asset_id).unwrap(); let token = asset_uda.token.clone().unwrap(); assert_eq!(token.index, UDA_FIXED_INDEX); - let tokens = wallet.database().iter_tokens().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let asset_db = txn.get_asset(asset_id.to_string()).unwrap().unwrap(); + let tokens = txn.iter_tokens().unwrap(); let token_db = tokens.iter().find(|t| t.asset_idx == asset_db.idx).unwrap(); if let Some(ref token_db_1) = token_db_1 { assert_eq!(token_db, token_db_1); } else { token_db_1 = Some(token_db.clone()); } - let token_medias = wallet.database().iter_token_medias().unwrap(); + let token_medias = txn.iter_token_medias().unwrap(); let token_media_entries: Vec<_> = token_medias .into_iter() .filter(|tm| tm.token_idx == token_db.idx) .collect(); assert_eq!(token_media_entries.len(), 3); - let medias = wallet.database().iter_media().unwrap(); + let medias = txn.iter_media().unwrap(); let mut digests: Vec = token_media_entries .iter() .map(|tm| { @@ -1124,6 +1118,7 @@ fn check_asset_metadata( } else { digests_1 = digests; } + txn.commit().unwrap(); let attachments = &token.attachments; assert_eq!(attachments.len(), 2); if let Some(ref token_1) = token_1 { @@ -1172,10 +1167,14 @@ pub(super) fn check_btc_balance( } pub(super) fn check_change_consistency(wlt_a: &mut MultisigParty, wlt_b: &mut MultisigParty) { - let wlt_a_txos = wlt_a.multisig.database().iter_txos().unwrap(); - let wlt_b_txos = wlt_b.multisig.database().iter_txos().unwrap(); - let wlt_a_colorings = wlt_a.multisig.database().iter_colorings().unwrap(); - let wlt_b_colorings = wlt_b.multisig.database().iter_colorings().unwrap(); + let txn = wlt_a.multisig.database().begin_transaction().unwrap(); + let wlt_a_txos = txn.iter_txos().unwrap(); + let wlt_a_colorings = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + let txn = wlt_b.multisig.database().begin_transaction().unwrap(); + let wlt_b_txos = txn.iter_txos().unwrap(); + let wlt_b_colorings = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); let resolve_change_outpoints = |txos: &[DbTxo], colorings: &[DbColoring]| -> Vec { colorings .iter() diff --git a/src/wallet/test/new.rs b/src/wallet/test/new.rs index 5bf143ec..dea85aaa 100644 --- a/src/wallet/test/new.rs +++ b/src/wallet/test/new.rs @@ -58,7 +58,9 @@ fn success() { // with private keys let wallet = get_test_wallet(true, None); - let bak_info_after = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.is_none()); // without private keys diff --git a/src/wallet/test/refresh.rs b/src/wallet/test/refresh.rs index ffa87255..6b93af19 100644 --- a/src/wallet/test/refresh.rs +++ b/src/wallet/test/refresh.rs @@ -51,9 +51,13 @@ fn success() { }], )]); // return false if no transfer has changed - let bak_info_before = wallet_2.database().get_backup_info().unwrap().unwrap(); + let txn = wallet_2.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(!test_refresh_all(&mut wallet_2, online_2)); - let bak_info_after = wallet_2.database().get_backup_info().unwrap().unwrap(); + let txn = wallet_2.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -73,9 +77,13 @@ fn success() { let txid_2a = test_send(&mut wallet_2, online_2, &recipient_map_2a); assert!(!txid_2a.is_empty()); assert!(test_refresh_all(&mut wallet_1, online_1)); - let bak_info_before = wallet_2.database().get_backup_info().unwrap().unwrap(); + let txn = wallet_2.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(test_refresh_all(&mut wallet_2, online_2)); - let bak_info_after = wallet_2.database().get_backup_info().unwrap().unwrap(); + let txn = wallet_2.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!( test_refresh_result( @@ -335,20 +343,17 @@ fn nia_with_media() { let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); let media = Media::from_attachment(&attachment, wallet_1.get_media_dir()); wallet_1.copy_media_file(fp, &media).unwrap(); - let media_idx = wallet_1 + let txn = wallet_1.database().begin_transaction().unwrap(); + let media_idx = txn .get_or_insert_media(media.get_digest(), media.mime.clone()) .unwrap(); - let db_asset = wallet_1 - .database() - .get_asset(asset.asset_id.clone()) - .unwrap() - .unwrap(); + let db_asset = txn.get_asset(asset.asset_id.clone()).unwrap().unwrap(); + txn.commit().unwrap(); let mut updated_asset: DbAssetActMod = db_asset.into(); updated_asset.media_idx = ActiveValue::Set(Some(media_idx)); - wallet_1 - .database() - .update_asset(&mut updated_asset) - .unwrap(); + let txn = wallet_1.database().begin_transaction().unwrap(); + txn.update_asset(&mut updated_asset).unwrap(); + txn.commit().unwrap(); let receive_data = test_blind_receive(&mut wallet_2); let recipient_map = HashMap::from([( @@ -508,20 +513,17 @@ fn uda_with_media() { let asset = test_issue_asset_uda(&mut wallet_1, online_1, None, Some(FILE_STR), vec![]); let media = Media::from_attachment(&attachment, wallet_1.get_media_dir()); wallet_1.copy_media_file(fp, &media).unwrap(); - let media_idx = wallet_1 + let txn = wallet_1.database().begin_transaction().unwrap(); + let media_idx = txn .get_or_insert_media(media.get_digest(), media.mime.clone()) .unwrap(); - let db_asset = wallet_1 - .database() - .get_asset(asset.asset_id.clone()) - .unwrap() - .unwrap(); + let db_asset = txn.get_asset(asset.asset_id.clone()).unwrap().unwrap(); + txn.commit().unwrap(); let mut updated_asset: DbAssetActMod = db_asset.into(); updated_asset.media_idx = ActiveValue::Set(Some(media_idx)); - wallet_1 - .database() - .update_asset(&mut updated_asset) - .unwrap(); + let txn = wallet_1.database().begin_transaction().unwrap(); + txn.update_asset(&mut updated_asset).unwrap(); + txn.commit().unwrap(); let receive_data = test_blind_receive(&mut wallet_2); let recipient_map = HashMap::from([( diff --git a/src/wallet/test/rust_only.rs b/src/wallet/test/rust_only.rs index 2701481f..54a827d0 100644 --- a/src/wallet/test/rust_only.rs +++ b/src/wallet/test/rust_only.rs @@ -173,10 +173,14 @@ fn list_unspents_vanilla_success() { let (mut wallet, online) = get_empty_wallet!(); // no unspents - let bak_info_before = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_before.is_none()); let unspent_list = test_list_unspents_vanilla(&mut wallet, online, None); - let bak_info_after = wallet.database().get_backup_info().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.is_none()); assert_eq!(unspent_list.len(), 0); @@ -261,17 +265,10 @@ fn save_new_asset_success() { &nia_asset.asset_id, Assignment::Fungible(asset_amount), ); - assert!( - &rcv_wallet - .database() - .check_asset_exists(nia_asset.asset_id.clone()) - .is_ok() - ); - let asset_model = rcv_wallet - .database() - .get_asset(nia_asset.asset_id.clone()) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + assert!(txn.check_asset_exists(nia_asset.asset_id.clone()).is_ok()); + let asset_model = txn.get_asset(nia_asset.asset_id.clone()).unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!(asset_model.id, nia_asset.asset_id); assert_eq!(asset_model.initial_supply, AMOUNT.to_string()); assert_eq!(asset_model.name, NAME); @@ -288,17 +285,10 @@ fn save_new_asset_success() { &cfa_asset.asset_id, Assignment::Fungible(asset_amount), ); - assert!( - &rcv_wallet - .database() - .check_asset_exists(cfa_asset.asset_id.clone()) - .is_ok() - ); - let asset_model = rcv_wallet - .database() - .get_asset(cfa_asset.asset_id.clone()) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + assert!(txn.check_asset_exists(cfa_asset.asset_id.clone()).is_ok()); + let asset_model = txn.get_asset(cfa_asset.asset_id.clone()).unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!(asset_model.id, cfa_asset.asset_id); assert_eq!(asset_model.initial_supply, AMOUNT.to_string()); assert_eq!(asset_model.name, NAME); @@ -323,17 +313,10 @@ fn save_new_asset_success() { &uda_asset.asset_id, Assignment::NonFungible, ); - assert!( - &rcv_wallet - .database() - .check_asset_exists(uda_asset.asset_id.clone()) - .is_ok() - ); - let asset_model = rcv_wallet - .database() - .get_asset(uda_asset.asset_id.clone()) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + assert!(txn.check_asset_exists(uda_asset.asset_id.clone()).is_ok()); + let asset_model = txn.get_asset(uda_asset.asset_id.clone()).unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!(asset_model.id, uda_asset.asset_id); assert_eq!(asset_model.initial_supply, 1.to_string()); assert_eq!(asset_model.name, NAME); diff --git a/src/wallet/test/send.rs b/src/wallet/test/send.rs index 10874254..b5ef5726 100644 --- a/src/wallet/test/send.rs +++ b/src/wallet/test/send.rs @@ -31,7 +31,9 @@ fn success() { }], )]); let expiration_timestamp = (now().unix_timestamp() + expiration_secs) as u64; - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let operation_result = wallet .send( online, @@ -42,15 +44,18 @@ fn success() { Some(expiration_timestamp), ) .unwrap(); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let txid = operation_result.txid; assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(!txid.is_empty()); let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), 1); let ce = tte_data.first().unwrap(); assert_eq!(ce.1.endpoint, PROXY_URL); @@ -220,10 +225,11 @@ fn success() { let txid = test_send(&mut wallet, online, &recipient_map); assert!(!txid.is_empty()); let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), 3); let mut tte_data_iter = tte_data.iter(); let (ce_0, ce_1, ce_2) = ( @@ -302,10 +308,11 @@ fn success() { .txid; assert!(!txid.is_empty()); let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), 3); let mut tte_data_iter = tte_data.iter(); let (ce_0, ce_1, ce_2) = ( @@ -1397,15 +1404,15 @@ fn send_received_uda_success() { Some(FILE_STR), vec![&image_str, FILE_STR], ); + let txn = wallet_1.database().begin_transaction().unwrap(); assert!( - wallet_1 - .database() - .get_asset(asset.asset_id.clone()) + txn.get_asset(asset.asset_id.clone()) .unwrap() .unwrap() .media_idx .is_none() ); + txn.commit().unwrap(); // // 1st transfer: wallet 1 > wallet 2 @@ -1465,15 +1472,15 @@ fn send_received_uda_success() { // take transfers from WaitingCounterparty to Settled wait_for_refresh(&mut wallet_3, online_3, None, None); + let txn = wallet_3.database().begin_transaction().unwrap(); assert!( - wallet_3 - .database() - .get_asset(asset.asset_id.clone()) + txn.get_asset(asset.asset_id.clone()) .unwrap() .unwrap() .media_idx .is_none() ); + txn.commit().unwrap(); wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); mine(false); wait_for_refresh(&mut wallet_3, online_3, None, None); @@ -4931,13 +4938,10 @@ fn spend_double_receive() { }], )]); // manually set the input unspents to the UTXO of the 1st allocation - let db_data = wallet_2.database().get_db_data(false).unwrap(); - let utxos = wallet_2 - .database() - .get_unspent_txos(db_data.txos.clone()) - .unwrap(); - let mut input_unspents = wallet_2 - .database() + let txn = wallet_2.database().begin_transaction().unwrap(); + let db_data = txn.get_db_data(false).unwrap(); + let utxos = txn.get_unspent_txos(db_data.txos.clone()).unwrap(); + let mut input_unspents = txn .get_rgb_allocations( utxos, Some(db_data.colorings.clone()), @@ -4946,6 +4950,7 @@ fn spend_double_receive() { Some(db_data.transfers.clone()), ) .unwrap(); + txn.commit().unwrap(); input_unspents.retain(|u| { !u.rgb_allocations.is_empty() && u.rgb_allocations.iter().all(|a| { @@ -6629,12 +6634,11 @@ fn pending_witness_txo() { ); // check the recipient doesn't see the TXO yet + has one pending witness script - let rcv_txos = rcv_wallet.database().iter_txos().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txos = txn.iter_txos().unwrap(); assert!(!rcv_txos.iter().any(|t| t.txid == txid)); - let rcv_pending_witness_scripts = rcv_wallet - .database() - .iter_pending_witness_scripts() - .unwrap(); + let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // sync recipient wallet @@ -6649,12 +6653,11 @@ fn pending_witness_txo() { .unwrap(); // check the recipient doesn't see the TXO yet + has one pending witness - let rcv_txos = rcv_wallet.database().iter_txos().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txos = txn.iter_txos().unwrap(); assert!(!rcv_txos.iter().any(|t| t.txid == txid)); - let rcv_pending_witness_scripts = rcv_wallet - .database() - .iter_pending_witness_scripts() - .unwrap(); + let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // refresh the recipient to move the transfer to WaitingConfirmations @@ -6667,7 +6670,8 @@ fn pending_witness_txo() { ); // check the recipient now sees the TXO yet as inexistent + pending witness - let rcv_txos = rcv_wallet.database().iter_txos().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txos = txn.iter_txos().unwrap(); let rcv_witness_txos: Vec = rcv_txos.into_iter().filter(|t| t.txid == txid).collect(); assert_eq!(rcv_witness_txos.len(), 1); @@ -6680,10 +6684,8 @@ fn pending_witness_txo() { }; // check the recipient still has the pending witness script - let rcv_pending_witness_scripts = rcv_wallet - .database() - .iter_pending_witness_scripts() - .unwrap(); + let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // refresh the sender to move the transfer to WaitingConfirmations (broadcast) @@ -6701,19 +6703,14 @@ fn pending_witness_txo() { .unwrap(); // check the recipient TXO now exists and is still pending witness - let rcv_txo = rcv_wallet - .database() - .get_txo(&rcv_outpoint) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); assert!(rcv_txo.exists); assert!(rcv_txo.pending_witness); // check the recipient pending witness script has been deleted - let rcv_pending_witness_scripts = rcv_wallet - .database() - .iter_pending_witness_scripts() - .unwrap(); + let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); assert!(rcv_pending_witness_scripts.is_empty()); // mine + refresh the recipient to move the transfer to Settled @@ -6726,11 +6723,9 @@ fn pending_witness_txo() { assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); // check the recipient TXO still exists and is no more pending witness - let rcv_txo = rcv_wallet - .database() - .get_txo(&rcv_outpoint) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); + txn.commit().unwrap(); assert!(rcv_txo.exists); assert!(!rcv_txo.pending_witness); @@ -6775,12 +6770,11 @@ fn pending_witness_txo() { ); // check the recipient doesn't see the TXO yet + has one pending witness script - let rcv_txos = rcv_wallet.database().iter_txos().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txos = txn.iter_txos().unwrap(); assert!(!rcv_txos.iter().any(|t| t.txid == txid)); - let rcv_pending_witness_scripts = rcv_wallet - .database() - .iter_pending_witness_scripts() - .unwrap(); + let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // sync recipient wallet @@ -6795,7 +6789,8 @@ fn pending_witness_txo() { .unwrap(); // check the recipient now sees the TXO, as existent + pending witness - let rcv_txos = rcv_wallet.database().iter_txos().unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txos = txn.iter_txos().unwrap(); let rcv_witness_txos: Vec = rcv_txos.into_iter().filter(|t| t.txid == txid).collect(); assert_eq!(rcv_witness_txos.len(), 1); @@ -6808,10 +6803,8 @@ fn pending_witness_txo() { }; // check pending witness script has been deleted - let rcv_pending_witness_scripts = rcv_wallet - .database() - .iter_pending_witness_scripts() - .unwrap(); + let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); assert!(rcv_pending_witness_scripts.is_empty()); // refresh to move the transfer to WaitingConfirmations @@ -6824,11 +6817,9 @@ fn pending_witness_txo() { ); // check the TXO is still existent + pending witness - let rcv_txo = rcv_wallet - .database() - .get_txo(&rcv_outpoint) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); + txn.commit().unwrap(); assert!(rcv_txo.exists); assert!(rcv_txo.pending_witness); @@ -6842,11 +6833,9 @@ fn pending_witness_txo() { assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); // check the TXO is still existent but not pending witness anymore - let rcv_txo = rcv_wallet - .database() - .get_txo(&rcv_outpoint) - .unwrap() - .unwrap(); + let txn = rcv_wallet.database().begin_transaction().unwrap(); + let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); + txn.commit().unwrap(); assert!(rcv_txo.exists); assert!(!rcv_txo.pending_witness); } @@ -7372,8 +7361,9 @@ fn send_end_without_send_begin() { fn allocations() { fn get_coloring_map(wallet: &Wallet, unspents: &[Unspent]) -> HashMap> { let mut coloring_map: HashMap> = HashMap::new(); - let db_txos = wallet.database().iter_txos().unwrap(); - let db_colorings: Vec = wallet.database().iter_colorings().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let db_txos = txn.iter_txos().unwrap(); + let db_colorings: Vec = txn.iter_colorings().unwrap(); for u in unspents { let outpoint = &u.utxo.outpoint; let db_txo = db_txos @@ -7386,6 +7376,7 @@ fn allocations() { .collect(); coloring_map.insert(db_txo.clone(), txo_colorings.into_iter().cloned().collect()); } + txn.commit().unwrap(); coloring_map } @@ -7397,7 +7388,9 @@ fn allocations() { pending_xfer: bool, ) { let coloring_map = get_coloring_map(wallet, unspents_colorable); - let db_asset_transfers = wallet.database().iter_asset_transfers().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let db_asset_transfers = txn.iter_asset_transfers().unwrap(); + txn.commit().unwrap(); let assignments_auto: Vec<_> = amounts_auto .iter() .map(|a| Assignment::Fungible(*a)) @@ -7743,8 +7736,10 @@ fn allocations() { "wallet 2 unspents after 2nd send (WaitingCounterparty)", ); let coloring_map = get_coloring_map(&wallet_2, &unspents_colorable); - let db_batch_transfers = wallet_2.database().iter_batch_transfers().unwrap(); - let db_asset_transfers = wallet_2.database().iter_asset_transfers().unwrap(); + let txn = wallet_2.database().begin_transaction().unwrap(); + let db_batch_transfers = txn.iter_batch_transfers().unwrap(); + let db_asset_transfers = txn.iter_asset_transfers().unwrap(); + txn.commit().unwrap(); // check input colorings let input_colorings: Vec<_> = coloring_map .values() diff --git a/src/wallet/test/send_btc.rs b/src/wallet/test/send_btc.rs index da71c687..249b2f25 100644 --- a/src/wallet/test/send_btc.rs +++ b/src/wallet/test/send_btc.rs @@ -31,14 +31,18 @@ fn success() { assert_eq!(test_get_btc_balance(&mut wallet, online), expected_balance); // balance after send - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let txid = test_send_btc( &mut wallet, online, &test_get_address(&mut rcv_wallet), amount, ); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -196,15 +200,15 @@ fn begin_reservation_interactions() { let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); // no reservations and no SendBtc wallet_transactions initially - assert!(wallet.database().iter_reserved_txos().unwrap().is_empty()); + let txn = wallet.database().begin_transaction().unwrap(); + assert!(txn.iter_reserved_txos().unwrap().is_empty()); assert!( - wallet - .database() - .iter_wallet_transactions() + txn.iter_wallet_transactions() .unwrap() .iter() .all(|wt| wt.r#type != WalletTransactionType::SendBtc) ); + txn.commit().unwrap(); // capture vanilla spendable balance before reservation let balance_before = test_get_btc_balance(&mut wallet, online); @@ -230,11 +234,12 @@ fn begin_reservation_interactions() { assert!(balance_reserved.vanilla.spendable < balance_before.vanilla.spendable); // wallet_transaction(SendBtc) row for this txid exists - let (wt, reservations) = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let (wt, reservations) = txn .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) .unwrap() .expect("should exist after begin"); + txn.commit().unwrap(); assert_eq!(wt.r#type, WalletTransactionType::SendBtc); // one reserved_txo per PSBT input, all pointing to that wt row assert!(reservations.iter().all(|r| r.reserved_for == Some(wt.idx))); @@ -260,7 +265,9 @@ fn begin_reservation_interactions() { // sign + end releases the reservations but keeps the wallet_transaction row let signed_psbt = wallet.sign_psbt(unsigned_psbt_str, None).unwrap(); let _end_txid = wallet.send_btc_end(online, signed_psbt).unwrap(); - assert!(wallet.database().iter_reserved_txos().unwrap().is_empty()); + let txn = wallet.database().begin_transaction().unwrap(); + assert!(txn.iter_reserved_txos().unwrap().is_empty()); + txn.commit().unwrap(); assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); // after end, balance is no longer reduced by reservations (the UTXO is now spent, @@ -268,13 +275,14 @@ fn begin_reservation_interactions() { let balance_after_end = test_get_btc_balance(&mut wallet, online); assert!(balance_after_end.vanilla.spendable > balance_reserved.vanilla.spendable); // the wallet_transaction row is still there (so list_transactions classifies the tx) - let wts: Vec<_> = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let wts: Vec<_> = txn .iter_wallet_transactions() .unwrap() .into_iter() .filter(|wt| wt.txid == psbt_txid && wt.r#type == WalletTransactionType::SendBtc) .collect(); + txn.commit().unwrap(); assert_eq!(wts.len(), 1); // list_transactions sees it as SendBtc @@ -301,28 +309,29 @@ fn begin_reservation_interactions() { let psbt_txid = unsigned_psbt.unsigned_tx.compute_txid().to_string(); // no reservations, no wallet_transaction row yet - assert!(wallet.database().iter_reserved_txos().unwrap().is_empty()); + let txn = wallet.database().begin_transaction().unwrap(); + assert!(txn.iter_reserved_txos().unwrap().is_empty()); assert!( - wallet - .database() - .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) + txn.get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) .unwrap() .is_none() ); + txn.commit().unwrap(); assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); // end still creates the SendBtc row after broadcast (for list_transactions) let signed_psbt = wallet.sign_psbt(unsigned_psbt_str, None).unwrap(); let end_txid = wallet.send_btc_end(online, signed_psbt).unwrap(); assert_eq!(end_txid, psbt_txid); - assert!(wallet.database().iter_reserved_txos().unwrap().is_empty()); - let wts: Vec<_> = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + assert!(txn.iter_reserved_txos().unwrap().is_empty()); + let wts: Vec<_> = txn .iter_wallet_transactions() .unwrap() .into_iter() .filter(|wt| wt.txid == psbt_txid && wt.r#type == WalletTransactionType::SendBtc) .collect(); + txn.commit().unwrap(); assert_eq!(wts.len(), 1); } diff --git a/src/wallet/test/sync.rs b/src/wallet/test/sync.rs new file mode 100644 index 00000000..ea952a5b --- /dev/null +++ b/src/wallet/test/sync.rs @@ -0,0 +1,22 @@ +use super::*; + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn fail() { + initialize(); + + let sync_options = SyncOptions { + keychain: SyncKeychain::Colored, + strategy: SyncStrategy::FastSync, + }; + + // wallets + let (mut wallet, _online) = get_funded_wallet!(); + + // sync input params + // - check online is correct + let wrong_online = Online { id: 1 }; + let result = test_sync_result(&mut wallet, wrong_online, sync_options); + assert!(matches!(result, Err(Error::CannotChangeOnline))); +} diff --git a/src/wallet/test/utils/api.rs b/src/wallet/test/utils/api.rs index e0d914c1..b05e8d83 100644 --- a/src/wallet/test/utils/api.rs +++ b/src/wallet/test/utils/api.rs @@ -688,3 +688,12 @@ pub(crate) fn test_send_btc_result( ) -> Result { wallet.send_btc(online, address.to_string(), amount, FEE_RATE, false) } + +#[cfg(any(feature = "electrum", feature = "esplora"))] +pub(crate) fn test_sync_result( + wallet: &mut Wallet, + online: Online, + options: SyncOptions, +) -> Result<(), Error> { + wallet.sync(online, options) +} diff --git a/src/wallet/test/utils/helpers.rs b/src/wallet/test/utils/helpers.rs index cfec1520..57517330 100644 --- a/src/wallet/test/utils/helpers.rs +++ b/src/wallet/test/utils/helpers.rs @@ -223,7 +223,9 @@ pub(crate) fn check_test_transfer_status_recipient( recipient_id: &str, expected_status: TransferStatus, ) -> bool { - let transfers = wallet.database().iter_transfers().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); let mut recipient_transfers = transfers .iter() .filter(|t| t.recipient_id.as_deref() == Some(recipient_id)); @@ -309,10 +311,10 @@ pub(crate) fn compare_test_directories(src: &Path, dst: &Path, skip: &[&str]) { } pub(crate) fn get_test_batch_transfers(wallet: &Wallet, txid: &str) -> Vec { - wallet - .database() - .iter_batch_transfers() - .unwrap() + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + batch_transfers .into_iter() .filter(|b| b.txid == Some(txid.to_string())) .collect() @@ -322,10 +324,10 @@ pub(crate) fn get_test_asset_transfers( wallet: &Wallet, batch_transfer_idx: i32, ) -> Vec { - wallet - .database() - .iter_asset_transfers() - .unwrap() + let txn = wallet.database().begin_transaction().unwrap(); + let asset_transfers = txn.iter_asset_transfers().unwrap(); + txn.commit().unwrap(); + asset_transfers .into_iter() .filter(|at| at.batch_transfer_idx == batch_transfer_idx) .collect() @@ -335,10 +337,10 @@ pub(crate) fn get_test_transfers( wallet: &Wallet, asset_transfer_idx: i32, ) -> impl Iterator { - wallet - .database() - .iter_transfers() - .unwrap() + let txn = wallet.database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); + transfers .into_iter() .filter(move |t| t.asset_transfer_idx == asset_transfer_idx) } @@ -352,20 +354,20 @@ pub(crate) fn get_test_asset_transfer(wallet: &Wallet, batch_transfer_idx: i32) } pub(crate) fn get_test_colorings(wallet: &Wallet, asset_transfer_idx: i32) -> Vec { - wallet - .database() - .iter_colorings() - .unwrap() + let txn = wallet.database().begin_transaction().unwrap(); + let colorings = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + colorings .into_iter() .filter(|c| c.asset_transfer_idx == asset_transfer_idx) .collect() } pub(crate) fn get_test_transfer_recipient(wallet: &Wallet, recipient_id: &str) -> DbTransfer { - let mut transfers = wallet - .database() - .iter_transfers() - .unwrap() + let txn = wallet.database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); + let mut transfers = transfers .into_iter() .filter(|t| t.recipient_id == Some(recipient_id.to_string()) && t.incoming); let transfer = transfers.next().unwrap(); @@ -412,7 +414,9 @@ pub(crate) fn get_test_transfer_data( wallet: &Wallet, transfer: &DbTransfer, ) -> (TransferData, DbAssetTransfer) { - let db_data = wallet.database().get_db_data(false).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let db_data = txn.get_db_data(false).unwrap(); + txn.commit().unwrap(); let (asset_transfer, batch_transfer) = transfer .related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) .unwrap(); @@ -432,7 +436,9 @@ pub(crate) fn get_test_transfer_related( wallet: &Wallet, transfer: &DbTransfer, ) -> (DbAssetTransfer, DbBatchTransfer) { - let db_data = wallet.database().get_db_data(false).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let db_data = txn.get_db_data(false).unwrap(); + txn.commit().unwrap(); transfer .related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) .unwrap() @@ -649,18 +655,21 @@ pub(crate) fn extract_opouts_from_transfer( .collect::>(); assert_eq!(asset_transfers.len(), 1); let asset_transfer = asset_transfers.first().unwrap(); - let colorings: Vec = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let colorings: Vec = txn .iter_colorings() .unwrap() .into_iter() .filter(|c| c.asset_transfer_idx == asset_transfer.idx) .collect(); + txn.commit().unwrap(); if colorings.is_empty() { panic!("cannot find colorings for this transfer"); } let txo_indices = colorings.iter().map(|c| c.txo_idx).collect::>(); - let db_txos = wallet.database().iter_txos().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let db_txos = txn.iter_txos().unwrap(); + txn.commit().unwrap(); let relevant_txos = db_txos.into_iter().filter(|t| txo_indices.contains(&t.idx)); let mut outpoints = relevant_txos .map(|txo| OutPoint::from(txo.clone())) @@ -706,10 +715,12 @@ pub(crate) fn show_unspent_colorings(wallet: &mut impl RgbWalletOpsOnline, msg: let unspents = test_list_unspents(wallet, None, false) .into_iter() .filter(|u| u.utxo.colorable); - let db_txos = wallet.database().iter_txos().unwrap(); - let db_colorings = wallet.database().iter_colorings().unwrap(); - let db_asset_transfers = wallet.database().iter_asset_transfers().unwrap(); - let db_batch_transfers = wallet.database().iter_batch_transfers().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let db_txos = txn.iter_txos().unwrap(); + let db_colorings = txn.iter_colorings().unwrap(); + let db_asset_transfers = txn.iter_asset_transfers().unwrap(); + let db_batch_transfers = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); let pending_blind_transfers = get_pending_blind_transfers(wallet); for unspent in unspents { let outpoint = unspent.utxo.outpoint; diff --git a/src/wallet/test/witness_receive.rs b/src/wallet/test/witness_receive.rs index c0315f13..f89cae92 100644 --- a/src/wallet/test/witness_receive.rs +++ b/src/wallet/test/witness_receive.rs @@ -11,7 +11,9 @@ fn success() { let (mut wallet, online) = get_funded_wallet!(); // only mandatory fields - let bak_info_before = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); let receive_data = wallet .witness_receive( None, @@ -21,7 +23,9 @@ fn success() { MIN_CONFIRMATIONS, ) .unwrap(); - let bak_info_after = wallet.database().get_backup_info().unwrap().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(receive_data.expiration_timestamp.is_none()); let decoded_invoice = Invoice::new(receive_data.invoice).unwrap(); @@ -94,10 +98,11 @@ fn success() { ); assert!(result.is_ok()); let transfer = get_test_transfer_recipient(&wallet, &result.unwrap().recipient_id); - let tte_data = wallet - .database() + let txn = wallet.database().begin_transaction().unwrap(); + let tte_data = txn .get_transfer_transport_endpoints_data(transfer.idx) .unwrap(); + txn.commit().unwrap(); assert_eq!(tte_data.len(), transport_endpoints.len()); } From 02f682b3afebf70165cfcb4e2b7cc68e37c708e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 7 May 2026 15:59:46 +0200 Subject: [PATCH 03/12] fix DB inefficiencies --- src/database/mod.rs | 87 ++++++++++++++----------------------------- src/wallet/offline.rs | 38 ++++++------------- src/wallet/online.rs | 35 +++++++++-------- 3 files changed, 56 insertions(+), 104 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index e137e5b2..2e461a94 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -247,9 +247,8 @@ impl DbTxn { pub(crate) fn set_batch_transfer( &self, - batch_transfer: DbBatchTransferActMod, + mut batch_transfer: DbBatchTransferActMod, ) -> Result { - let mut batch_transfer = batch_transfer; batch_transfer.updated_at = batch_transfer.created_at.clone(); let res = block_on(BatchTransfer::insert(batch_transfer).exec(self.inner()))?; Ok(res.last_insert_id) @@ -492,7 +491,7 @@ impl DbTxn { pub(crate) fn get_asset(&self, asset_id: String) -> Result, Error> { Ok(block_on( Asset::find() - .filter(asset::Column::Id.eq(asset_id.clone())) + .filter(asset::Column::Id.eq(asset_id)) .one(self.inner()), )?) } @@ -515,11 +514,7 @@ impl DbTxn { #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) fn get_media(&self, media_idx: i32) -> Result, Error> { - Ok(block_on( - Media::find() - .filter(media::Column::Idx.eq(media_idx)) - .one(self.inner()), - )?) + Ok(block_on(Media::find_by_id(media_idx).one(self.inner()))?) } pub(crate) fn get_media_by_digest(&self, digest: String) -> Result, Error> { @@ -679,31 +674,15 @@ impl DbTxn { colorings: Option>, txos: Option>, ) -> Result { - let batch_transfers = if let Some(bt) = batch_transfers { - bt - } else { - self.iter_batch_transfers()? - }; - let asset_transfers = if let Some(at) = asset_transfers { - at - } else { - self.iter_asset_transfers()? - }; - let transfers = if let Some(t) = transfers { - t - } else { - self.iter_transfers()? - }; - let colorings = if let Some(cs) = colorings { - cs - } else { - self.iter_colorings()? - }; - let txos = if let Some(t) = txos { - t - } else { - self.iter_txos()? - }; + let batch_transfers = batch_transfers + .map(Ok) + .unwrap_or_else(|| self.iter_batch_transfers())?; + let asset_transfers = asset_transfers + .map(Ok) + .unwrap_or_else(|| self.iter_asset_transfers())?; + let transfers = transfers.map(Ok).unwrap_or_else(|| self.iter_transfers())?; + let colorings = colorings.map(Ok).unwrap_or_else(|| self.iter_colorings())?; + let txos = txos.map(Ok).unwrap_or_else(|| self.iter_txos())?; let txos_allocations = self.get_rgb_allocations( txos, @@ -812,7 +791,7 @@ impl DbTxn { #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) fn get_asset_ids(&self) -> Result, Error> { - Ok(self.iter_assets()?.iter().map(|a| a.id.clone()).collect()) + Ok(self.iter_assets()?.into_iter().map(|a| a.id).collect()) } pub(crate) fn check_asset_exists(&self, asset_id: String) -> Result { @@ -848,9 +827,9 @@ impl DbTxn { fn get_utxo_allocations( &self, utxo: &DbTxo, - colorings: Vec, - asset_transfers: Vec, - batch_transfers: Vec, + colorings: &[DbColoring], + asset_transfers: &[DbAssetTransfer], + batch_transfers: &[DbBatchTransfer], ) -> Result, Error> { let utxo_colorings: Vec<&DbColoring> = colorings.iter().filter(|c| c.txo_idx == utxo.idx).collect(); @@ -886,26 +865,14 @@ impl DbTxn { asset_transfers: Option>, transfers: Option>, ) -> Result, Error> { - let batch_transfers = if let Some(bt) = batch_transfers { - bt - } else { - self.iter_batch_transfers()? - }; - let asset_transfers = if let Some(at) = asset_transfers { - at - } else { - self.iter_asset_transfers()? - }; - let colorings = if let Some(cs) = colorings { - cs - } else { - self.iter_colorings()? - }; - let transfers = if let Some(ts) = transfers { - ts - } else { - self.iter_transfers()? - }; + let batch_transfers = batch_transfers + .map(Ok) + .unwrap_or_else(|| self.iter_batch_transfers())?; + let asset_transfers = asset_transfers + .map(Ok) + .unwrap_or_else(|| self.iter_asset_transfers())?; + let colorings = colorings.map(Ok).unwrap_or_else(|| self.iter_colorings())?; + let transfers = transfers.map(Ok).unwrap_or_else(|| self.iter_transfers())?; let pending_blinded_utxos = transfers .iter() @@ -929,9 +896,9 @@ impl DbTxn { utxo: t.clone(), rgb_allocations: self.get_utxo_allocations( t, - colorings.clone(), - asset_transfers.clone(), - batch_transfers.clone(), + &colorings, + &asset_transfers, + &batch_transfers, )?, pending_blinded: *pending_blinded_utxos.get(&t.outpoint()).unwrap_or(&0), }) diff --git a/src/wallet/offline.rs b/src/wallet/offline.rs index b5e9b2e6..0d25d5be 100644 --- a/src/wallet/offline.rs +++ b/src/wallet/offline.rs @@ -560,10 +560,8 @@ pub trait WalletOffline: WalletBackup { let settled = self.get_total_issue_amount(&amounts, false)?; - let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = txn.get_rgb_allocations( - txn.get_unspent_txos(db_data.txos.clone())?, + txn.get_unspent_txos(txn.iter_txos()?)?, None, None, None, @@ -685,10 +683,8 @@ pub trait WalletOffline: WalletBackup { }); } - let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = txn.get_rgb_allocations( - txn.get_unspent_txos(db_data.txos.clone())?, + txn.get_unspent_txos(txn.iter_txos()?)?, None, None, None, @@ -815,10 +811,8 @@ pub trait WalletOffline: WalletBackup { let settled = self.get_total_issue_amount(&amounts, false)?; - let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = txn.get_rgb_allocations( - txn.get_unspent_txos(db_data.txos.clone())?, + txn.get_unspent_txos(txn.iter_txos()?)?, None, None, None, @@ -934,10 +928,8 @@ pub trait WalletOffline: WalletBackup { } let max_supply = settled + inflation_amt; - let db_data = txn.get_db_data(false)?; - let mut unspents: Vec = txn.get_rgb_allocations( - txn.get_unspent_txos(db_data.txos.clone())?, + txn.get_unspent_txos(txn.iter_txos()?)?, None, None, None, @@ -1316,7 +1308,7 @@ pub trait WalletOffline: WalletBackup { batch_transfer_idx: Option, no_asset_only: bool, ) -> Result { - let db_data = txn.get_db_data(false)?; + let db_data = txn.get_db_data(true)?; let mut transfers_changed = false; if let Some(batch_transfer_idx) = batch_transfer_idx { @@ -2243,44 +2235,38 @@ pub trait WalletOffline: WalletBackup { let db_data = txn.get_db_data(false)?; - let mut allocation_txos = txn.get_unspent_txos(db_data.txos.clone())?; let spent_txos_ids: Vec = db_data .txos - .clone() - .into_iter() + .iter() .filter(|t| t.spent) - .map(|u| u.idx) + .map(|t| t.idx) .collect(); let waiting_confs_batch_transfer_ids: Vec = db_data .batch_transfers - .clone() - .into_iter() + .iter() .filter(|t| t.waiting_confirmations()) .map(|t| t.idx) .collect(); let waiting_confs_transfer_ids: Vec = db_data .asset_transfers - .clone() - .into_iter() + .iter() .filter(|t| waiting_confs_batch_transfer_ids.contains(&t.batch_transfer_idx)) .map(|t| t.idx) .collect(); let almost_spent_txos_ids: Vec = db_data .colorings - .clone() - .into_iter() + .iter() .filter(|c| { waiting_confs_transfer_ids.contains(&c.asset_transfer_idx) && spent_txos_ids.contains(&c.txo_idx) }) .map(|c| c.txo_idx) .collect(); - let mut spent_txos = db_data + let allocation_txos: Vec = db_data .txos .into_iter() - .filter(|t| almost_spent_txos_ids.contains(&t.idx)) + .filter(|t| !t.spent || almost_spent_txos_ids.contains(&t.idx)) .collect(); - allocation_txos.append(&mut spent_txos); let mut txos_allocations = txn.get_rgb_allocations( allocation_txos, diff --git a/src/wallet/online.rs b/src/wallet/online.rs index 299a92c8..c2d23def 100644 --- a/src/wallet/online.rs +++ b/src/wallet/online.rs @@ -423,7 +423,7 @@ pub trait WalletOnline: WalletOffline { &mut self, txn: &DbTxn, batch_transfer: &DbBatchTransfer, - db_data: &mut DbData, + db_data: &DbData, ) -> Result { let updated_batch_transfer = match self.refresh_transfer(txn, batch_transfer, db_data, &[], true) { @@ -460,7 +460,7 @@ pub trait WalletOnline: WalletOffline { )?; } - let mut db_data = txn.get_db_data(false)?; + let db_data = txn.get_db_data(false)?; let mut transfers_changed = false; let mut cannot_fail = false; @@ -489,18 +489,17 @@ pub trait WalletOnline: WalletOffline { transfers_changed = true; if let TryFailBatchTransferOutcome::Refreshed = - self.try_fail_batch_transfer(txn, &batch_transfer, &mut db_data)? + self.try_fail_batch_transfer(txn, &batch_transfer, &db_data)? { cannot_fail = true; } } else { // fail all expired transfers that are in a fallible status let now = now().unix_timestamp(); - let expired_batch_transfers = db_data.batch_transfers.clone().into_iter().filter(|t| { + for batch_transfer in db_data.batch_transfers.iter().filter(|t| { let expired = t.expiration.unwrap_or(now) < now; expired && t.is_fallible() - }); - for batch_transfer in expired_batch_transfers { + }) { if no_asset_only { let connected_assets = batch_transfer .get_asset_transfers(&db_data.asset_transfers)? @@ -511,7 +510,7 @@ pub trait WalletOnline: WalletOffline { } } transfers_changed = true; - self.try_fail_batch_transfer(txn, &batch_transfer, &mut db_data)?; + self.try_fail_batch_transfer(txn, batch_transfer, &db_data)?; } } @@ -1411,7 +1410,7 @@ pub trait WalletOnline: WalletOffline { &mut self, txn: &DbTxn, batch_transfer: &DbBatchTransfer, - db_data: &mut DbData, + db_data: &DbData, ) -> Result, Error> { debug!(self.logger(), "Waiting safe height..."); @@ -1463,7 +1462,7 @@ pub trait WalletOnline: WalletOffline { &mut self, txn: &DbTxn, batch_transfer: &DbBatchTransfer, - db_data: &mut DbData, + db_data: &DbData, ) -> Result, Error> { debug!(self.logger(), "Waiting ACK..."); @@ -1669,7 +1668,7 @@ pub trait WalletOnline: WalletOffline { &mut self, txn: &DbTxn, transfer: &DbBatchTransfer, - db_data: &mut DbData, + db_data: &DbData, incoming: bool, ) -> Result, Error> { if incoming { @@ -1683,7 +1682,7 @@ pub trait WalletOnline: WalletOffline { &mut self, txn: &DbTxn, transfer: &DbBatchTransfer, - db_data: &mut DbData, + db_data: &DbData, filter: &[RefreshFilter], skip_sync: bool, ) -> Result, Error> { @@ -1736,10 +1735,10 @@ pub trait WalletOnline: WalletOffline { db_data.batch_transfers.retain(|t| t.waiting()); let mut refresh_result = HashMap::new(); - for transfer in db_data.batch_transfers.clone() { + for transfer in &db_data.batch_transfers { let mut failure = None; let mut updated_status = None; - match self.refresh_transfer(txn, &transfer, &mut db_data, &filter, skip_sync) { + match self.refresh_transfer(txn, transfer, &db_data, &filter, skip_sync) { Ok(Some(updated_transfer)) => updated_status = Some(updated_transfer.status), Err(e) => failure = Some(e), _ => {} @@ -2847,14 +2846,14 @@ pub trait WalletOnline: WalletOffline { let db_data = txn.get_db_data(false)?; - let utxos = txn.get_unspent_txos(db_data.txos.clone())?; + let utxos = txn.get_unspent_txos(db_data.txos)?; let unspents = txn.get_rgb_allocations( utxos, - Some(db_data.colorings.clone()), - Some(db_data.batch_transfers.clone()), - Some(db_data.asset_transfers.clone()), - Some(db_data.transfers.clone()), + Some(db_data.colorings), + Some(db_data.batch_transfers), + Some(db_data.asset_transfers), + Some(db_data.transfers), )?; #[cfg(test)] From 44c01cd0b31af7e254f838b97d590a6907ca318f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 7 May 2026 17:27:10 +0200 Subject: [PATCH 04/12] simplify issuance methods --- src/wallet/multisig.rs | 92 +++++++++++++-------------- src/wallet/offline.rs | 137 +--------------------------------------- src/wallet/singlesig.rs | 59 +++++++---------- 3 files changed, 67 insertions(+), 221 deletions(-) diff --git a/src/wallet/multisig.rs b/src/wallet/multisig.rs index 69547e38..9780d47e 100644 --- a/src/wallet/multisig.rs +++ b/src/wallet/multisig.rs @@ -1303,14 +1303,14 @@ impl MultisigWallet { precision: u8, amounts: Vec, ) -> Result { + info!(self.logger(), "Issuing NIA..."); self.check_online(online)?; self.check_is_cosigner()?; let txn = self.database().begin_transaction()?; - let res = - self.issue_asset_nia_with_impl(&txn, ticker, name, precision, amounts, |issue_data| { - self.upload_and_process_issuance(&txn, &issue_data, vec![]) - })?; + let issue_data = self.create_nia_contract(&txn, ticker, name, precision, amounts)?; + let res = self.upload_and_process_issuance(&txn, &issue_data, vec![])?; txn.commit()?; + info!(self.logger(), "Issue asset NIA completed"); Ok(res) } @@ -1332,10 +1332,11 @@ impl MultisigWallet { media_file_path: Option, attachments_file_paths: Vec, ) -> Result { + info!(self.logger(), "Issuing UDA..."); self.check_online(online)?; self.check_is_cosigner()?; let txn = self.database().begin_transaction()?; - let res = self.issue_asset_uda_with_impl( + let issue_data = self.create_uda_contract( &txn, ticker, name, @@ -1343,31 +1344,30 @@ impl MultisigWallet { precision, media_file_path, attachments_file_paths, - |issue_data| { - let mut files = vec![]; - if let Some(media) = &issue_data.asset_data.token.as_ref().unwrap().media { - files.push(( - FileType::Media, - FileSource::Path(media.file_path.clone().into()), - )) - } - for media in issue_data - .asset_data - .token - .as_ref() - .unwrap() - .attachments - .values() - { - files.push(( - FileType::Media, - FileSource::Path(media.file_path.clone().into()), - )) - } - self.upload_and_process_issuance(&txn, &issue_data, files) - }, )?; + let mut files = vec![]; + if let Some(media) = &issue_data.asset_data.token.as_ref().unwrap().media { + files.push(( + FileType::Media, + FileSource::Path(media.file_path.clone().into()), + )) + } + for media in issue_data + .asset_data + .token + .as_ref() + .unwrap() + .attachments + .values() + { + files.push(( + FileType::Media, + FileSource::Path(media.file_path.clone().into()), + )) + } + let res = self.upload_and_process_issuance(&txn, &issue_data, files)?; txn.commit()?; + info!(self.logger(), "Issue asset UDA completed"); Ok(res) } @@ -1391,28 +1391,22 @@ impl MultisigWallet { amounts: Vec, file_path: Option, ) -> Result { + info!(self.logger(), "Issuing CFA..."); self.check_online(online)?; self.check_is_cosigner()?; let txn = self.database().begin_transaction()?; - let res = self.issue_asset_cfa_with_impl( - &txn, - name, - details, - precision, - amounts, - file_path, - |issue_data| { - let mut files = vec![]; - if let Some(media) = &issue_data.asset_data.media { - files.push(( - FileType::Media, - FileSource::Path(media.file_path.clone().into()), - )) - } - self.upload_and_process_issuance(&txn, &issue_data, files) - }, - )?; + let issue_data = + self.create_cfa_contract(&txn, name, details, precision, amounts, file_path)?; + let mut files = vec![]; + if let Some(media) = &issue_data.asset_data.media { + files.push(( + FileType::Media, + FileSource::Path(media.file_path.clone().into()), + )) + } + let res = self.upload_and_process_issuance(&txn, &issue_data, files)?; txn.commit()?; + info!(self.logger(), "Issue asset CFA completed"); Ok(res) } @@ -1437,10 +1431,11 @@ impl MultisigWallet { inflation_amounts: Vec, reject_list_url: Option, ) -> Result { + info!(self.logger(), "Issuing IFA..."); self.check_online(online)?; self.check_is_cosigner()?; let txn = self.database().begin_transaction()?; - let res = self.issue_asset_ifa_with_impl( + let issue_data = self.create_ifa_contract( &txn, ticker, name, @@ -1448,9 +1443,10 @@ impl MultisigWallet { amounts, inflation_amounts, reject_list_url, - |issue_data| self.upload_and_process_issuance(&txn, &issue_data, vec![]), )?; + let res = self.upload_and_process_issuance(&txn, &issue_data, vec![])?; txn.commit()?; + info!(self.logger(), "Issue asset IFA completed"); Ok(res) } diff --git a/src/wallet/offline.rs b/src/wallet/offline.rs index 0d25d5be..05c982d6 100644 --- a/src/wallet/offline.rs +++ b/src/wallet/offline.rs @@ -84,141 +84,6 @@ pub trait WalletOffline: WalletBackup { Ok(()) } - fn issue_asset_with_impl( - &self, - schema: AssetSchema, - log_msg: String, - begin_fn: B, - impl_fn: F, - ) -> Result - where - F: FnOnce(IssueData) -> Result, - B: FnOnce() -> Result, - { - info!(self.logger(), "Issuing {schema} with {}...", log_msg); - let issue_data = begin_fn()?; - let asset = impl_fn(issue_data)?; - info!(self.logger(), "Issue asset {schema} completed"); - Ok(asset) - } - - fn issue_asset_nia_with_impl( - &self, - txn: &DbTxn, - ticker: String, - name: String, - precision: u8, - amounts: Vec, - impl_fn: F, - ) -> Result - where - F: FnOnce(IssueData) -> Result, - { - self.issue_asset_with_impl( - AssetSchema::Nia, - format!( - "ticker '{}' name '{}' precision '{}' amounts '{:?}'", - ticker, name, precision, amounts - ), - || self.create_nia_contract(txn, ticker, name, precision, amounts), - impl_fn, - ) - } - - fn issue_asset_uda_with_impl( - &self, - txn: &DbTxn, - ticker: String, - name: String, - details: Option, - precision: u8, - media_file_path: Option, - attachments_file_paths: Vec, - impl_fn: F, - ) -> Result - where - F: FnOnce(IssueData) -> Result, - { - self.issue_asset_with_impl( - AssetSchema::Uda, - format!( - "ticker '{}' name '{}' precision '{}'", - ticker, name, precision - ), - || { - self.create_uda_contract( - txn, - ticker, - name, - details, - precision, - media_file_path, - attachments_file_paths, - ) - }, - impl_fn, - ) - } - - fn issue_asset_cfa_with_impl( - &self, - txn: &DbTxn, - name: String, - details: Option, - precision: u8, - amounts: Vec, - file_path: Option, - impl_fn: F, - ) -> Result - where - F: FnOnce(IssueData) -> Result, - { - self.issue_asset_with_impl( - AssetSchema::Cfa, - format!( - "name '{}' precision '{}' amounts '{:?}'", - name, precision, amounts - ), - || self.create_cfa_contract(txn, name, details, precision, amounts, file_path), - impl_fn, - ) - } - - fn issue_asset_ifa_with_impl( - &self, - txn: &DbTxn, - ticker: String, - name: String, - precision: u8, - amounts: Vec, - inflation_amounts: Vec, - reject_list_url: Option, - impl_fn: F, - ) -> Result - where - F: FnOnce(IssueData) -> Result, - { - self.issue_asset_with_impl( - AssetSchema::Ifa, - format!( - "ticker '{}' name '{}' precision '{}' amounts '{:?}' inflation amounts {:?}", - ticker, name, precision, amounts, inflation_amounts - ), - || { - self.creata_ifa_contract( - txn, - ticker, - name, - precision, - amounts, - inflation_amounts, - reject_list_url, - ) - }, - impl_fn, - ) - } - fn filter_unspents(&self, keychain: KeychainKind) -> impl Iterator + '_ { self.bdk_wallet() .list_unspent() @@ -907,7 +772,7 @@ pub trait WalletOffline: WalletBackup { }) } - fn creata_ifa_contract( + fn create_ifa_contract( &self, txn: &DbTxn, ticker: String, diff --git a/src/wallet/singlesig.rs b/src/wallet/singlesig.rs index f6050bde..f4c9faf8 100644 --- a/src/wallet/singlesig.rs +++ b/src/wallet/singlesig.rs @@ -320,9 +320,7 @@ impl Wallet { ) -> Result { let mut runtime = self.rgb_runtime()?; let asset = self.import_and_save_contract(txn, issue_data, &mut runtime)?; - let result = T::from_issuance(txn, self, &asset, issue_data)?; - self.update_backup_info(txn, false)?; - Ok(result) + T::from_issuance(txn, self, &asset, issue_data) } /// Issue a new RGB NIA asset with the provided `ticker`, `name`, `precision` and `amounts`, @@ -340,12 +338,13 @@ impl Wallet { precision: u8, amounts: Vec, ) -> Result { + info!(self.logger(), "Issuing NIA..."); let txn = self.database().begin_transaction()?; - let res = - self.issue_asset_nia_with_impl(&txn, ticker, name, precision, amounts, |issue_data| { - self.finalize_offline_issuance(&txn, &issue_data) - })?; + let issue_data = self.create_nia_contract(&txn, ticker, name, precision, amounts)?; + let res = self.finalize_offline_issuance(&txn, &issue_data)?; + self.update_backup_info(&txn, false)?; txn.commit()?; + info!(self.logger(), "Issue asset NIA completed"); Ok(res) } @@ -366,8 +365,9 @@ impl Wallet { media_file_path: Option, attachments_file_paths: Vec, ) -> Result { + info!(self.logger(), "Issuing UDA..."); let txn = self.database().begin_transaction()?; - let res = self.issue_asset_uda_with_impl( + let issue_data = self.create_uda_contract( &txn, ticker, name, @@ -375,26 +375,11 @@ impl Wallet { precision, media_file_path, attachments_file_paths, - |issue_data| { - let mut runtime = self.rgb_runtime()?; - let asset = self.import_and_save_contract(&txn, &issue_data, &mut runtime)?; - let asset_uda = AssetUDA::get_asset_details( - &txn, - self, - &asset, - issue_data.asset_data.token.map(|t| t.into()), - None, - None, - None, - None, - None, - None, - )?; - self.update_backup_info(&txn, false)?; - Ok(asset_uda) - }, )?; + let res = self.finalize_offline_issuance(&txn, &issue_data)?; + self.update_backup_info(&txn, false)?; txn.commit()?; + info!(self.logger(), "Issue asset UDA completed"); Ok(res) } @@ -417,17 +402,14 @@ impl Wallet { amounts: Vec, file_path: Option, ) -> Result { + info!(self.logger(), "Issuing CFA..."); let txn = self.database().begin_transaction()?; - let res = self.issue_asset_cfa_with_impl( - &txn, - name, - details, - precision, - amounts, - file_path, - |issue_data| self.finalize_offline_issuance(&txn, &issue_data), - )?; + let issue_data = + self.create_cfa_contract(&txn, name, details, precision, amounts, file_path)?; + let res = self.finalize_offline_issuance(&txn, &issue_data)?; + self.update_backup_info(&txn, false)?; txn.commit()?; + info!(self.logger(), "Issue asset CFA completed"); Ok(res) } @@ -451,8 +433,9 @@ impl Wallet { inflation_amounts: Vec, reject_list_url: Option, ) -> Result { + info!(self.logger(), "Issuing IFA..."); let txn = self.database().begin_transaction()?; - let res = self.issue_asset_ifa_with_impl( + let issue_data = self.create_ifa_contract( &txn, ticker, name, @@ -460,9 +443,11 @@ impl Wallet { amounts, inflation_amounts, reject_list_url, - |issue_data| self.finalize_offline_issuance(&txn, &issue_data), )?; + let res = self.finalize_offline_issuance(&txn, &issue_data)?; + self.update_backup_info(&txn, false)?; txn.commit()?; + info!(self.logger(), "Issue asset IFA completed"); Ok(res) } From 14e4480f2c96e0a54bb8d8a749f295e494dba3e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 7 May 2026 22:12:43 +0200 Subject: [PATCH 05/12] add missing begin_end tests + fix backup info update --- src/wallet/multisig.rs | 5 --- src/wallet/singlesig.rs | 24 ++++++++-- src/wallet/test/burn.rs | 63 ++++++++++++++++++++++++++ src/wallet/test/create_utxos.rs | 48 ++++++++++++++++++++ src/wallet/test/drain_to.rs | 49 ++++++++++++++++++++ src/wallet/test/inflate.rs | 63 ++++++++++++++++++++++++++ src/wallet/test/multisig/utils.rs | 10 ++--- src/wallet/test/send.rs | 75 +++++++++++++++++++++++++++++++ src/wallet/test/send_btc.rs | 54 ++++++++++++++++++++-- 9 files changed, 374 insertions(+), 17 deletions(-) diff --git a/src/wallet/multisig.rs b/src/wallet/multisig.rs index 9780d47e..b76944d7 100644 --- a/src/wallet/multisig.rs +++ b/src/wallet/multisig.rs @@ -2161,7 +2161,6 @@ impl MultisigWallet { let psbt = self.create_utxos_begin_impl(&txn, up_to, num, size, fee_rate, skip_sync, true)?; let res = self.post_operation(OperationType::CreateUtxos, PostData::Psbt(psbt))?; - self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Initiate creating UTXOs completed"); Ok(res) @@ -2186,7 +2185,6 @@ impl MultisigWallet { let txn = self.database().begin_transaction()?; let psbt = self.send_btc_begin_impl(&txn, address, amount, fee_rate, skip_sync, true)?; let res = self.post_operation(OperationType::SendBtc, PostData::Psbt(psbt))?; - self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Initiate sending BTC completed"); Ok(res) @@ -2241,7 +2239,6 @@ impl MultisigWallet { OperationType::SendRgb, PostData::BeginOperationData(Box::new(data)), )?; - self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Initiate sending completed"); Ok(res) @@ -2283,7 +2280,6 @@ impl MultisigWallet { OperationType::Inflation, PostData::BeginOperationData(Box::new(data)), )?; - self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Initiate inflating completed"); Ok(res) @@ -2315,7 +2311,6 @@ impl MultisigWallet { OperationType::Burn, PostData::BeginOperationData(Box::new(data)), )?; - self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Initiate burning completed"); Ok(res) diff --git a/src/wallet/singlesig.rs b/src/wallet/singlesig.rs index f4c9faf8..a600e15e 100644 --- a/src/wallet/singlesig.rs +++ b/src/wallet/singlesig.rs @@ -654,6 +654,9 @@ impl Wallet { let txn = self.database().begin_transaction()?; let res = self.create_utxos_begin_impl(&txn, up_to, num, size, fee_rate, skip_sync, dry_run)?; + if !dry_run { + self.update_backup_info(&txn, false)?; + } txn.commit()?; info!(self.logger(), "Create UTXOs (begin) completed"); Ok(res.to_string()) @@ -673,6 +676,7 @@ impl Wallet { let psbt = Psbt::from_str(&signed_psbt)?; let txn = self.database().begin_transaction()?; let res = self.create_utxos_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Create UTXOs (end) completed"); Ok(res) @@ -741,6 +745,9 @@ impl Wallet { self.check_online(online)?; let txn = self.database().begin_transaction()?; let psbt = self.drain_to_begin_impl(&txn, address, fee_rate, dry_run)?; + if !dry_run { + self.update_backup_info(&txn, false)?; + } txn.commit()?; info!(self.logger(), "Drain (begin) completed"); Ok(psbt.to_string()) @@ -861,7 +868,9 @@ impl Wallet { expiration_timestamp.map(|t| t as i64), dry_run, )?; - self.update_backup_info(&txn, false)?; + if !dry_run { + self.update_backup_info(&txn, false)?; + } txn.commit()?; info!(self.logger(), "Send (begin) completed"); Ok(SendBeginResult { @@ -927,6 +936,7 @@ impl Wallet { self.send_btc_begin_impl(&txn, address, amount, fee_rate, skip_sync, true)?; self.sign_psbt_impl(&mut psbt, None)?; let res = self.send_btc_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Send BTC completed"); Ok(res) @@ -958,6 +968,9 @@ impl Wallet { self.check_online(online)?; let txn = self.database().begin_transaction()?; let res = self.send_btc_begin_impl(&txn, address, amount, fee_rate, skip_sync, dry_run)?; + if !dry_run { + self.update_backup_info(&txn, false)?; + } txn.commit()?; info!(self.logger(), "Send BTC (begin) completed"); Ok(res.to_string()) @@ -977,6 +990,7 @@ impl Wallet { let psbt = Psbt::from_str(&signed_psbt)?; let txn = self.database().begin_transaction()?; let res = self.send_btc_end_impl(&txn, &psbt)?; + self.update_backup_info(&txn, false)?; txn.commit()?; info!(self.logger(), "Send BTC (end) completed"); Ok(res) @@ -1065,7 +1079,9 @@ impl Wallet { min_confirmations, dry_run, )?; - self.update_backup_info(&txn, false)?; + if !dry_run { + self.update_backup_info(&txn, false)?; + } txn.commit()?; info!(self.logger(), "Inflate (begin) completed"); Ok(InflateBeginResult { @@ -1167,7 +1183,9 @@ impl Wallet { let txn = self.database().begin_transaction()?; let begin_operation_data = self.burn_begin_impl(&txn, asset_id, amount, fee_rate, min_confirmations, dry_run)?; - self.update_backup_info(&txn, false)?; + if !dry_run { + self.update_backup_info(&txn, false)?; + } txn.commit()?; info!(self.logger(), "Burn (begin) completed"); Ok(BurnBeginResult { diff --git a/src/wallet/test/burn.rs b/src/wallet/test/burn.rs index e90be08b..015b3e05 100644 --- a/src/wallet/test/burn.rs +++ b/src/wallet/test/burn.rs @@ -607,3 +607,66 @@ fn fail() { let result = test_burn_end_result(&mut wallet_2, online_2, &signed_psbt); assert_matches!(result, Err(Error::UnknownTransfer { txid }) if txid == psbt_txid); } + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn begin_end() { + initialize(); + + let (mut wallet, online) = get_funded_wallet!(); + let asset = test_issue_asset_ifa(&mut wallet, online, None, None, None); + + // begin does not update backup_info with dry_run=true + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let _res = wallet + .burn_begin( + online, + asset.asset_id.clone(), + AMOUNT, + FEE_RATE, + MIN_CONFIRMATIONS, + true, + ) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert_eq!( + bak_info_after.last_operation_timestamp, + bak_info_before.last_operation_timestamp + ); + + // begin does update backup_info with dry_run=false + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let res = wallet + .burn_begin( + online, + asset.asset_id.clone(), + AMOUNT, + FEE_RATE, + MIN_CONFIRMATIONS, + false, + ) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + + let signed_psbt = wallet.sign_psbt(res.psbt, None).unwrap(); + + // end updates backup_info + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + wallet.burn_end(online, signed_psbt).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); +} diff --git a/src/wallet/test/create_utxos.rs b/src/wallet/test/create_utxos.rs index 4fc928db..9bb0069f 100644 --- a/src/wallet/test/create_utxos.rs +++ b/src/wallet/test/create_utxos.rs @@ -427,3 +427,51 @@ fn begin_reservation_interactions() { }) )); } + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn begin_end() { + initialize(); + + let (mut wallet, online) = get_funded_noutxo_wallet!(); + + // begin does not update backup_info with dry_run=true + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let _psbt = wallet + .create_utxos_begin(online, true, None, None, FEE_RATE, false, true) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert_eq!( + bak_info_after.last_operation_timestamp, + bak_info_before.last_operation_timestamp + ); + + // begin does update backup_info with dry_run=false + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let psbt = wallet + .create_utxos_begin(online, true, None, None, FEE_RATE, false, false) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + + let signed_psbt = wallet.sign_psbt(psbt, None).unwrap(); + + // end updates backup_info + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + wallet.create_utxos_end(online, signed_psbt).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); +} diff --git a/src/wallet/test/drain_to.rs b/src/wallet/test/drain_to.rs index 710e761b..5309964a 100644 --- a/src/wallet/test/drain_to.rs +++ b/src/wallet/test/drain_to.rs @@ -301,3 +301,52 @@ fn reservation_interaction() { .all(|outpoint| drain_inputs.contains(outpoint)) ); } + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn begin_end() { + initialize(); + + let (mut wallet, online) = get_funded_noutxo_wallet!(); + let address = test_get_address(&mut wallet); + + // begin does not update backup_info with dry_run=true + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let _psbt = wallet + .drain_to_begin(online, address.clone(), FEE_RATE, true) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert_eq!( + bak_info_before.last_operation_timestamp, + bak_info_after.last_operation_timestamp + ); + + // begin does update backup_info with dry_run=false + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let psbt = wallet + .drain_to_begin(online, address, FEE_RATE, false) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + + let signed_psbt = wallet.sign_psbt(psbt, None).unwrap(); + + // end updates backup_info + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + wallet.drain_to_end(online, signed_psbt).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); +} diff --git a/src/wallet/test/inflate.rs b/src/wallet/test/inflate.rs index 089093e6..780d4980 100644 --- a/src/wallet/test/inflate.rs +++ b/src/wallet/test/inflate.rs @@ -529,3 +529,66 @@ fn fail() { let result = test_inflate_end_result(&mut wallet_2, online_2, &signed_psbt); assert_matches!(result, Err(Error::UnknownTransfer { txid }) if txid == psbt_txid); } + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn begin_end() { + initialize(); + + let (mut wallet, online) = get_funded_wallet!(); + let asset = test_issue_asset_ifa(&mut wallet, online, None, Some(&[1000]), None); + + // begin does not update backup_info with dry_run=true + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let _res = wallet + .inflate_begin( + online, + asset.asset_id.clone(), + vec![1000], + FEE_RATE, + MIN_CONFIRMATIONS, + true, + ) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert_eq!( + bak_info_after.last_operation_timestamp, + bak_info_before.last_operation_timestamp + ); + + // begin does update backup_info with dry_run=false + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let res = wallet + .inflate_begin( + online, + asset.asset_id.clone(), + vec![1000], + FEE_RATE, + MIN_CONFIRMATIONS, + false, + ) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + + let signed_psbt = wallet.sign_psbt(res.psbt, None).unwrap(); + + // end updates backup_info + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + wallet.inflate_end(online, signed_psbt).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); +} diff --git a/src/wallet/test/multisig/utils.rs b/src/wallet/test/multisig/utils.rs index 990fd21c..7ac5b044 100644 --- a/src/wallet/test/multisig/utils.rs +++ b/src/wallet/test/multisig/utils.rs @@ -465,7 +465,7 @@ pub(super) trait MultisigOps { let res = self .create_utxos_init_res(up_to, num, size, fee_rate) .unwrap(); - assert!(self.bak_ts() > bt_before); + assert_eq!(self.bak_ts(), bt_before); let op_idx = op_counter_bump(); assert_eq!(res.operation_idx, op_idx); println!( @@ -517,7 +517,7 @@ pub(super) trait MultisigOps { ); let bt_before = self.bak_ts(); let res = self.inflate_init_res(asset_id, inflation_amounts).unwrap(); - assert!(self.bak_ts() > bt_before); + assert_eq!(self.bak_ts(), bt_before); op_counter_bump(); println!("initiated inflate with operation ID {}", res.operation_idx); res @@ -545,7 +545,7 @@ pub(super) trait MultisigOps { ); let bt_before = self.bak_ts(); let res = self.burn_init_res(asset_id, amount).unwrap(); - assert!(self.bak_ts() > bt_before); + assert_eq!(self.bak_ts(), bt_before); op_counter_bump(); println!("initiated burn with operation ID {}", res.operation_idx); res @@ -732,7 +732,7 @@ pub(super) trait MultisigOps { ); let bt_before = self.bak_ts(); let res = self.send_btc_init_res(address, amount).unwrap(); - assert!(self.bak_ts() > bt_before); + assert_eq!(self.bak_ts(), bt_before); let op_idx = op_counter_bump(); assert_eq!(res.operation_idx, op_idx); println!("initiated send_btc with operation ID {}", res.operation_idx); @@ -756,7 +756,7 @@ pub(super) trait MultisigOps { ); let bt_before = self.bak_ts(); let res = self.send_init_res(recipient_map).unwrap(); - assert!(self.bak_ts() > bt_before); + assert_eq!(self.bak_ts(), bt_before); let op_idx = op_counter_bump(); assert_eq!(res.operation_idx, op_idx); println!("initiated send with operation ID {}", res.operation_idx); diff --git a/src/wallet/test/send.rs b/src/wallet/test/send.rs index b5ef5726..ae9fe2ea 100644 --- a/src/wallet/test/send.rs +++ b/src/wallet/test/send.rs @@ -8090,3 +8090,78 @@ fn unsafe_history_waits_for_safe_height() { TransferStatus::Settled )); } + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn begin_end() { + initialize(); + + let (mut wallet, online) = get_funded_wallet!(); + let asset = test_issue_asset_nia(&mut wallet, online, None); + let receive_data = test_blind_receive(&mut wallet); + let recipient_map = HashMap::from([( + asset.asset_id.clone(), + vec![Recipient { + assignment: Assignment::Fungible(AMOUNT), + recipient_id: receive_data.recipient_id.clone(), + witness_data: None, + transport_endpoints: TRANSPORT_ENDPOINTS.clone(), + }], + )]); + + // begin does not update backup_info with dry_run=true + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let _res = wallet + .send_begin( + online, + recipient_map.clone(), + false, + FEE_RATE, + MIN_CONFIRMATIONS, + None, + true, + ) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert_eq!( + bak_info_after.last_operation_timestamp, + bak_info_before.last_operation_timestamp + ); + + // begin does update backup_info with dry_run=false + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let res = wallet + .send_begin( + online, + recipient_map, + false, + FEE_RATE, + MIN_CONFIRMATIONS, + None, + false, + ) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + + let signed_psbt = wallet.sign_psbt(res.psbt, None).unwrap(); + + // end updates backup_info + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + wallet.send_end(online, signed_psbt).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); +} diff --git a/src/wallet/test/send_btc.rs b/src/wallet/test/send_btc.rs index 249b2f25..6ba24b99 100644 --- a/src/wallet/test/send_btc.rs +++ b/src/wallet/test/send_btc.rs @@ -43,10 +43,7 @@ fn success() { let txn = wallet.database().begin_transaction().unwrap(); let bak_info_after = txn.get_backup_info().unwrap().unwrap(); txn.commit().unwrap(); - assert_eq!( - bak_info_after.last_operation_timestamp, - bak_info_before.last_operation_timestamp - ); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(!txid.is_empty()); mine(false); let expected_balance = BtcBalance { @@ -446,3 +443,52 @@ fn send_btc_end_twice() { wallet.send_btc_end(online, signed_psbt.clone()).unwrap(); wallet.send_btc_end(online, signed_psbt).unwrap(); } + +#[cfg(feature = "electrum")] +#[test] +#[parallel] +fn begin_end() { + initialize(); + + let (mut wallet, online) = get_funded_noutxo_wallet!(); + let address = test_get_address(&mut wallet); + + // begin does not update backup_info with dry_run=true + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let _psbt = wallet + .send_btc_begin(online, address.clone(), 1000, FEE_RATE, false, true) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert_eq!( + bak_info_before.last_operation_timestamp, + bak_info_after.last_operation_timestamp + ); + + // begin does update backup_info with dry_run=false + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + let psbt = wallet + .send_btc_begin(online, address, 1000, FEE_RATE, false, false) + .unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + + let signed_psbt = wallet.sign_psbt(psbt, None).unwrap(); + + // end updates backup_info + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_before = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + wallet.send_btc_end(online, signed_psbt).unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let bak_info_after = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); +} From 2c479ed53f32739ef1546a1d3fa2dccaad41ec59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 7 May 2026 22:13:44 +0200 Subject: [PATCH 06/12] add psbt_path for initiated transfers --- bindings/uniffi/src/lib.rs | 3 +++ bindings/uniffi/src/rgb-lib.udl | 1 + src/wallet/mod.rs | 1 + src/wallet/objects.rs | 4 ++++ src/wallet/offline.rs | 13 +++++++++++++ src/wallet/online.rs | 6 ++++++ 6 files changed, 28 insertions(+) diff --git a/bindings/uniffi/src/lib.rs b/bindings/uniffi/src/lib.rs index cf201008..d52218e3 100644 --- a/bindings/uniffi/src/lib.rs +++ b/bindings/uniffi/src/lib.rs @@ -202,6 +202,7 @@ pub struct Transfer { pub transport_endpoints: Vec, pub invoice_string: Option, pub consignment_path: Option, + pub psbt_path: Option, } impl From for Transfer { fn from(orig: RgbLibTransfer) -> Self { @@ -222,6 +223,7 @@ impl From for Transfer { transport_endpoints: orig.transport_endpoints, invoice_string: orig.invoice_string.clone(), consignment_path: orig.consignment_path.clone(), + psbt_path: orig.psbt_path.clone(), } } } @@ -244,6 +246,7 @@ impl From for RgbLibTransfer { transport_endpoints: orig.transport_endpoints, invoice_string: orig.invoice_string.clone(), consignment_path: orig.consignment_path.clone(), + psbt_path: orig.psbt_path.clone(), } } } diff --git a/bindings/uniffi/src/rgb-lib.udl b/bindings/uniffi/src/rgb-lib.udl index 1fbbc848..20022687 100644 --- a/bindings/uniffi/src/rgb-lib.udl +++ b/bindings/uniffi/src/rgb-lib.udl @@ -550,6 +550,7 @@ dictionary Transfer { sequence transport_endpoints; string? invoice_string; string? consignment_path; + string? psbt_path; }; dictionary Unspent { diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 24c9b926..989b06d1 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -75,6 +75,7 @@ use super::*; pub(crate) const CONSIGNMENT_FILE: &str = "consignment_out"; pub(crate) const FASCIA_FILE: &str = "fascia"; +pub(crate) const UNSIGNED_PSBT_FILE: &str = "unsigned.psbt"; pub(crate) const SCHEMA_ID_NIA: &str = "rgb:sch:RWhwUfTMpuP2Zfx1~j4nswCANGeJrYOqDcKelaMV4zU#remote-digital-pegasus"; diff --git a/src/wallet/objects.rs b/src/wallet/objects.rs index a0c2ea9a..d36626fe 100644 --- a/src/wallet/objects.rs +++ b/src/wallet/objects.rs @@ -1215,6 +1215,7 @@ pub struct TransferData { pub(crate) updated_at: i64, pub(crate) expiration_timestamp: Option, pub(crate) consignment_path: Option, + pub(crate) psbt_path: Option, } /// An RGB transfer. @@ -1253,6 +1254,8 @@ pub struct Transfer { pub invoice_string: Option, /// Consignment path pub consignment_path: Option, + /// Path of the unsigned PSBT produced by the `_begin` step, when available + pub psbt_path: Option, } impl DbTransfer { @@ -1278,6 +1281,7 @@ impl DbTransfer { transport_endpoints, invoice_string: self.invoice_string.clone(), consignment_path: td.consignment_path, + psbt_path: td.psbt_path, } } } diff --git a/src/wallet/offline.rs b/src/wallet/offline.rs index 05c982d6..58233fd8 100644 --- a/src/wallet/offline.rs +++ b/src/wallet/offline.rs @@ -2036,6 +2036,18 @@ pub trait WalletOffline: WalletBackup { } .map(|p| p.to_string_lossy().to_string()); + let psbt_path = match &kind { + TransferKind::Send | TransferKind::Inflation | TransferKind::Burn => batch_transfer + .txid + .as_ref() + .map(|txid| self.get_transfer_dir(txid).join(UNSIGNED_PSBT_FILE)) + .filter(|p| p.exists()) + .map(|p| p.to_string_lossy().to_string()), + TransferKind::ReceiveBlind | TransferKind::ReceiveWitness | TransferKind::Issuance => { + None + } + }; + Ok(TransferData { kind, status: batch_transfer.status, @@ -2048,6 +2060,7 @@ pub trait WalletOffline: WalletBackup { updated_at: batch_transfer.updated_at, expiration_timestamp: batch_transfer.expiration, consignment_path, + psbt_path, }) } diff --git a/src/wallet/online.rs b/src/wallet/online.rs index c2d23def..c41ee55c 100644 --- a/src/wallet/online.rs +++ b/src/wallet/online.rs @@ -2944,6 +2944,12 @@ pub trait WalletOnline: WalletOffline { let new_transfer_dir = self.get_transfer_dir(&txid); fs::rename(transfer_dir, &new_transfer_dir)?; + // persist the unsigned PSBT + fs::write( + new_transfer_dir.join(UNSIGNED_PSBT_FILE), + begin_operation_data.psbt.to_string(), + )?; + // update transfer_dir to the new (renamed) directory let mut begin_operation_data = begin_operation_data; begin_operation_data.transfer_dir = new_transfer_dir; From 0d814b7744fe28d3bd189d8d9a7612548f29a30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 14 May 2026 14:16:34 +0200 Subject: [PATCH 07/12] improve delete_transfers tests --- src/wallet/test/delete_transfers.rs | 157 +++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) diff --git a/src/wallet/test/delete_transfers.rs b/src/wallet/test/delete_transfers.rs index 49c13fee..bed395e1 100644 --- a/src/wallet/test/delete_transfers.rs +++ b/src/wallet/test/delete_transfers.rs @@ -7,9 +7,14 @@ fn success() { initialize(); let (mut wallet, online) = get_funded_wallet!(); + let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); // return false if no transfer has changed let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 0); + let txn = wallet.database().begin_transaction().unwrap(); let bak_info_before = txn.get_backup_info().unwrap().unwrap(); txn.commit().unwrap(); assert!(!test_delete_transfers(&wallet, None, false)); @@ -20,6 +25,10 @@ fn success() { bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 0); // delete single transfer let receive_data = test_blind_receive(&mut wallet); @@ -32,6 +41,10 @@ fn success() { let txn = wallet.database().begin_transaction().unwrap(); let bak_info_before = txn.get_backup_info().unwrap().unwrap(); txn.commit().unwrap(); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 1); assert!(test_delete_transfers( &wallet, Some(receive_data.batch_transfer_idx), @@ -41,6 +54,10 @@ fn success() { let bak_info_after = txn.get_backup_info().unwrap().unwrap(); txn.commit().unwrap(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 0); // delete all Failed transfers let receive_data_1 = test_blind_receive(&mut wallet); @@ -59,7 +76,11 @@ fn success() { TransferStatus::Failed )); show_unspent_colorings(&mut wallet, "run 1 before delete"); - test_delete_transfers(&wallet, None, false); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 3); + assert!(test_delete_transfers(&wallet, None, false)); show_unspent_colorings(&mut wallet, "run 1 after delete"); let txn = wallet.database().begin_transaction().unwrap(); let transfers = txn.iter_transfers().unwrap(); @@ -70,8 +91,16 @@ fn success() { &receive_data_3.recipient_id, TransferStatus::WaitingCounterparty )); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 1); // fail and delete remaining pending transfers + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 1); assert!(test_fail_transfers_single( &mut wallet, online, @@ -86,10 +115,122 @@ fn success() { let transfers = txn.iter_transfers().unwrap(); txn.commit().unwrap(); assert_eq!(transfers.len(), 0); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 0); // issue let asset = test_issue_asset_nia(&mut wallet, online, None); + // delete an initiated transfer with no RGB change + let receive_data = test_blind_receive(&mut rcv_wallet); + let recipient_map = HashMap::from([( + asset.asset_id.clone(), + vec![Recipient { + assignment: Assignment::Fungible(AMOUNT), + recipient_id: receive_data.recipient_id.clone(), + witness_data: None, + transport_endpoints: TRANSPORT_ENDPOINTS.clone(), + }], + )]); + let send_result = wallet + .send_begin( + online, + recipient_map, + false, + FEE_RATE, + MIN_CONFIRMATIONS, + None, + false, + ) + .unwrap(); + let batch_transfer_idx = send_result.batch_transfer_idx.unwrap(); + test_fail_transfers_single(&mut wallet, online, batch_transfer_idx); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 2); + let txn = wallet.database().begin_transaction().unwrap(); + let txos_before = txn.iter_txos().unwrap(); + txn.commit().unwrap(); + assert_eq!(txos_before.len(), 5); + let txn = wallet.database().begin_transaction().unwrap(); + let colorings_before = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + assert_eq!(colorings_before.len(), 2); + assert!(test_delete_transfers( + &wallet, + Some(batch_transfer_idx), + false + )); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 1); + let txn = wallet.database().begin_transaction().unwrap(); + let txos_after = txn.iter_txos().unwrap(); + txn.commit().unwrap(); + assert_eq!(txos_after.len(), 5); + let txn = wallet.database().begin_transaction().unwrap(); + let colorings_after = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + assert_eq!(colorings_after.len(), 1); + + // delete an initiated transfer with RGB change on bitcoin change UTXO + let receive_data = test_blind_receive(&mut rcv_wallet); + let recipient_map = HashMap::from([( + asset.asset_id.clone(), + vec![Recipient { + assignment: Assignment::Fungible(AMOUNT - 1), + recipient_id: receive_data.recipient_id.clone(), + witness_data: None, + transport_endpoints: TRANSPORT_ENDPOINTS.clone(), + }], + )]); + let send_result = wallet + .send_begin( + online, + recipient_map, + false, + FEE_RATE, + MIN_CONFIRMATIONS, + None, + false, + ) + .unwrap(); + let batch_transfer_idx = send_result.batch_transfer_idx.unwrap(); + test_fail_transfers_single(&mut wallet, online, batch_transfer_idx); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 2); + let txn = wallet.database().begin_transaction().unwrap(); + let txos_before = txn.iter_txos().unwrap(); + txn.commit().unwrap(); + assert_eq!(txos_before.len(), 6); + let txn = wallet.database().begin_transaction().unwrap(); + let colorings_before = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + assert_eq!(colorings_before.len(), 3); + assert!(test_delete_transfers( + &wallet, + Some(batch_transfer_idx), + false + )); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 1); + let txn = wallet.database().begin_transaction().unwrap(); + let txos_after = txn.iter_txos().unwrap(); + txn.commit().unwrap(); + assert_eq!(txos_after.len(), 5); + let txn = wallet.database().begin_transaction().unwrap(); + let colorings_after = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + assert_eq!(colorings_after.len(), 1); + // don't delete failed transfer with asset_id if no_asset_only is true let receive_data_1 = test_blind_receive(&mut wallet); let receive_data_2 = wallet @@ -174,7 +315,19 @@ fn batch_success() { let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); assert!(!send_result.txid.is_empty()); test_fail_transfers_single(&mut wallet, online, send_result.batch_transfer_idx); - test_delete_transfers(&wallet, Some(send_result.batch_transfer_idx), false); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_before = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_before.len(), 2); + assert!(test_delete_transfers( + &wallet, + Some(send_result.batch_transfer_idx), + false + )); + let txn = wallet.database().begin_transaction().unwrap(); + let batch_transfers_after = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + assert_eq!(batch_transfers_after.len(), 1); } #[cfg(feature = "electrum")] From efb36d3027e3031d29b2cbb6ff5eccaccf729041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Thu, 14 May 2026 14:18:54 +0200 Subject: [PATCH 08/12] create inexistent txo only when needed --- src/wallet/online.rs | 88 +++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 29 deletions(-) diff --git a/src/wallet/online.rs b/src/wallet/online.rs index c41ee55c..2ba5cda1 100644 --- a/src/wallet/online.rs +++ b/src/wallet/online.rs @@ -2528,6 +2528,46 @@ pub trait WalletOnline: WalletOffline { Ok(()) } + fn get_change_utxo_idx( + &self, + txn: &DbTxn, + txid: &str, + info_contents: &InfoBatchTransfer, + change_utxo_idx: &mut Option, + ) -> Result { + if let Some(idx) = *change_utxo_idx { + return Ok(idx); + } + let idx = if let Some(btc_change) = &info_contents.btc_change { + match txn.get_txo(&Outpoint { + txid: txid.to_string(), + vout: btc_change.vout, + })? { + Some(txo) => txo.idx, + None => { + let db_utxo = DbTxoActMod { + txid: ActiveValue::Set(txid.to_string()), + vout: ActiveValue::Set(btc_change.vout), + btc_amount: ActiveValue::Set(btc_change.amount.to_string()), + spent: ActiveValue::Set(false), + exists: ActiveValue::Set(false), + pending_witness: ActiveValue::Set(false), + ..Default::default() + }; + txn.set_txo(db_utxo)? + } + } + } else { + let outpoint = info_contents + .change_utxo_outpoint + .as_ref() + .expect("change utxo source"); + txn.get_txo(outpoint)?.expect("should exist").idx + }; + *change_utxo_idx = Some(idx); + Ok(idx) + } + fn save_transfers( &mut self, txn: &DbTxn, @@ -2545,32 +2585,7 @@ pub trait WalletOnline: WalletOffline { }; let batch_transfer_idx = txn.set_batch_transfer(batch_transfer)?; - let change_utxo_idx = if let Some(btc_change) = &info_contents.btc_change { - Some( - match txn.get_txo(&Outpoint { - txid: txid.clone(), - vout: btc_change.vout, - })? { - Some(txo) => txo.idx, - None => { - let db_utxo = DbTxoActMod { - txid: ActiveValue::Set(txid.clone()), - vout: ActiveValue::Set(btc_change.vout), - btc_amount: ActiveValue::Set(btc_change.amount.to_string()), - spent: ActiveValue::Set(false), - exists: ActiveValue::Set(false), - pending_witness: ActiveValue::Set(false), - ..Default::default() - }; - txn.set_txo(db_utxo)? - } - }, - ) - } else if let Some(outpoint) = &info_contents.change_utxo_outpoint { - Some(txn.get_txo(outpoint)?.expect("should exist").idx) - } else { - None - }; + let mut change_utxo_idx: Option = None; for (asset_id, transfer_info) in info_contents.transfers.iter() { let asset_transfer = DbAssetTransferActMod { @@ -2613,7 +2628,12 @@ pub trait WalletOnline: WalletOffline { } if transfer_info.change.fungible > 0 { let db_coloring = DbColoringActMod { - txo_idx: ActiveValue::Set(change_utxo_idx.unwrap()), + txo_idx: ActiveValue::Set(self.get_change_utxo_idx( + txn, + &txid, + info_contents, + &mut change_utxo_idx, + )?), asset_transfer_idx: ActiveValue::Set(asset_transfer_idx), r#type: ActiveValue::Set(ColoringType::Change), assignment: ActiveValue::Set(Assignment::Fungible( @@ -2625,7 +2645,12 @@ pub trait WalletOnline: WalletOffline { } if transfer_info.change.inflation > 0 { let db_coloring = DbColoringActMod { - txo_idx: ActiveValue::Set(change_utxo_idx.unwrap()), + txo_idx: ActiveValue::Set(self.get_change_utxo_idx( + txn, + &txid, + info_contents, + &mut change_utxo_idx, + )?), asset_transfer_idx: ActiveValue::Set(asset_transfer_idx), r#type: ActiveValue::Set(ColoringType::Change), assignment: ActiveValue::Set(Assignment::InflationRight( @@ -2744,7 +2769,12 @@ pub trait WalletOnline: WalletOffline { }; txn.set_coloring(db_coloring)?; let db_coloring = DbColoringActMod { - txo_idx: ActiveValue::Set(change_utxo_idx.unwrap()), + txo_idx: ActiveValue::Set(self.get_change_utxo_idx( + txn, + &txid, + info_contents, + &mut change_utxo_idx, + )?), asset_transfer_idx: ActiveValue::Set(asset_transfer_idx), r#type: ActiveValue::Set(ColoringType::Change), assignment: ActiveValue::Set(assignment.clone()), From 355bfa1863fa6e467c13e3b2e69980ce7739faac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Sat, 9 May 2026 00:12:29 +0200 Subject: [PATCH 09/12] fix DB del methods --- src/database/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index 2e461a94..6d0348d4 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -438,7 +438,7 @@ impl DbTxn { } pub(crate) fn del_batch_transfer(&self, batch_transfer: &DbBatchTransfer) -> Result<(), Error> { - block_on(Transfer::delete_by_id(batch_transfer.idx).exec(self.inner()))?; + block_on(BatchTransfer::delete_by_id(batch_transfer.idx).exec(self.inner()))?; Ok(()) } @@ -479,7 +479,7 @@ impl DbTxn { } pub(crate) fn del_txo(&self, idx: i32) -> Result<(), Error> { - block_on(Coloring::delete_by_id(idx).exec(self.inner()))?; + block_on(Txo::delete_by_id(idx).exec(self.inner()))?; Ok(()) } From 56479b1fbc605a6fca38067fb854979b3f396975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Sat, 9 May 2026 00:19:10 +0200 Subject: [PATCH 10/12] remove Result from some infallible methods --- src/database/mod.rs | 64 +++++++++++++++----------------- src/wallet/offline.rs | 7 ++-- src/wallet/online.rs | 7 ++-- src/wallet/test/utils/helpers.rs | 9 ++--- 4 files changed, 38 insertions(+), 49 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index 6d0348d4..ed50c081 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -22,27 +22,27 @@ impl DbBatchTransfer { &self, asset_transfers: &[DbAssetTransfer], transfers: &[DbTransfer], - ) -> Result { + ) -> bool { let asset_transfer_ids: Vec = asset_transfers .iter() .filter(|t| t.batch_transfer_idx == self.idx) .map(|t| t.idx) .collect(); - Ok(transfers + transfers .iter() .filter(|t| asset_transfer_ids.contains(&t.asset_transfer_idx)) - .all(|t| t.incoming)) + .all(|t| t.incoming) } pub(crate) fn get_asset_transfers( &self, asset_transfers: &[DbAssetTransfer], - ) -> Result, Error> { - Ok(asset_transfers + ) -> Vec { + asset_transfers .iter() .filter(|&t| t.batch_transfer_idx == self.idx) .cloned() - .collect()) + .collect() } #[cfg(any(feature = "electrum", feature = "esplora"))] @@ -51,7 +51,7 @@ impl DbBatchTransfer { asset_transfers: &[DbAssetTransfer], transfers: &[DbTransfer], ) -> Result { - let asset_transfers = self.get_asset_transfers(asset_transfers)?; + let asset_transfers = self.get_asset_transfers(asset_transfers); let mut asset_transfers_data = vec![]; for asset_transfer in asset_transfers { let transfers: Vec = transfers @@ -136,7 +136,7 @@ impl DbTransfer { &self, asset_transfers: &[DbAssetTransfer], batch_transfers: &[DbBatchTransfer], - ) -> Result<(DbAssetTransfer, DbBatchTransfer), Error> { + ) -> (DbAssetTransfer, DbBatchTransfer) { let asset_transfer = asset_transfers .iter() .find(|t| t.idx == self.asset_transfer_idx) @@ -146,7 +146,7 @@ impl DbTransfer { .find(|t| t.idx == asset_transfer.batch_transfer_idx) .expect("asset transfer should be connected to a batch transfer"); - Ok((asset_transfer.clone(), batch_transfer.clone())) + (asset_transfer.clone(), batch_transfer.clone()) } } @@ -717,28 +717,23 @@ impl DbTxn { .filter(|t| { t.incoming && matches!(t.recipient_type, Some(RecipientTypeFull::Witness { .. })) }) - .filter_map( - |t| match t.related_transfers(&asset_transfers, &batch_transfers) { - Ok((at, bt)) => { - if bt.status.waiting_confirmations() { - // filter for asset ID (always present in WaitingConfirmations status) - if at.asset_id.unwrap() != asset_id { - return None; - } - Some(Ok(t - .requested_assignment - .as_ref() - .map(|a| a.main_amount()) - .unwrap_or(0))) - } else { - None - } + .filter_map(|t| { + let (at, bt) = t.related_transfers(&asset_transfers, &batch_transfers); + if bt.status.waiting_confirmations() { + // filter for asset ID (always present in WaitingConfirmations status) + if at.asset_id.unwrap() != asset_id { + return None; } - Err(e) => Some(Err(e)), - }, - ) - .collect::, Error>>()? - .iter() + Some( + t.requested_assignment + .as_ref() + .map(|a| a.main_amount()) + .unwrap_or(0), + ) + } else { + None + } + }) .sum(); ass_pending_incoming += witness_pending; let ass_pending_outgoing: u64 = ass_allocations @@ -877,11 +872,10 @@ impl DbTxn { let pending_blinded_utxos = transfers .iter() .filter_map(|t| match (&t.recipient_type, t.incoming) { - (Some(RecipientTypeFull::Blind { unblinded_utxo }), true) => t - .related_transfers(&asset_transfers, &batch_transfers) - .ok() - .filter(|(_, bt)| bt.status.waiting_counterparty()) - .map(|_| unblinded_utxo), + (Some(RecipientTypeFull::Blind { unblinded_utxo }), true) => { + let (_, bt) = t.related_transfers(&asset_transfers, &batch_transfers); + bt.status.waiting_counterparty().then_some(unblinded_utxo) + } _ => None, }) .fold(HashMap::new(), |mut acc, utxo| { diff --git a/src/wallet/offline.rs b/src/wallet/offline.rs index 58233fd8..bad64281 100644 --- a/src/wallet/offline.rs +++ b/src/wallet/offline.rs @@ -1184,7 +1184,7 @@ pub trait WalletOffline: WalletBackup { return Err(Error::CannotDeleteBatchTransfer); } - let asset_transfers = batch_transfer.get_asset_transfers(&db_data.asset_transfers)?; + let asset_transfers = batch_transfer.get_asset_transfers(&db_data.asset_transfers); if no_asset_only { let connected_assets = asset_transfers.iter().any(|t| t.asset_id.is_some()); @@ -1210,8 +1210,7 @@ pub trait WalletOffline: WalletBackup { .filter(|t| t.failed()) .collect(); for batch_transfer in batch_transfers.iter_mut() { - let asset_transfers = - batch_transfer.get_asset_transfers(&db_data.asset_transfers)?; + let asset_transfers = batch_transfer.get_asset_transfers(&db_data.asset_transfers); if no_asset_only { let connected_assets = asset_transfers.iter().any(|t| t.asset_id.is_some()); if connected_assets { @@ -2083,7 +2082,7 @@ pub trait WalletOffline: WalletBackup { .filter(|t| asset_transfer_ids.contains(&t.asset_transfer_idx)) .map(|t| { let (asset_transfer, batch_transfer) = - t.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers)?; + t.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers); let td = self.get_transfer_data( &t, &asset_transfer, diff --git a/src/wallet/online.rs b/src/wallet/online.rs index 2ba5cda1..ebfa8f87 100644 --- a/src/wallet/online.rs +++ b/src/wallet/online.rs @@ -476,8 +476,7 @@ pub trait WalletOnline: WalletOffline { } if no_asset_only { - let asset_transfers = - batch_transfer.get_asset_transfers(&db_data.asset_transfers)?; + let asset_transfers = batch_transfer.get_asset_transfers(&db_data.asset_transfers); let connected_assets = asset_transfers.iter().any(|t| t.asset_id.is_some()); if connected_assets { return Ok(FailTransfersOutcome { @@ -502,7 +501,7 @@ pub trait WalletOnline: WalletOffline { }) { if no_asset_only { let connected_assets = batch_transfer - .get_asset_transfers(&db_data.asset_transfers)? + .get_asset_transfers(&db_data.asset_transfers) .iter() .any(|t| t.asset_id.is_some()); if connected_assets { @@ -1687,7 +1686,7 @@ pub trait WalletOnline: WalletOffline { skip_sync: bool, ) -> Result, Error> { debug!(self.logger(), "Refreshing transfer: {:?}", transfer); - let incoming = transfer.incoming(&db_data.asset_transfers, &db_data.transfers)?; + let incoming = transfer.incoming(&db_data.asset_transfers, &db_data.transfers); if !filter.is_empty() { let requested = RefreshFilter { status: RefreshTransferStatus::try_from(transfer.status).expect("pending status"), diff --git a/src/wallet/test/utils/helpers.rs b/src/wallet/test/utils/helpers.rs index 57517330..565fd5a8 100644 --- a/src/wallet/test/utils/helpers.rs +++ b/src/wallet/test/utils/helpers.rs @@ -417,9 +417,8 @@ pub(crate) fn get_test_transfer_data( let txn = wallet.database().begin_transaction().unwrap(); let db_data = txn.get_db_data(false).unwrap(); txn.commit().unwrap(); - let (asset_transfer, batch_transfer) = transfer - .related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) - .unwrap(); + let (asset_transfer, batch_transfer) = + transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers); let transfer_data = wallet .get_transfer_data( transfer, @@ -439,9 +438,7 @@ pub(crate) fn get_test_transfer_related( let txn = wallet.database().begin_transaction().unwrap(); let db_data = txn.get_db_data(false).unwrap(); txn.commit().unwrap(); - transfer - .related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) - .unwrap() + transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) } #[cfg(any(feature = "electrum", feature = "esplora"))] From d286f46cd45672fb14be99cfb92872ec12b8447b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Sat, 9 May 2026 00:38:19 +0200 Subject: [PATCH 11/12] move get_utxo_allocations method --- src/database/mod.rs | 68 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/src/database/mod.rs b/src/database/mod.rs index ed50c081..869dce34 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -157,6 +157,38 @@ impl DbTxo { vout: self.vout, } } + + fn get_utxo_allocations( + &self, + colorings: &[DbColoring], + asset_transfers: &[DbAssetTransfer], + batch_transfers: &[DbBatchTransfer], + ) -> Result, Error> { + let utxo_colorings: Vec<&DbColoring> = + colorings.iter().filter(|c| c.txo_idx == self.idx).collect(); + + let mut allocations: Vec = vec![]; + utxo_colorings.iter().for_each(|c| { + let asset_transfer: &DbAssetTransfer = asset_transfers + .iter() + .find(|t| t.idx == c.asset_transfer_idx) + .expect("coloring should be connected to an asset transfer"); + let batch_transfer: &DbBatchTransfer = batch_transfers + .iter() + .find(|t| asset_transfer.batch_transfer_idx == t.idx) + .expect("asset transfer should be connected to a batch transfer"); + + allocations.push(LocalRgbAllocation { + asset_id: asset_transfer.asset_id.clone(), + assignment: c.assignment.clone(), + status: batch_transfer.status, + incoming: c.incoming(), + txo_spent: self.spent, + }); + }); + + Ok(allocations) + } } impl From for BdkOutPoint { @@ -819,39 +851,6 @@ impl DbTxn { }) } - fn get_utxo_allocations( - &self, - utxo: &DbTxo, - colorings: &[DbColoring], - asset_transfers: &[DbAssetTransfer], - batch_transfers: &[DbBatchTransfer], - ) -> Result, Error> { - let utxo_colorings: Vec<&DbColoring> = - colorings.iter().filter(|c| c.txo_idx == utxo.idx).collect(); - - let mut allocations: Vec = vec![]; - utxo_colorings.iter().for_each(|c| { - let asset_transfer: &DbAssetTransfer = asset_transfers - .iter() - .find(|t| t.idx == c.asset_transfer_idx) - .expect("coloring should be connected to an asset transfer"); - let batch_transfer: &DbBatchTransfer = batch_transfers - .iter() - .find(|t| asset_transfer.batch_transfer_idx == t.idx) - .expect("asset transfer should be connected to a batch transfer"); - - allocations.push(LocalRgbAllocation { - asset_id: asset_transfer.asset_id.clone(), - assignment: c.assignment.clone(), - status: batch_transfer.status, - incoming: c.incoming(), - txo_spent: utxo.spent, - }); - }); - - Ok(allocations) - } - pub(crate) fn get_rgb_allocations( &self, utxos: Vec, @@ -888,8 +887,7 @@ impl DbTxn { .map(|t| { Ok(LocalUnspent { utxo: t.clone(), - rgb_allocations: self.get_utxo_allocations( - t, + rgb_allocations: t.get_utxo_allocations( &colorings, &asset_transfers, &batch_transfers, From 00bf9c037d81b4f7f7ed8d5be8dd43c36818d5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zoe=20Faltib=C3=A0?= Date: Wed, 6 May 2026 18:16:39 +0200 Subject: [PATCH 12/12] refactor tests: use SinglesigParty --- src/wallet/objects.rs | 2 +- src/wallet/test/abort_pending_vanilla_tx.rs | 68 +- src/wallet/test/backup.rs | 130 +- src/wallet/test/blind_receive.rs | 249 +- src/wallet/test/burn.rs | 311 +- src/wallet/test/create_utxos.rs | 306 +- src/wallet/test/delete_transfers.rs | 297 +- src/wallet/test/drain_to.rs | 208 +- src/wallet/test/fail_transfers.rs | 551 ++- src/wallet/test/finalize_psbt.rs | 27 +- src/wallet/test/get_address.rs | 14 +- src/wallet/test/get_asset_balance.rs | 277 +- src/wallet/test/get_asset_metadata.rs | 48 +- src/wallet/test/get_btc_balance.rs | 73 +- src/wallet/test/get_fee_estimation.rs | 52 +- src/wallet/test/get_wallet_data.rs | 4 +- src/wallet/test/get_wallet_dir.rs | 2 +- src/wallet/test/go_online.rs | 199 +- src/wallet/test/inflate.rs | 281 +- src/wallet/test/issue_asset_cfa.rs | 143 +- src/wallet/test/issue_asset_ifa.rs | 141 +- src/wallet/test/issue_asset_nia.rs | 128 +- src/wallet/test/issue_asset_uda.rs | 145 +- src/wallet/test/list_assets.rs | 29 +- src/wallet/test/list_pending_vanilla_txs.rs | 30 +- src/wallet/test/list_transactions.rs | 63 +- src/wallet/test/list_transfers.rs | 48 +- src/wallet/test/list_unspents.rs | 122 +- src/wallet/test/mod.rs | 25 +- src/wallet/test/multisig/mod.rs | 165 +- src/wallet/test/multisig/utils.rs | 322 +- src/wallet/test/new.rs | 237 +- src/wallet/test/refresh.rs | 660 ++-- src/wallet/test/rust_only.rs | 268 +- src/wallet/test/send.rs | 3549 +++++++++---------- src/wallet/test/send_btc.rs | 290 +- src/wallet/test/sign_psbt.rs | 17 +- src/wallet/test/sync.rs | 7 +- src/wallet/test/utils/api.rs | 2011 +++++++---- src/wallet/test/utils/helpers.rs | 549 +-- src/wallet/test/utils/mod.rs | 1 + src/wallet/test/witness_receive.rs | 38 +- 42 files changed, 5624 insertions(+), 6463 deletions(-) diff --git a/src/wallet/objects.rs b/src/wallet/objects.rs index d36626fe..8637eed4 100644 --- a/src/wallet/objects.rs +++ b/src/wallet/objects.rs @@ -158,7 +158,7 @@ pub struct Balance { /// balances. /// The spendable balances include the settled balance and also the untrusted and trusted pending /// balances. -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)] +#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] #[cfg_attr(feature = "camel_case", serde(rename_all = "camelCase"))] pub struct BtcBalance { /// Funds that will never hold RGB assets diff --git a/src/wallet/test/abort_pending_vanilla_tx.rs b/src/wallet/test/abort_pending_vanilla_tx.rs index bbc51cd7..3c572f7f 100644 --- a/src/wallet/test/abort_pending_vanilla_tx.rs +++ b/src/wallet/test/abort_pending_vanilla_tx.rs @@ -6,13 +6,14 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); - let unsigned_psbt_str = wallet + let unsigned_psbt_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), 1000, FEE_RATE, false, @@ -23,41 +24,30 @@ fn success() { let psbt_txid = unsigned_psbt.unsigned_tx.compute_txid().to_string(); // pre-abort: reservation + wallet_transaction exist - assert_eq!(wallet.list_pending_vanilla_txs().unwrap().len(), 1); - let txn = wallet.database().begin_transaction().unwrap(); - let reserved_txos = txn.iter_reserved_txos().unwrap(); - txn.commit().unwrap(); + assert_eq!(party.wallet.list_pending_vanilla_txs().unwrap().len(), 1); + let reserved_txos = party.db_reserved_txos(); assert!(!reserved_txos.is_empty()); // abort - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.abort_pending_vanilla_tx(psbt_txid.clone()).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party.abort_pending_vanilla_tx(&psbt_txid); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // post-abort: reservation + wallet_transaction row both gone - assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); - let txn = wallet.database().begin_transaction().unwrap(); - let reserved_txos = txn.iter_reserved_txos().unwrap(); - txn.commit().unwrap(); + assert!(party.wallet.list_pending_vanilla_txs().unwrap().is_empty()); + let reserved_txos = party.db_reserved_txos(); assert!(reserved_txos.is_empty()); - let txn = wallet.database().begin_transaction().unwrap(); - let maybe_wallet_tx = txn - .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) - .unwrap(); - txn.commit().unwrap(); + let maybe_wallet_tx = party.db_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid); assert!(maybe_wallet_tx.is_none()); // the previously-reserved UTXOs are now available again: a fresh send_btc_begin // re-selects them - let unsigned_psbt_2_str = wallet + let unsigned_psbt_2_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), 1000, FEE_RATE, true, @@ -77,27 +67,19 @@ fn success() { fn fail() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // unknown txid - let result = wallet.abort_pending_vanilla_tx(FAKE_TXID.to_string()); + let result = party.abort_pending_vanilla_tx_result(FAKE_TXID); assert!(matches!(result, Err(Error::CannotAbortPendingVanillaTx))); // a wallet_transaction row exists but has no attached reservations - let txid = test_send_btc( - &mut wallet, - online, - &test_get_address(&mut rcv_wallet), - 1000, - ); - let txn = wallet.database().begin_transaction().unwrap(); - let (_wt, reservations) = txn - .get_wallet_transaction_with_reserved_txos_by_txid(&txid) - .unwrap() + let txid = party.send_btc(&rcv_party.get_address(), 1000); + let (_wt, reservations) = party + .db_wallet_transaction_with_reserved_txos_by_txid(&txid) .expect("SendBtc wallet_transaction should exist after send_btc"); - txn.commit().unwrap(); assert!(reservations.is_empty()); - let result = wallet.abort_pending_vanilla_tx(txid); + let result = party.abort_pending_vanilla_tx_result(&txid); assert!(matches!(result, Err(Error::CannotAbortPendingVanillaTx))); } diff --git a/src/wallet/test/backup.rs b/src/wallet/test/backup.rs index 6ee4ea86..73873b97 100644 --- a/src/wallet/test/backup.rs +++ b/src/wallet/test/backup.rs @@ -12,17 +12,17 @@ fn success() { let _ = std::fs::remove_file(backup_file); // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); - let mut wallet_data = wallet.get_wallet_data(); - let keys = wallet.get_keys(); - let wallet_dir = wallet.get_wallet_dir(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); + let mut wallet_data = party.get_wallet_data(); + let keys = party.get_keys(); + let wallet_dir = party.wallet.get_wallet_dir(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -32,28 +32,28 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, Some(&asset.asset_id), None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(Some(&asset.asset_id)); + party.wait_for_refresh(Some(&asset.asset_id)); // pre-backup wallet data - check_test_wallet_data(&mut wallet, &asset, None, 1, amount); + party.check_test_wallet_data(&asset, None, 1, amount); // backup println!("\nbacking up..."); - wallet.backup(backup_file, PASSWORD).unwrap(); + party.wallet.backup(backup_file, PASSWORD).unwrap(); // backup not required after doing one - let backup_required = wallet.backup_info().unwrap(); + let backup_required = party.wallet.backup_info().unwrap(); assert!(!backup_required); // drop wallets - drop(wallet); + drop(party); // restore println!("\nrestoring..."); @@ -68,16 +68,17 @@ fn success() { // post-restore wallet data wallet_data.data_dir = target_dir.to_string(); - let mut wallet = Wallet::new(wallet_data, keys.clone()).unwrap(); - let online = test_go_online(&mut wallet, true, None); - check_test_wallet_data(&mut wallet, &asset, None, 1, amount); + let mut party = offline_party!(Wallet::new(wallet_data, keys.clone()).unwrap()); + let online = party.go_online(true, None); + let mut party = party!(party.wallet, online); + party.check_test_wallet_data(&asset, None, 1, amount); // backup not required after restoring one - let backup_required = wallet.backup_info().unwrap(); + let backup_required = party.wallet.backup_info().unwrap(); assert!(!backup_required); // spend asset once more and check wallet data again - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -87,18 +88,18 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, Some(&asset.asset_id), None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - check_test_wallet_data(&mut wallet, &asset, None, 2, amount * 2); + rcv_party.wait_for_refresh(Some(&asset.asset_id)); + party.wait_for_refresh(Some(&asset.asset_id)); + party.check_test_wallet_data(&asset, None, 2, amount * 2); // issue a second asset with the restored wallet - let _asset = test_issue_asset_nia(&mut wallet, online, None); + let _asset = party.issue_asset_nia(None); } #[cfg(feature = "electrum")] @@ -194,24 +195,24 @@ fn double_restore() { let password_2 = "password2"; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); - let mut wallet_1_data = wallet_1.get_wallet_data(); - let keys_1 = wallet_1.get_keys(); - let mut wallet_2_data = wallet_2.get_wallet_data(); - let keys_2 = wallet_2.get_keys(); - let wallet_1_dir = wallet_1.get_wallet_dir(); - let wallet_2_dir = wallet_2.get_wallet_dir(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut rcv_party = get_funded_party!(); + let mut wallet_1_data = party_1.get_wallet_data(); + let keys_1 = party_1.get_keys(); + let mut wallet_2_data = party_2.get_wallet_data(); + let keys_2 = party_2.get_keys(); + let wallet_1_dir = party_1.wallet.get_wallet_dir(); + let wallet_2_dir = party_2.wallet.get_wallet_dir(); let asset_2_supply = AMOUNT * 2; // issue - let asset_1 = test_issue_asset_nia(&mut wallet_1, online_1, None); - let asset_2 = test_issue_asset_nia(&mut wallet_2, online_2, Some(&[asset_2_supply])); + let asset_1 = party_1.issue_asset_nia(None); + let asset_2 = party_2.issue_asset_nia(Some(&[asset_2_supply])); // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); - let receive_data_2 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); + let receive_data_2 = rcv_party.blind_receive(); let recipient_map_1 = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -230,38 +231,39 @@ fn double_restore() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map_1); - let txid_2 = test_send(&mut wallet_2, online_2, &recipient_map_2); + let txid_1 = party_1.send_retry(&recipient_map_1); + let txid_2 = party_2.send_retry(&recipient_map_2); assert!(!txid_1.is_empty()); assert!(!txid_2.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset_1.asset_id), None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset_2.asset_id), None); + rcv_party.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset_1.asset_id)); + party_2.wait_for_refresh(Some(&asset_2.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, Some(&asset_1.asset_id), None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset_1.asset_id), None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset_2.asset_id), None); + rcv_party.wait_for_refresh(Some(&asset_1.asset_id)); + party_1.wait_for_refresh(Some(&asset_1.asset_id)); + party_2.wait_for_refresh(Some(&asset_2.asset_id)); // pre-backup wallet data - check_test_wallet_data(&mut wallet_1, &asset_1, None, 1, amount); - check_test_wallet_data(&mut wallet_2, &asset_2, Some(asset_2_supply), 1, amount * 2); + party_1.check_test_wallet_data(&asset_1, None, 1, amount); + party_2.check_test_wallet_data(&asset_2, Some(asset_2_supply), 1, amount * 2); // backup println!("\nbacking up..."); - wallet_1.backup(backup_file_1, password_1).unwrap(); + party_1.wallet.backup(backup_file_1, password_1).unwrap(); let custom_params = ScryptParams::new( Some(Params::RECOMMENDED_LOG_N + 1), Some(Params::RECOMMENDED_R + 1), Some(Params::RECOMMENDED_P + 1), ); - wallet_2 + party_2 + .wallet .backup_customize(backup_file_2, password_2, Some(custom_params)) .unwrap(); // drop wallets - drop(wallet_1); - drop(wallet_2); + drop(party_1); + drop(party_2); // restore println!("\nrestoring..."); @@ -282,16 +284,18 @@ fn double_restore() { // post-restore wallet data wallet_1_data.data_dir = target_dir_1.to_string(); wallet_2_data.data_dir = target_dir_2.to_string(); - let mut wallet_1 = Wallet::new(wallet_1_data, keys_1.clone()).unwrap(); - let mut wallet_2 = Wallet::new(wallet_2_data, keys_2.clone()).unwrap(); - let online_1 = test_go_online(&mut wallet_1, true, None); - let online_2 = test_go_online(&mut wallet_2, true, None); - check_test_wallet_data(&mut wallet_1, &asset_1, None, 1, amount); - check_test_wallet_data(&mut wallet_2, &asset_2, Some(asset_2_supply), 1, amount * 2); + let mut party_1 = offline_party!(Wallet::new(wallet_1_data, keys_1.clone()).unwrap()); + let mut party_2 = offline_party!(Wallet::new(wallet_2_data, keys_2.clone()).unwrap()); + let online_1 = party_1.go_online(true, None); + let online_2 = party_2.go_online(true, None); + let mut party_1 = party!(party_1.wallet, online_1); + let mut party_2 = party!(party_2.wallet, online_2); + party_1.check_test_wallet_data(&asset_1, None, 1, amount); + party_2.check_test_wallet_data(&asset_2, Some(asset_2_supply), 1, amount * 2); // issue a second asset with the restored wallets - test_issue_asset_nia(&mut wallet_1, online_1, None); - test_issue_asset_nia(&mut wallet_2, online_2, None); + party_1.issue_asset_nia(None); + party_2.issue_asset_nia(None); } #[cfg(feature = "electrum")] diff --git a/src/wallet/test/blind_receive.rs b/src/wallet/test/blind_receive.rs index 86dec3f1..cc7b4fc4 100644 --- a/src/wallet/test/blind_receive.rs +++ b/src/wallet/test/blind_receive.rs @@ -8,13 +8,12 @@ fn success() { let amount = 69; let expiration_secs = 60i64; - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // only mandatory fields - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let receive_data = wallet + let bak_info_before = party.db_backup_info(); + let receive_data = party + .wallet .blind_receive( None, Assignment::Any, @@ -23,9 +22,7 @@ fn success() { MIN_CONFIRMATIONS, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(receive_data.expiration_timestamp.is_none()); let decoded_invoice = Invoice::new(receive_data.invoice).unwrap(); @@ -33,16 +30,17 @@ fn success() { decoded_invoice.invoice_data.network, BitcoinNetwork::Regtest ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); - let (_, batch_transfer) = get_test_transfer_related(&wallet, &transfer); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (_, batch_transfer) = party.get_test_transfer_related(&transfer); assert_eq!(batch_transfer.min_confirmations, MIN_CONFIRMATIONS); // asset ID (NIA) + expiration + 0 min confirmations - let asset_nia = test_issue_asset_nia(&mut wallet, online, None); + let asset_nia = party.issue_asset_nia(None); let asset_nia_id = asset_nia.asset_id; let expiration_timestamp = (now().unix_timestamp() + expiration_secs) as u64; let min_confirmations = 0; - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_nia_id.clone()), Assignment::Any, @@ -55,17 +53,18 @@ fn success() { receive_data.expiration_timestamp, Some(expiration_timestamp) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); - let (_, batch_transfer) = get_test_transfer_related(&wallet, &transfer); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (_, batch_transfer) = party.get_test_transfer_related(&transfer); assert_eq!(batch_transfer.min_confirmations, min_confirmations); let invoice = Invoice::new(receive_data.invoice).unwrap(); let invoice_data = invoice.invoice_data(); assert_eq!(invoice_data.asset_schema, Some(AssetSchema::Nia)); // asset id is set (UDA) - let asset_uda = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); + let asset_uda = party.issue_asset_uda(None, None, vec![]); let asset_uda_id = asset_uda.asset_id; - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_uda_id.clone()), Assignment::Any, @@ -79,9 +78,10 @@ fn success() { assert_eq!(invoice_data.asset_schema, Some(AssetSchema::Uda)); // asset id is set (CFA) - let asset_cfa = test_issue_asset_cfa(&mut wallet, online, None, None); + let asset_cfa = party.issue_asset_cfa(None, None); let asset_cfa_id = asset_cfa.asset_id; - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_cfa_id.clone()), Assignment::Any, @@ -95,11 +95,12 @@ fn success() { assert_eq!(invoice_data.asset_schema, Some(AssetSchema::Cfa)); // asset id is set (IFA) + amount - test_create_utxos_default(&mut wallet, online); // more UTXOs to have free alocation slots - let asset_ifa = test_issue_asset_ifa(&mut wallet, online, None, None, None); + party.create_utxos_default(); // more UTXOs to have free alocation slots + let asset_ifa = party.issue_asset_ifa(None, None, None); let asset_ifa_id = asset_ifa.asset_id; let expiration_timestamp = (now().unix_timestamp() + expiration_secs) as u64; - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_ifa_id.clone()), Assignment::Fungible(amount), @@ -127,7 +128,8 @@ fn success() { ); // detect assignment: amount, NIA (CFA/IFA) - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_nia_id.clone()), Assignment::Fungible(amount), @@ -143,14 +145,15 @@ fn success() { invoice_data.assignment_name, Some(RGB_STATE_ASSET_OWNER.to_string()) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!( transfer.requested_assignment, Some(Assignment::Fungible(amount)) ); // detect assignment: amount, no schema - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( None, Assignment::Fungible(amount), @@ -166,14 +169,15 @@ fn success() { invoice_data.assignment_name, Some(RGB_STATE_ASSET_OWNER.to_string()) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!( transfer.requested_assignment, Some(Assignment::Fungible(amount)) ); // detect assignment: any, NIA (CFA) - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_nia_id.clone()), Assignment::Any, @@ -189,11 +193,12 @@ fn success() { invoice_data.assignment_name, Some(RGB_STATE_ASSET_OWNER.to_string()) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!(transfer.requested_assignment, Some(Assignment::Fungible(0))); // detect assignment: non fungible, UDA - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_uda_id.clone()), Assignment::NonFungible, @@ -209,11 +214,12 @@ fn success() { invoice_data.assignment_name, Some(RGB_STATE_ASSET_OWNER.to_string()) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!(transfer.requested_assignment, Some(Assignment::NonFungible)); // detect assignment: any, UDA - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_uda_id.clone()), Assignment::Any, @@ -229,11 +235,12 @@ fn success() { invoice_data.assignment_name, Some(RGB_STATE_ASSET_OWNER.to_string()) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!(transfer.requested_assignment, Some(Assignment::NonFungible)); // detect assignment: inflation right, IFA - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset_ifa_id.clone()), Assignment::InflationRight(amount), @@ -249,14 +256,15 @@ fn success() { invoice_data.assignment_name, Some(RGB_STATE_INFLATION_ALLOWANCE.to_string()) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!( transfer.requested_assignment, Some(Assignment::InflationRight(amount)) ); // detect assignment: any, no schema - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( None, Assignment::Any, @@ -269,11 +277,11 @@ fn success() { let invoice_data = invoice.invoice_data(); assert_eq!(invoice_data.assignment, Assignment::Any); assert_eq!(invoice_data.assignment_name, None); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); assert_eq!(transfer.requested_assignment, Some(Assignment::Any)); // invalid assignment: non fungible, IFA schema - let result = wallet.blind_receive( + let result = party.wallet.blind_receive( Some(asset_ifa_id.clone()), Assignment::NonFungible, None, @@ -292,7 +300,7 @@ fn success() { format!("rpc://{}", "127.0.0.1:3001/json-rpc"), format!("rpc://{}", "127.0.0.1:3002/json-rpc"), ]; - let result = wallet.blind_receive( + let result = party.wallet.blind_receive( None, Assignment::Any, None, @@ -300,12 +308,8 @@ fn success() { MIN_CONFIRMATIONS, ); assert!(result.is_ok()); - let transfer = get_test_transfer_recipient(&wallet, &result.unwrap().recipient_id); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + let transfer = party.get_test_transfer_recipient(&result.unwrap().recipient_id); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), transport_endpoints.len()); } @@ -315,16 +319,16 @@ fn success() { fn respect_max_allocations() { initialize(); - let (mut wallet, _online) = get_funded_wallet!(); + let mut party = get_funded_party!(); let available_allocations = UTXO_NUM as u32 * MAX_ALLOCATIONS_PER_UTXO; let mut created_allocations = 0; for _ in 0..UTXO_NUM { let mut txo_list: HashSet = HashSet::new(); for _ in 0..MAX_ALLOCATIONS_PER_UTXO { - let receive_data = test_blind_receive(&mut wallet); + let receive_data = party.blind_receive(); created_allocations += 1; - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); let txo = if let RecipientTypeFull::Blind { unblinded_utxo } = transfer.recipient_type.unwrap() { @@ -340,7 +344,7 @@ fn respect_max_allocations() { } assert_eq!(available_allocations, created_allocations); - let result = test_blind_receive_result(&mut wallet); + let result = party.blind_receive_result(); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } @@ -352,14 +356,14 @@ fn pending_outgoing_transfer_fail() { let amount = 66; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); let asset_id = asset.asset_id; // get issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_issue = unspents .iter() .find(|u| { @@ -369,7 +373,7 @@ fn pending_outgoing_transfer_fail() { }) .unwrap(); // send - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_id.clone(), vec![Recipient { @@ -379,26 +383,26 @@ fn pending_outgoing_transfer_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // check blind doesn't get allocated to UTXO being spent - let receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "after 1st blind"); - let unspents = test_list_unspents(&mut wallet, None, false); + let receive_data = party.blind_receive(); + party.show_unspent_colorings("after 1st blind"); + let unspents = party.list_unspents(false); let unspent_blind_1 = unspents.iter().find(|u| u.pending_blinded > 0).unwrap(); assert_ne!(unspent_issue.utxo.outpoint, unspent_blind_1.utxo.outpoint); // remove transfer - test_fail_transfers_single(&mut wallet, online, receive_data.batch_transfer_idx); - test_delete_transfers(&wallet, Some(receive_data.batch_transfer_idx), false); + party.fail_transfers_single(receive_data.batch_transfer_idx); + party.delete_transfers(Some(receive_data.batch_transfer_idx), false); // take transfer from WaitingCounterparty to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_id)); // check blind doesn't get allocated to UTXO being spent - let _receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "after 2nd blind"); - let unspents = test_list_unspents(&mut wallet, None, false); + let _receive_data = party.blind_receive(); + party.show_unspent_colorings("after 2nd blind"); + let unspents = party.list_unspents(false); let unspent_blind_2 = unspents.iter().find(|u| u.pending_blinded > 0).unwrap(); assert_ne!(unspent_issue.utxo.outpoint, unspent_blind_2.utxo.outpoint); } @@ -422,23 +426,25 @@ fn fail() { ) } - let mut wallet = get_test_wallet(true, Some(1)); // using 1 max allocation per utxo - let online = test_go_online(&mut wallet, true, None); + let mut party = offline_party!(get_test_wallet(true, Some(1))); // using 1 max allocation per utxo + let online = party.go_online(true, None); + let mut party = party!(party.wallet, online); // insufficient funds - let result = test_blind_receive_result(&mut wallet); + let result = party.blind_receive_result(); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // invalid recipient ID let result = RecipientInfo::new(s!("invalid")); assert!(matches!(result, Err(Error::InvalidRecipientID))); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); mine(false); - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); + party.create_utxos(true, Some(1), None, FEE_RATE, None); // expiration in the past - let result = wallet + let result = party + .wallet .blind_receive( None, Assignment::Any, @@ -450,7 +456,7 @@ fn fail() { assert!(matches!(result, Error::InvalidExpiration)); // bad asset id - let result = wallet.blind_receive( + let result = party.wallet.blind_receive( Some(s!("rgb1inexistent")), Assignment::Any, None, @@ -460,15 +466,15 @@ fn fail() { assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ }))); // cannot blind if all UTXOS already have an allocation - let _asset = test_issue_asset_nia(&mut wallet, online, None); - let result = test_blind_receive_result(&mut wallet); + let _asset = party.issue_asset_nia(None); + let result = party.blind_receive_result(); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // transport endpoints: malformed string - fund_wallet(test_get_address(&mut wallet)); - test_create_utxos_default(&mut wallet, online); + fund_wallet(party.get_address()); + party.create_utxos_default(); let transport_endpoints = vec!["malformed".to_string()]; - let result = blind_receive_withte(&mut wallet, transport_endpoints); + let result = blind_receive_withte(&mut party.wallet, transport_endpoints); assert!(matches!( result, Err(Error::InvalidTransportEndpoint { details: _ }) @@ -476,7 +482,7 @@ fn fail() { // transport endpoints: unknown transport type let transport_endpoints = vec![format!("unknown://{PROXY_HOST}")]; - let result = blind_receive_withte(&mut wallet, transport_endpoints); + let result = blind_receive_withte(&mut party.wallet, transport_endpoints); assert!(matches!( result, Err(Error::InvalidTransportEndpoint { details: _ }) @@ -484,12 +490,12 @@ fn fail() { // transport endpoints: transport type supported by RgbInvoice but unsupported by rgb-lib let transport_endpoints = vec![format!("ws://{PROXY_HOST}")]; - let result = blind_receive_withte(&mut wallet, transport_endpoints); + let result = blind_receive_withte(&mut party.wallet, transport_endpoints); assert!(matches!(result, Err(Error::UnsupportedTransportType))); // transport endpoints: not enough endpoints let transport_endpoints = vec![]; - let result = blind_receive_withte(&mut wallet, transport_endpoints); + let result = blind_receive_withte(&mut party.wallet, transport_endpoints); let msg = s!("must provide at least a transport endpoint"); assert!(matches!( result, @@ -503,7 +509,7 @@ fn fail() { format!("rpc://127.0.0.1:3002/json-rpc"), format!("rpc://127.0.0.1:3003/json-rpc"), ]; - let result = blind_receive_withte(&mut wallet, transport_endpoints); + let result = blind_receive_withte(&mut party.wallet, transport_endpoints); let msg = format!("library supports at max {MAX_TRANSPORT_ENDPOINTS} transport endpoints"); assert!(matches!( result, @@ -512,21 +518,17 @@ fn fail() { // transport endpoints: no endpoints for transfer > Failed let transport_endpoints = vec![format!("rpc://{PROXY_HOST}")]; - let receive_data = blind_receive_withte(&mut wallet, transport_endpoints).unwrap(); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); + let receive_data = blind_receive_withte(&mut party.wallet, transport_endpoints).unwrap(); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); for (tte, _) in tte_data { - txn.del_transfer_transport_endpoint(tte.idx).unwrap(); + party.db_del_transfer_transport_endpoint(tte.idx); } - txn.commit().unwrap(); assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); - wait_for_refresh(&mut wallet, online, None, None); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + party.wait_for_refresh(None); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(transfer_data.status, TransferStatus::Failed); // transport endpoints: same endpoint repeated @@ -535,7 +537,7 @@ fn fail() { format!("rpc://{PROXY_HOST}"), format!("rpc://{PROXY_HOST}"), ]; - let result = blind_receive_withte(&mut wallet, transport_endpoints); + let result = blind_receive_withte(&mut party.wallet, transport_endpoints); let msg = s!("no duplicate transport endpoints allowed"); assert!(matches!( result, @@ -545,7 +547,7 @@ fn fail() { // invoice: unsupported layer 1 println!("setting MOCK_CHAIN_NET"); MOCK_CHAIN_NET.replace(Some(ChainNet::LiquidTestnet)); - let recipient_data = test_blind_receive(&mut wallet); + let recipient_data = party.blind_receive(); let result = Invoice::new(recipient_data.invoice); assert!(matches!(result, Err(Error::UnsupportedLayer1 { layer_1: l }) if l == "liquid" )); } @@ -558,14 +560,15 @@ fn wrong_asset_fail() { let amount: u64 = 66; - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue one asset per wallet - let asset_a = test_issue_asset_nia(&mut wallet_1, online_1, None); - let asset_b = test_issue_asset_nia(&mut wallet_2, online_2, None); + let asset_a = party_1.issue_asset_nia(None); + let asset_b = party_2.issue_asset_nia(None); - let receive_data_a = wallet_1 + let receive_data_a = party_1 + .wallet .blind_receive( Some(asset_a.asset_id), Assignment::Any, @@ -584,25 +587,25 @@ fn wrong_asset_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // transfer is pending - let rcv_transfer_a = get_test_transfer_recipient(&wallet_1, &receive_data_a.recipient_id); - let (rcv_transfer_data_a, _) = get_test_transfer_data(&wallet_1, &rcv_transfer_a); + let rcv_transfer_a = party_1.get_test_transfer_recipient(&receive_data_a.recipient_id); + let (rcv_transfer_data_a, _) = party_1.get_test_transfer_data(&rcv_transfer_a); assert_eq!( rcv_transfer_data_a.status, TransferStatus::WaitingCounterparty ); // transfer doesn't progress to status WaitingConfirmations on the receiving side - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); // transfer has been NACKed - let (rcv_transfer_data_a, _) = get_test_transfer_data(&wallet_1, &rcv_transfer_a); + let (rcv_transfer_data_a, _) = party_1.get_test_transfer_data(&rcv_transfer_a); assert_eq!(rcv_transfer_data_a.status, TransferStatus::Failed); - let rcv_transfers_b_result = test_list_transfers_result(&wallet_1, Some(&asset_b.asset_id)); + let rcv_transfers_b_result = party_1.list_transfers_result(Some(&asset_b.asset_id)); assert!(matches!( rcv_transfers_b_result, Err(Error::AssetNotFound { asset_id: _ }) @@ -650,29 +653,21 @@ fn multiple_receive_same_utxo() { let amount: u64 = 66; - let (mut wallet_recv, online_recv) = get_funded_noutxo_wallet!(); - let (mut wallet_send_1, online_send_1) = get_funded_wallet!(); - let (mut wallet_send_2, online_send_2) = get_funded_wallet!(); + let mut party_recv = get_funded_noutxo_party!(); + let mut party_send_1 = get_funded_party!(); + let mut party_send_2 = get_funded_party!(); // create 1 colorable UTXO on receiver wallet - test_create_utxos( - &mut wallet_recv, - online_recv, - false, - Some(1), - None, - FEE_RATE, - None, - ); - let unspents_recv = test_list_unspents(&mut wallet_recv, None, false); + party_recv.create_utxos(false, Some(1), None, FEE_RATE, None); + let unspents_recv = party_recv.list_unspents(false); assert_eq!(unspents_recv.iter().filter(|u| u.utxo.colorable).count(), 1); // blind twice, yielding 2 invoices paying to the same UTXO - let receive_data_1 = test_blind_receive(&mut wallet_recv); - let receive_data_2 = test_blind_receive(&mut wallet_recv); + let receive_data_1 = party_recv.blind_receive(); + let receive_data_2 = party_recv.blind_receive(); // check both transfers are to be received on the same UTXO - let transfers_recv = test_list_transfers(&wallet_recv, None); + let transfers_recv = party_recv.list_transfers(None); assert!( transfers_recv .windows(2) @@ -680,7 +675,7 @@ fn multiple_receive_same_utxo() { ); // issue + send from wallet_send_1 to wallet_recv blind 1 - let asset_1 = test_issue_asset_nia(&mut wallet_send_1, online_send_1, None); + let asset_1 = party_send_1.issue_asset_nia(None); let recipient_map_1 = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -690,11 +685,11 @@ fn multiple_receive_same_utxo() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_send_1, online_send_1, &recipient_map_1); + let txid_1 = party_send_1.send_retry(&recipient_map_1); assert!(!txid_1.is_empty()); // issue + send from wallet_send_2 to wallet_recv blind 2 - let asset_2 = test_issue_asset_nia(&mut wallet_send_2, online_send_2, None); + let asset_2 = party_send_2.issue_asset_nia(None); let recipient_map_2 = HashMap::from([( asset_2.asset_id.clone(), vec![Recipient { @@ -704,12 +699,12 @@ fn multiple_receive_same_utxo() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_send_2, online_send_2, &recipient_map_2); + let txid_2 = party_send_2.send_retry(&recipient_map_2); assert!(!txid_2.is_empty()); // refresh receiver + check both RGB allocations are on the same UTXO - wait_for_refresh(&mut wallet_recv, online_recv, None, None); - let unspents_recv = test_list_unspents(&mut wallet_recv, None, false); + party_recv.wait_for_refresh(None); + let unspents_recv = party_recv.list_unspents(false); let unspents_recv_colorable: Vec<&Unspent> = unspents_recv.iter().filter(|u| u.utxo.colorable).collect(); assert_eq!(unspents_recv_colorable.len(), 1); diff --git a/src/wallet/test/burn.rs b/src/wallet/test/burn.rs index 015b3e05..35390cdb 100644 --- a/src/wallet/test/burn.rs +++ b/src/wallet/test/burn.rs @@ -2,11 +2,11 @@ use super::*; #[cfg(feature = "electrum")] fn assert_burn_unspents( - wallet: &mut Wallet, + party: &mut SinglesigParty, asset_id: &str, expected_change: Option<(&Outpoint, u64)>, ) { - let unspents = test_list_unspents(wallet, None, false); + let unspents = party.list_unspents(false); // the burnt allocation (Fungible(0)) must not surface anywhere in list_unspents let zero_count = unspents @@ -42,40 +42,37 @@ fn success() { initialize(); // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue let issue_amounts = [AMOUNT, AMOUNT]; - let asset = test_issue_asset_ifa(&mut wallet, online, Some(&issue_amounts), None, None); - show_unspent_colorings(&mut wallet, "after issue"); + let asset = party.issue_asset_ifa(Some(&issue_amounts), None, None); + party.show_unspent_colorings("after issue"); let initial_supply = issue_amounts.iter().sum::(); assert_eq!(asset.initial_supply, initial_supply); assert_eq!(asset.known_circulating_supply, initial_supply); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 1); assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance); - let unspents: Vec = test_list_unspents(&mut wallet, None, false) + let unspents: Vec = party + .list_unspents(false) .into_iter() .filter(|u| u.utxo.colorable) .collect(); assert_eq!(unspents.len(), 5); // burn - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); let burn_amount = 199; - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let res = test_burn(&mut wallet, online, &asset.asset_id, burn_amount); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let res = party.burn(&asset.asset_id, burn_amount); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - show_unspent_colorings(&mut wallet, "after burn"); + party.show_unspent_colorings("after burn"); // check updated balance - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); let burn_change = AMOUNT - burn_amount; let remaining_after_burn = initial_supply - burn_amount; assert_eq!( @@ -89,10 +86,10 @@ fn success() { // mine and refresh mine(false); - assert!(test_refresh_asset(&mut wallet, online, &asset.asset_id)); + assert!(party.refresh_asset(&asset.asset_id)); // check updated balance - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -103,7 +100,7 @@ fn success() { ); // check transfer info - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 2); let transfer = transfers.get(1).unwrap(); assert_eq!(transfer.batch_transfer_idx, 2); @@ -127,21 +124,21 @@ fn success() { assert!(transfer.consignment_path.is_some()); assert_burn_unspents( - &mut wallet, + &mut party, &asset.asset_id, transfer.change_utxo.as_ref().map(|o| (o, burn_change)), ); // inflate using all the default inflation rights, producing a new Fungible allocation // smaller than AMOUNT - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); let inflated_amount = AMOUNT_INFLATION; assert!(inflated_amount < AMOUNT); - test_inflate(&mut wallet, online, &asset.asset_id, &[inflated_amount]); - show_unspent_colorings(&mut wallet, "after inflate"); + party.inflate(&asset.asset_id, &[inflated_amount]); + party.show_unspent_colorings("after inflate"); let amount_after_inflate = remaining_after_burn + inflated_amount; - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -152,10 +149,10 @@ fn success() { ); mine(false); - assert!(test_refresh_asset(&mut wallet, online, &asset.asset_id)); - show_unspent_colorings(&mut wallet, "after inflate mine + refresh"); + assert!(party.refresh_asset(&asset.asset_id)); + party.show_unspent_colorings("after inflate mine + refresh"); - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -170,17 +167,17 @@ fn success() { // input selection sorts by main amount ascending, so it should pick the inflated allocation // first, then the burn change, leaving the untouched AMOUNT allocation as the only spendable // one before the burn tx is mined - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); let burn_amount_2 = burn_change + inflated_amount - 100; assert!(burn_amount_2 > burn_change); assert!(burn_amount_2 > inflated_amount); assert!(burn_amount_2 < burn_change + inflated_amount); - let res_burn_2 = test_burn(&mut wallet, online, &asset.asset_id, burn_amount_2); - show_unspent_colorings(&mut wallet, "after second burn"); + let res_burn_2 = party.burn(&asset.asset_id, burn_amount_2); + party.show_unspent_colorings("after second burn"); let remaining_amount = amount_after_inflate - burn_amount_2; let burn_change_2 = burn_change + inflated_amount - burn_amount_2; - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -191,10 +188,10 @@ fn success() { ); mine(false); - assert!(test_refresh_asset(&mut wallet, online, &asset.asset_id)); - show_unspent_colorings(&mut wallet, "after second burn mine + refresh"); + assert!(party.refresh_asset(&asset.asset_id)); + party.show_unspent_colorings("after second burn mine + refresh"); - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -205,7 +202,7 @@ fn success() { ); // check second burn transfer info - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 4); let transfer = transfers.get(3).unwrap(); assert_eq!(transfer.status, TransferStatus::Settled); @@ -224,13 +221,13 @@ fn success() { assert!(transfer.change_utxo.is_some()); assert_burn_unspents( - &mut wallet, + &mut party, &asset.asset_id, transfer.change_utxo.as_ref().map(|o| (o, burn_change_2)), ); // send all - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -240,22 +237,18 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after send"); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + party.show_unspent_colorings("after send"); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), 1); let ce = tte_data.first().unwrap(); assert_eq!(ce.1.endpoint, PROXY_URL); assert!(ce.0.used); // check balance (no assets left) - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -266,13 +259,12 @@ fn success() { ); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + rcv_party.wait_for_refresh(None); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _rcv_asset_transfer) = rcv_party.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(Some(&asset.asset_id)); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations @@ -280,7 +272,7 @@ fn success() { assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations); // asset has been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let ifa_assets = rcv_assets.ifa.unwrap(); assert_eq!(ifa_assets.len(), 1); let rcv_asset = ifa_assets.last().unwrap(); @@ -297,16 +289,16 @@ fn success() { } ); assert_eq!(rcv_asset.initial_supply, initial_supply); - show_unspent_colorings(&mut wallet, "after send refresh 1"); + party.show_unspent_colorings("after send refresh 1"); // transfers progress to status Settled after tx mining + refresh mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - show_unspent_colorings(&mut wallet, "after send mine + refresh 2"); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + party.show_unspent_colorings("after send mine + refresh 2"); // check balance (no assets left) - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -316,33 +308,28 @@ fn success() { } ); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.change_utxo, None); - let asset_metadata = test_get_asset_metadata(&rcv_wallet, &asset.asset_id); + let asset_metadata = rcv_party.get_asset_metadata(&asset.asset_id); assert_eq!(asset_metadata.initial_supply, initial_supply); // check there's no change (sent all) assert!(transfer_data.change_utxo.is_none()); // the receiving wallet now holds all remaining assets: burn part of them, then burn the rest - test_create_utxos_default(&mut rcv_wallet, rcv_online); + rcv_party.create_utxos_default(); let rcv_burn_amount = 50; - let res_rcv_burn = test_burn( - &mut rcv_wallet, - rcv_online, - &asset.asset_id, - rcv_burn_amount, - ); - show_unspent_colorings(&mut rcv_wallet, "after rcv partial burn"); + let res_rcv_burn = rcv_party.burn(&asset.asset_id, rcv_burn_amount); + rcv_party.show_unspent_colorings("after rcv partial burn"); let rcv_remaining = remaining_amount - rcv_burn_amount; - let balance = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + let balance = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -353,14 +340,10 @@ fn success() { ); mine(false); - assert!(test_refresh_asset( - &mut rcv_wallet, - rcv_online, - &asset.asset_id - )); - show_unspent_colorings(&mut rcv_wallet, "after rcv partial burn mine + refresh"); - - let balance = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + assert!(rcv_party.refresh_asset(&asset.asset_id)); + rcv_party.show_unspent_colorings("after rcv partial burn mine + refresh"); + + let balance = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -370,7 +353,7 @@ fn success() { } ); - let rcv_transfers = test_list_transfers(&rcv_wallet, Some(&asset.asset_id)); + let rcv_transfers = rcv_party.list_transfers(Some(&asset.asset_id)); let rcv_burn_transfer = rcv_transfers.last().unwrap(); assert_eq!(rcv_burn_transfer.status, TransferStatus::Settled); assert_eq!(rcv_burn_transfer.kind, TransferKind::Burn); @@ -385,7 +368,7 @@ fn success() { assert_eq!(rcv_burn_transfer.txid.as_ref().unwrap(), &res_rcv_burn.txid); assert_burn_unspents( - &mut rcv_wallet, + &mut rcv_party, &asset.asset_id, rcv_burn_transfer .change_utxo @@ -394,11 +377,11 @@ fn success() { ); // burn everything from the receiving wallet - test_create_utxos_default(&mut rcv_wallet, rcv_online); - let res_rcv_burn_all = test_burn(&mut rcv_wallet, rcv_online, &asset.asset_id, rcv_remaining); - show_unspent_colorings(&mut rcv_wallet, "after rcv burn all"); + rcv_party.create_utxos_default(); + let res_rcv_burn_all = rcv_party.burn(&asset.asset_id, rcv_remaining); + rcv_party.show_unspent_colorings("after rcv burn all"); - let balance = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + let balance = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -409,14 +392,10 @@ fn success() { ); mine(false); - assert!(test_refresh_asset( - &mut rcv_wallet, - rcv_online, - &asset.asset_id - )); - show_unspent_colorings(&mut rcv_wallet, "after rcv burn all mine + refresh"); - - let balance = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + assert!(rcv_party.refresh_asset(&asset.asset_id)); + rcv_party.show_unspent_colorings("after rcv burn all mine + refresh"); + + let balance = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -426,7 +405,7 @@ fn success() { } ); - let rcv_transfers = test_list_transfers(&rcv_wallet, Some(&asset.asset_id)); + let rcv_transfers = rcv_party.list_transfers(Some(&asset.asset_id)); let rcv_burn_all_transfer = rcv_transfers.last().unwrap(); assert_eq!(rcv_burn_all_transfer.status, TransferStatus::Settled); assert_eq!(rcv_burn_all_transfer.kind, TransferKind::Burn); @@ -441,7 +420,7 @@ fn success() { // nothing left to burn: no fungible change, no change_utxo assert_eq!(rcv_burn_all_transfer.assignments, vec![]); assert!(rcv_burn_all_transfer.change_utxo.is_none()); - assert_burn_unspents(&mut rcv_wallet, &asset.asset_id, None); + assert_burn_unspents(&mut rcv_party, &asset.asset_id, None); } #[cfg(feature = "electrum")] @@ -450,9 +429,9 @@ fn success() { fn fail() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); - let asset_ifa = test_issue_asset_ifa(&mut wallet, online, None, None, None); + let asset_ifa = party.issue_asset_ifa(None, None, None); // don't check burn input params (checked in _begin/_end sections below) @@ -460,7 +439,8 @@ fn fail() { // - watch-only (_check_xprv) let mut wallet_wo = get_test_wallet(false, None); let online_wo = wallet_wo.go_online(test_go_online_options(None)).unwrap(); - let result = test_burn_result(&mut wallet_wo, online_wo, &asset_ifa.asset_id, 10); + let mut party_wo = party!(wallet_wo, online_wo); + let result = party_wo.burn_result(&asset_ifa.asset_id, 10); assert_matches!(result, Err(Error::WatchOnly)); // - wrong online @@ -468,18 +448,21 @@ fn fail() { // burn_begin input params // - check online is correct - let result = test_burn_begin_result(&mut wallet, wrong_online, &asset_ifa.asset_id, 10); + let good_online = party.online; + party.online = wrong_online; + let result = party.burn_begin_result(&asset_ifa.asset_id, 10); + party.online = good_online; assert_matches!(result, Err(Error::CannotChangeOnline)); // - invalid asset_id - let result = test_burn_begin_result(&mut wallet, online, "malformed", 10); + let result = party.burn_begin_result("malformed", 10); assert_matches!(result, Err(Error::AssetNotFound { asset_id: _ })); // - check zero burn amount - let result = test_burn_begin_result(&mut wallet, online, &asset_ifa.asset_id, 0); + let result = party.burn_begin_result(&asset_ifa.asset_id, 0); assert_matches!(result, Err(Error::NoBurnAmount)); // - check fee_rate // - low - let result = wallet.burn_begin( - online, + let result = party.wallet.burn_begin( + party.online, asset_ifa.asset_id.clone(), 10, 0, @@ -488,8 +471,8 @@ fn fail() { ); assert_matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW); // - overflow - let result = wallet.burn_begin( - online, + let result = party.wallet.burn_begin( + party.online, asset_ifa.asset_id.clone(), 10, u64::MAX, @@ -500,7 +483,7 @@ fn fail() { // burn_begin errors // - inexistent asset - let result = test_burn_begin_result(&mut wallet, online, "rgb1nexistent", 10); + let result = party.burn_begin_result("rgb1nexistent", 10); assert_matches!(result, Err(Error::AssetNotFound { asset_id: _ })); // - schema not supported create_test_data_dir(); @@ -520,9 +503,10 @@ fn fail() { let online_nia = wallet_nia .go_online(test_go_online_options(Some(ELECTRUM_URL))) .unwrap(); - fund_wallet(wallet_nia.get_address().unwrap()); - test_create_utxos_default(&mut wallet_nia, online_nia); - let receive_data = test_blind_receive(&mut wallet_nia); + let mut party_nia = party!(wallet_nia, online_nia); + fund_wallet(party_nia.get_address()); + party_nia.create_utxos_default(); + let receive_data = party_nia.blind_receive(); let recipient_map = HashMap::from([( asset_ifa.asset_id.clone(), vec![Recipient { @@ -532,20 +516,20 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_nia, online_nia, None, None); - wait_for_refresh(&mut wallet, online, None, None); + party_nia.wait_for_refresh(None); + party.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_nia, online_nia, None, None); - wait_for_refresh(&mut wallet, online, None, None); - let transfer_recv = get_test_transfer_recipient(&wallet_nia, &receive_data.recipient_id); - let (transfer_send, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data_recv, _) = get_test_transfer_data(&wallet_nia, &transfer_recv); - let (transfer_data_send, _) = get_test_transfer_data(&wallet, &transfer_send); + party_nia.wait_for_refresh(None); + party.wait_for_refresh(None); + let transfer_recv = party_nia.get_test_transfer_recipient(&receive_data.recipient_id); + let (transfer_send, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data_recv, _) = party_nia.get_test_transfer_data(&transfer_recv); + let (transfer_data_send, _) = party.get_test_transfer_data(&transfer_send); assert_eq!(transfer_data_recv.status, TransferStatus::Settled); assert_eq!(transfer_data_send.status, TransferStatus::Settled); - drop(wallet_nia); + drop(party_nia); let mut wallet_nia = Wallet::new( WalletData { data_dir: get_test_data_dir_string(), @@ -560,51 +544,56 @@ fn fail() { let online_nia = wallet_nia .go_online(test_go_online_options(Some(ELECTRUM_URL))) .unwrap(); - let result = test_burn_begin_result(&mut wallet_nia, online_nia, &asset_ifa.asset_id, 10); + let mut party_nia = party!(wallet_nia, online_nia); + let result = party_nia.burn_begin_result(&asset_ifa.asset_id, 10); assert_matches!(result, Err(Error::UnsupportedSchema { asset_schema: _ })); // - burn not supported - let asset_nia = test_issue_asset_nia(&mut wallet, online, None); - let asset_cfa = test_issue_asset_cfa(&mut wallet, online, None, None); - let asset_uda = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); + let asset_nia = party.issue_asset_nia(None); + let asset_cfa = party.issue_asset_cfa(None, None); + let asset_uda = party.issue_asset_uda(None, None, vec![]); let unsupported_asset_ids = [ (asset_nia.asset_id, AssetSchema::Nia), (asset_cfa.asset_id, AssetSchema::Cfa), (asset_uda.asset_id, AssetSchema::Uda), ]; for (asset_id, schema) in unsupported_asset_ids { - let result = test_burn_result(&mut wallet, online, &asset_id, 10); + let result = party.burn_result(&asset_id, 10); assert_matches!(result, Err(Error::UnsupportedBurn { asset_schema }) if asset_schema == schema); } // - burn zero amount - let result = test_burn_begin_result(&mut wallet, online, &asset_ifa.asset_id, 0); + let result = party.burn_begin_result(&asset_ifa.asset_id, 0); assert_matches!(result, Err(Error::NoBurnAmount)); // burn_end input params - let address = test_get_address(&mut wallet); - let unsigned_psbt = wallet - .send_btc_begin(online, address, 1000, FEE_RATE, false, true) + let address = party.get_address(); + let unsigned_psbt = party + .wallet + .send_btc_begin(party.online, address, 1000, FEE_RATE, false, true) .unwrap(); - let signed_psbt = wallet.sign_psbt(unsigned_psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt, None).unwrap(); // - check online is correct - let result = test_burn_end_result(&mut wallet, wrong_online, &signed_psbt); + let good_online = party.online; + party.online = wrong_online; + let result = party.burn_end_result(&signed_psbt); + party.online = good_online; assert_matches!(result, Err(Error::CannotChangeOnline)); // - check signed_psbt is valid - let result = test_burn_end_result(&mut wallet, online, ""); + let result = party.burn_end_result(""); assert_matches!(result, Err(Error::InvalidPsbt { details: _ })); // burn_end errors // - no prior burn_begin - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let unsigned_psbt = test_burn_begin(&mut wallet, online, &asset_ifa.asset_id, 10); - let signed_psbt = wallet.sign_psbt(unsigned_psbt, None).unwrap(); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let unsigned_psbt = party.burn_begin(&asset_ifa.asset_id, 10); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt, None).unwrap(); let psbt_txid = Psbt::from_str(&signed_psbt) .unwrap() .extract_tx() .unwrap() .compute_txid() .to_string(); - let (mut wallet_2, online_2) = get_empty_wallet!(); - let result = test_burn_end_result(&mut wallet_2, online_2, &signed_psbt); + let mut party_2 = get_empty_party!(); + let result = party_2.burn_end_result(&signed_psbt); assert_matches!(result, Err(Error::UnknownTransfer { txid }) if txid == psbt_txid); } @@ -614,16 +603,15 @@ fn fail() { fn begin_end() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let asset = test_issue_asset_ifa(&mut wallet, online, None, None, None); + let mut party = get_funded_party!(); + let asset = party.issue_asset_ifa(None, None, None); // begin does not update backup_info with dry_run=true - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let _res = wallet + let bak_info_before = party.db_backup_info(); + let _res = party + .wallet .burn_begin( - online, + party.online, asset.asset_id.clone(), AMOUNT, FEE_RATE, @@ -631,21 +619,18 @@ fn begin_end() { true, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); // begin does update backup_info with dry_run=false - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let res = wallet + let bak_info_before = party.db_backup_info(); + let res = party + .wallet .burn_begin( - online, + party.online, asset.asset_id.clone(), AMOUNT, FEE_RATE, @@ -653,20 +638,14 @@ fn begin_end() { false, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let signed_psbt = wallet.sign_psbt(res.psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(res.psbt, None).unwrap(); // end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.burn_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party.wallet.burn_end(party.online, signed_psbt).unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); } diff --git a/src/wallet/test/create_utxos.rs b/src/wallet/test/create_utxos.rs index 9bb0069f..3fbc4793 100644 --- a/src/wallet/test/create_utxos.rs +++ b/src/wallet/test/create_utxos.rs @@ -8,36 +8,24 @@ fn success() { // up_to version with 0 allocatable UTXOs println!("\n=== up_to true, 0 allocatable"); - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - test_create_utxos(&mut wallet, online, true, None, None, FEE_RATE, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let mut party = get_funded_noutxo_party!(); + let bak_info_before = party.db_backup_info(); + party.create_utxos(true, None, None, FEE_RATE, None); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), (UTXO_NUM + 1) as usize); // up_to version with allocatable UTXOs partially available (1 missing) println!("\n=== up_to true, need to create 1 more"); - test_create_utxos( - &mut wallet, - online, - true, - Some(UTXO_NUM + 1), - None, - FEE_RATE, - Some(1), - ); - let unspents = test_list_unspents(&mut wallet, None, false); + party.create_utxos(true, Some(UTXO_NUM + 1), None, FEE_RATE, Some(1)); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), (UTXO_NUM + 2) as usize); // forced version always creates UTXOs println!("\n=== up_to false"); - test_create_utxos(&mut wallet, online, false, None, None, FEE_RATE, None); - let unspents = test_list_unspents(&mut wallet, None, false); + party.create_utxos(false, None, None, FEE_RATE, None); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), (UTXO_NUM * 2 + 2) as usize); } @@ -50,17 +38,17 @@ fn up_to_allocation_checks() { let amount = 66; // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); // MAX_ALLOCATIONS_PER_UTXO failed allocations // - check unspent counted as allocatable - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); + party.create_utxos(false, Some(1), None, FEE_RATE, None); let mut batch_transfer_idxs: Vec = vec![]; let mut txo_list: HashSet = HashSet::new(); for _ in 0..MAX_ALLOCATIONS_PER_UTXO { - let receive_data = test_blind_receive(&mut wallet); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let receive_data = party.blind_receive(); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); let txo = if let RecipientTypeFull::Blind { unblinded_utxo } = transfer.recipient_type.unwrap() { unblinded_utxo @@ -73,28 +61,26 @@ fn up_to_allocation_checks() { // check all transfers are on the same UTXO + fail all of them assert_eq!(txo_list.len(), 1); for batch_transfer_idx in batch_transfer_idxs { - assert!(test_fail_transfers_single( - &mut wallet, - online, - batch_transfer_idx - )); + assert!(party.fail_transfers_single(batch_transfer_idx)); } // request 1 new UTXO, expecting the existing one is still allocatable - let result = wallet.create_utxos(online, true, Some(1), None, FEE_RATE, false); + let result = party + .wallet + .create_utxos(party.online, true, Some(1), None, FEE_RATE, false); assert!(matches!(result, Err(Error::AllocationsAlreadyAvailable))); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 2); // new wallet - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); // MAX_ALLOCATIONS_PER_UTXO allocations - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); + party.create_utxos(true, Some(1), None, FEE_RATE, None); // create MAX_ALLOCATIONS_PER_UTXO blinds on the same UTXO let mut txo_list: HashSet = HashSet::new(); for _ in 0..MAX_ALLOCATIONS_PER_UTXO { - let receive_data = test_blind_receive(&mut wallet); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); + let receive_data = party.blind_receive(); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); let txo = if let RecipientTypeFull::Blind { unblinded_utxo } = transfer.recipient_type.unwrap() { unblinded_utxo @@ -105,29 +91,21 @@ fn up_to_allocation_checks() { } assert_eq!(txo_list.len(), 1); // request 1 new UTXO, expecting one is created - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); - let unspents = test_list_unspents(&mut wallet, None, false); + party.create_utxos(true, Some(1), None, FEE_RATE, None); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 3); if MAX_ALLOCATIONS_PER_UTXO > 2 { // new wallet - let (mut wallet, online) = get_funded_noutxo_wallet!(); - fund_wallet(test_get_address(&mut rcv_wallet)); - - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); - test_create_utxos( - &mut rcv_wallet, - rcv_online, - true, - Some(1), - None, - FEE_RATE, - None, - ); + let mut party = get_funded_noutxo_party!(); + fund_wallet(rcv_party.get_address()); + + party.create_utxos(true, Some(1), None, FEE_RATE, None); + rcv_party.create_utxos(true, Some(1), None, FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -137,43 +115,51 @@ fn up_to_allocation_checks() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // - wait counterparty // UTXO 1 (input) locked, new UTXO created for change (exists = false) - show_unspent_colorings(&mut wallet, "sender after send - WaitingCounterparty"); - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); + party.show_unspent_colorings("sender after send - WaitingCounterparty"); + party.create_utxos(true, Some(1), None, FEE_RATE, None); // UTXO 1 (blind) has at least 1 free allocation - show_unspent_colorings(&mut rcv_wallet, "receiver after send - WaitingCounterparty"); - let result = rcv_wallet.create_utxos(rcv_online, true, Some(1), None, FEE_RATE, false); + rcv_party.show_unspent_colorings("receiver after send - WaitingCounterparty"); + let result = + rcv_party + .wallet + .create_utxos(rcv_party.online, true, Some(1), None, FEE_RATE, false); assert!(matches!(result, Err(Error::AllocationsAlreadyAvailable))); // - wait confirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // UTXO 1 now spent, UTXO 2 (RGB+BTC change) has at least 1 free allocation, UTXO 3 is empty - show_unspent_colorings(&mut wallet, "sender after send - WaitingConfirmations"); - let result = wallet.create_utxos(online, true, Some(2), None, FEE_RATE, false); + party.show_unspent_colorings("sender after send - WaitingConfirmations"); + let result = party + .wallet + .create_utxos(party.online, true, Some(2), None, FEE_RATE, false); assert!(matches!(result, Err(Error::AllocationsAlreadyAvailable))); // UTXO 1 (blind) has at least 1 free allocation - show_unspent_colorings( - &mut rcv_wallet, - "receiver after send - WaitingConfirmations", - ); - let result = rcv_wallet.create_utxos(rcv_online, true, Some(1), None, FEE_RATE, false); + rcv_party.show_unspent_colorings("receiver after send - WaitingConfirmations"); + let result = + rcv_party + .wallet + .create_utxos(rcv_party.online, true, Some(1), None, FEE_RATE, false); assert!(matches!(result, Err(Error::AllocationsAlreadyAvailable))); // - settled mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // UTXO 1 now spent, UTXO 2 (RGB+BTC change) has at least 1 free allocation, UTXO 3 is empty - show_unspent_colorings(&mut wallet, "sender after send - Settled"); - test_create_utxos(&mut wallet, online, true, Some(3), None, FEE_RATE, Some(1)); + party.show_unspent_colorings("sender after send - Settled"); + party.create_utxos(true, Some(3), None, FEE_RATE, Some(1)); // UTXO 1 (blind) has at least 1 free allocation - show_unspent_colorings(&mut rcv_wallet, "receiver after send - Settled"); - let result = rcv_wallet.create_utxos(rcv_online, true, Some(1), None, FEE_RATE, false); + rcv_party.show_unspent_colorings("receiver after send - Settled"); + let result = + rcv_party + .wallet + .create_utxos(rcv_party.online, true, Some(1), None, FEE_RATE, false); assert!(matches!(result, Err(Error::AllocationsAlreadyAvailable))); } } @@ -185,8 +171,10 @@ fn fail() { initialize(); // cannot create UTXOs for an empty wallet - let (mut wallet, online) = get_empty_wallet!(); - let result = wallet.create_utxos(online, true, None, None, FEE_RATE, false); + let mut party = get_empty_party!(); + let result = party + .wallet + .create_utxos(party.online, true, None, None, FEE_RATE, false); assert!(matches!( result, Err(Error::InsufficientBitcoins { @@ -195,30 +183,29 @@ fn fail() { }) if n == (UTXO_SIZE as u64 * UTXO_NUM as u64) + 1000 && a == 0 )); - fund_wallet(test_get_address(&mut wallet)); - test_create_utxos_default(&mut wallet, online); + fund_wallet(party.get_address()); + party.create_utxos_default(); // don't create UTXOs if enough allocations are already available - let result = wallet.create_utxos(online, true, None, None, FEE_RATE, false); + let result = party + .wallet + .create_utxos(party.online, true, None, None, FEE_RATE, false); assert!(matches!(result, Err(Error::AllocationsAlreadyAvailable))); // fee min - let result = test_create_utxos_begin_result(&mut wallet, online, false, Some(1), None, 0); + let result = party.create_utxos_begin_result(false, Some(1), None, 0); assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW)); // fee overflow - let result = - test_create_utxos_begin_result(&mut wallet, online, false, Some(1), None, u64::MAX); + let result = party.create_utxos_begin_result(false, Some(1), None, u64::MAX); assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_OVER)); // invalid amount - let result = - test_create_utxos_begin_result(&mut wallet, online, false, Some(1), Some(0), FEE_RATE); + let result = party.create_utxos_begin_result(false, Some(1), Some(0), FEE_RATE); assert!(matches!(result, Err(Error::InvalidAmountZero))); // output below dust limit - let result = - test_create_utxos_begin_result(&mut wallet, online, false, Some(1), Some(1), FEE_RATE); + let result = party.create_utxos_begin_result(false, Some(1), Some(1), FEE_RATE); assert!(matches!(result, Err(Error::OutputBelowDustLimit))); } @@ -235,8 +222,8 @@ fn casting() { let funds = 100_000_000; let utxo_size = funds as u32 / 256; - let (mut wallet, online) = get_empty_wallet!(); - fund_wallet(test_get_address(&mut wallet)); + let mut party = get_empty_party!(); + fund_wallet(party.get_address()); let expected_balance = BtcBalance { vanilla: Balance { settled: funds, @@ -249,17 +236,9 @@ fn casting() { spendable: 0, }, }; - wait_for_btc_balance(&mut wallet, online, &expected_balance); - test_create_utxos( - &mut wallet, - online, - true, - None, - Some(utxo_size), - FEE_RATE, - None, - ); - let unspents = test_list_unspents(&mut wallet, None, false); + party.wait_for_btc_balance(&expected_balance); + party.create_utxos(true, None, Some(utxo_size), FEE_RATE, None); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), (UTXO_NUM + 1) as usize); } @@ -270,12 +249,14 @@ fn skip_sync() { initialize(); // prepare wallet with 1 bitcoin UTXO - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); // bitcoin UTXO not yet visible > creating UTXOs skipping sync fails - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 0); - let result = wallet.create_utxos(online, true, None, None, FEE_RATE, true); + let result = party + .wallet + .create_utxos(party.online, true, None, None, FEE_RATE, true); assert_matches!( result, Err(Error::InsufficientBitcoins { @@ -285,9 +266,10 @@ fn skip_sync() { ); // sync so the bitcoin UTXO becomes visible - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -296,30 +278,32 @@ fn skip_sync() { }, ) .unwrap(); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 1); // create UTXOs skipping sync - let num_utxos_created = wallet - .create_utxos(online, true, None, None, FEE_RATE, true) + let num_utxos_created = party + .wallet + .create_utxos(party.online, true, None, None, FEE_RATE, true) .unwrap(); assert_eq!(num_utxos_created, UTXO_NUM); // created UTXOs already visible - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), (UTXO_NUM + 1) as usize); // created UTXOs still consistent after syncing - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, }, ) .unwrap(); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), (UTXO_NUM + 1) as usize); } @@ -330,14 +314,15 @@ fn begin_reservation_interactions() { initialize(); // two independent funding UTXOs, each with enough BTC to cover create_utxos - let (mut wallet, online) = get_empty_wallet!(); - fund_wallet(test_get_address(&mut wallet)); - fund_wallet(test_get_address(&mut wallet)); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_empty_party!(); + fund_wallet(party.get_address()); + fund_wallet(party.get_address()); + let mut rcv_party = get_empty_party!(); // create_utxos_begin(dry_run=false) creates CreateUtxos reservation rows - let unsigned_psbt_str = wallet - .create_utxos_begin(online, true, None, None, FEE_RATE, false, false) + let unsigned_psbt_str = party + .wallet + .create_utxos_begin(party.online, true, None, None, FEE_RATE, false, false) .unwrap(); let unsigned_psbt = Psbt::from_str(&unsigned_psbt_str).unwrap(); let psbt_txid = unsigned_psbt.unsigned_tx.compute_txid().to_string(); @@ -350,12 +335,9 @@ fn begin_reservation_interactions() { assert!(!psbt_inputs.is_empty()); // wallet_transaction(CreateUtxos) row exists with reservations matching inputs - let txn = wallet.database().begin_transaction().unwrap(); - let (wt, reservations) = txn - .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) - .unwrap() + let (wt, reservations) = party + .db_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) .expect("wallet_transaction should exist after dry_run=false begin"); - txn.commit().unwrap(); assert_eq!(wt.r#type, WalletTransactionType::CreateUtxos); assert!(reservations.iter().all(|r| r.reserved_for == Some(wt.idx))); let reserved_set: HashSet<(String, u32)> = reservations @@ -365,42 +347,39 @@ fn begin_reservation_interactions() { assert_eq!(reserved_set, psbt_inputs); // list_pending_vanilla_txs reports the in-flight CreateUtxos entry - let pending = wallet.list_pending_vanilla_txs().unwrap(); + let pending = party.wallet.list_pending_vanilla_txs().unwrap(); assert_eq!(pending.len(), 1); assert_eq!(pending[0].txid, psbt_txid); assert_eq!(pending[0].r#type, WalletTransactionType::CreateUtxos); // clear this in-flight create_utxos reservation - wallet.abort_pending_vanilla_tx(psbt_txid).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - assert!(txn.iter_reserved_txos().unwrap().is_empty()); - txn.commit().unwrap(); + party.wallet.abort_pending_vanilla_tx(psbt_txid).unwrap(); + assert!(party.db_reserved_txos().is_empty()); // reserve (at least) one vanilla UTXO via send_btc_begin(dry_run=false). BDK's // coin selection only picks the minimum inputs for amount + fee, so one of the // two funding UTXOs will be left untouched. - let _ = wallet + let _ = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), 1000, FEE_RATE, false, false, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let reserved_set: HashSet<(String, u32)> = txn - .iter_reserved_txos() - .unwrap() + let reserved_set: HashSet<(String, u32)> = party + .db_reserved_txos() .iter() .map(|r| (r.txid.clone(), r.vout)) .collect(); - txn.commit().unwrap(); assert_eq!(reserved_set.len(), 1); // create_utxos_begin(dry_run=true) must not select any reserved outpoint - let unsigned_psbt_str = wallet - .create_utxos_begin(online, true, Some(1), None, FEE_RATE, false, true) + let unsigned_psbt_str = party + .wallet + .create_utxos_begin(party.online, true, Some(1), None, FEE_RATE, false, true) .unwrap(); let unsigned_psbt = Psbt::from_str(&unsigned_psbt_str).unwrap(); let create_inputs: HashSet<(String, u32)> = unsigned_psbt @@ -413,12 +392,16 @@ fn begin_reservation_interactions() { assert!(create_inputs.is_disjoint(&reserved_set)); // reserve the remaining vanilla UTXO via create_utxos_begin(dry_run=false) - let _ = wallet - .create_utxos_begin(online, true, None, None, FEE_RATE, false, false) + let _ = party + .wallet + .create_utxos_begin(party.online, true, None, None, FEE_RATE, false, false) .unwrap(); // now all vanilla UTXOs are reserved, so another begin has nothing usable left - let result = wallet.create_utxos_begin(online, false, Some(1), None, FEE_RATE, true, true); + let result = + party + .wallet + .create_utxos_begin(party.online, false, Some(1), None, FEE_RATE, true, true); assert!(matches!( result, Err(Error::InsufficientBitcoins { @@ -434,44 +417,37 @@ fn begin_reservation_interactions() { fn begin_end() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); // begin does not update backup_info with dry_run=true - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let _psbt = wallet - .create_utxos_begin(online, true, None, None, FEE_RATE, false, true) + let bak_info_before = party.db_backup_info(); + let _psbt = party + .wallet + .create_utxos_begin(party.online, true, None, None, FEE_RATE, false, true) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); // begin does update backup_info with dry_run=false - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let psbt = wallet - .create_utxos_begin(online, true, None, None, FEE_RATE, false, false) + let bak_info_before = party.db_backup_info(); + let psbt = party + .wallet + .create_utxos_begin(party.online, true, None, None, FEE_RATE, false, false) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let signed_psbt = wallet.sign_psbt(psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(psbt, None).unwrap(); // end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.create_utxos_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party + .wallet + .create_utxos_end(party.online, signed_psbt) + .unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); } diff --git a/src/wallet/test/delete_transfers.rs b/src/wallet/test/delete_transfers.rs index bed395e1..561bb78a 100644 --- a/src/wallet/test/delete_transfers.rs +++ b/src/wallet/test/delete_transfers.rs @@ -6,125 +6,83 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // return false if no transfer has changed - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 0); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - assert!(!test_delete_transfers(&wallet, None, false)); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + assert!(!party.delete_transfers(None, false)); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 0); // delete single transfer - let receive_data = test_blind_receive(&mut wallet); - test_fail_transfers_single(&mut wallet, online, receive_data.batch_transfer_idx); - assert!(check_test_transfer_status_recipient( - &wallet, - &receive_data.recipient_id, - TransferStatus::Failed - )); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let receive_data = party.blind_receive(); + party.fail_transfers_single(receive_data.batch_transfer_idx); + assert!( + party.check_test_transfer_status_recipient( + &receive_data.recipient_id, + TransferStatus::Failed + ) + ); + let bak_info_before = party.db_backup_info(); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 1); - assert!(test_delete_transfers( - &wallet, - Some(receive_data.batch_transfer_idx), - false - )); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + assert!(party.delete_transfers(Some(receive_data.batch_transfer_idx), false)); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 0); // delete all Failed transfers - let receive_data_1 = test_blind_receive(&mut wallet); - let receive_data_2 = test_blind_receive(&mut wallet); - let receive_data_3 = test_blind_receive(&mut wallet); - test_fail_transfers_single(&mut wallet, online, receive_data_1.batch_transfer_idx); - test_fail_transfers_single(&mut wallet, online, receive_data_2.batch_transfer_idx); - assert!(check_test_transfer_status_recipient( - &wallet, + let receive_data_1 = party.blind_receive(); + let receive_data_2 = party.blind_receive(); + let receive_data_3 = party.blind_receive(); + party.fail_transfers_single(receive_data_1.batch_transfer_idx); + party.fail_transfers_single(receive_data_2.batch_transfer_idx); + assert!(party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::Failed )); - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::Failed )); - show_unspent_colorings(&mut wallet, "run 1 before delete"); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + party.show_unspent_colorings("run 1 before delete"); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 3); - assert!(test_delete_transfers(&wallet, None, false)); - show_unspent_colorings(&mut wallet, "run 1 after delete"); - let txn = wallet.database().begin_transaction().unwrap(); - let transfers = txn.iter_transfers().unwrap(); - txn.commit().unwrap(); + assert!(party.delete_transfers(None, false)); + party.show_unspent_colorings("run 1 after delete"); + let transfers = party.db_transfers(); assert_eq!(transfers.len(), 1); - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingCounterparty )); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 1); // fail and delete remaining pending transfers - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 1); - assert!(test_fail_transfers_single( - &mut wallet, - online, - receive_data_3.batch_transfer_idx - )); - assert!(test_delete_transfers( - &wallet, - Some(receive_data_3.batch_transfer_idx), - false - )); - let txn = wallet.database().begin_transaction().unwrap(); - let transfers = txn.iter_transfers().unwrap(); - txn.commit().unwrap(); + assert!(party.fail_transfers_single(receive_data_3.batch_transfer_idx)); + assert!(party.delete_transfers(Some(receive_data_3.batch_transfer_idx), false)); + let transfers = party.db_transfers(); assert_eq!(transfers.len(), 0); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 0); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // delete an initiated transfer with no RGB change - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -134,9 +92,10 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let send_result = wallet + let send_result = party + .wallet .send_begin( - online, + party.online, recipient_map, false, FEE_RATE, @@ -146,39 +105,23 @@ fn success() { ) .unwrap(); let batch_transfer_idx = send_result.batch_transfer_idx.unwrap(); - test_fail_transfers_single(&mut wallet, online, batch_transfer_idx); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + party.fail_transfers_single(batch_transfer_idx); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 2); - let txn = wallet.database().begin_transaction().unwrap(); - let txos_before = txn.iter_txos().unwrap(); - txn.commit().unwrap(); + let txos_before = party.db_txos(); assert_eq!(txos_before.len(), 5); - let txn = wallet.database().begin_transaction().unwrap(); - let colorings_before = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); + let colorings_before = party.db_colorings(); assert_eq!(colorings_before.len(), 2); - assert!(test_delete_transfers( - &wallet, - Some(batch_transfer_idx), - false - )); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + assert!(party.delete_transfers(Some(batch_transfer_idx), false)); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 1); - let txn = wallet.database().begin_transaction().unwrap(); - let txos_after = txn.iter_txos().unwrap(); - txn.commit().unwrap(); + let txos_after = party.db_txos(); assert_eq!(txos_after.len(), 5); - let txn = wallet.database().begin_transaction().unwrap(); - let colorings_after = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); + let colorings_after = party.db_colorings(); assert_eq!(colorings_after.len(), 1); // delete an initiated transfer with RGB change on bitcoin change UTXO - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -188,9 +131,10 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let send_result = wallet + let send_result = party + .wallet .send_begin( - online, + party.online, recipient_map, false, FEE_RATE, @@ -200,40 +144,25 @@ fn success() { ) .unwrap(); let batch_transfer_idx = send_result.batch_transfer_idx.unwrap(); - test_fail_transfers_single(&mut wallet, online, batch_transfer_idx); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + party.fail_transfers_single(batch_transfer_idx); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 2); - let txn = wallet.database().begin_transaction().unwrap(); - let txos_before = txn.iter_txos().unwrap(); - txn.commit().unwrap(); + let txos_before = party.db_txos(); assert_eq!(txos_before.len(), 6); - let txn = wallet.database().begin_transaction().unwrap(); - let colorings_before = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); + let colorings_before = party.db_colorings(); assert_eq!(colorings_before.len(), 3); - assert!(test_delete_transfers( - &wallet, - Some(batch_transfer_idx), - false - )); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + assert!(party.delete_transfers(Some(batch_transfer_idx), false)); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 1); - let txn = wallet.database().begin_transaction().unwrap(); - let txos_after = txn.iter_txos().unwrap(); - txn.commit().unwrap(); + let txos_after = party.db_txos(); assert_eq!(txos_after.len(), 5); - let txn = wallet.database().begin_transaction().unwrap(); - let colorings_after = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); + let colorings_after = party.db_colorings(); assert_eq!(colorings_after.len(), 1); // don't delete failed transfer with asset_id if no_asset_only is true - let receive_data_1 = test_blind_receive(&mut wallet); - let receive_data_2 = wallet + let receive_data_1 = party.blind_receive(); + let receive_data_2 = party + .wallet .blind_receive( Some(asset.asset_id), Assignment::Any, @@ -242,35 +171,22 @@ fn success() { MIN_CONFIRMATIONS, ) .unwrap(); - assert!(test_fail_transfers_single( - &mut wallet, - online, - receive_data_1.batch_transfer_idx - )); - assert!(test_fail_transfers_single( - &mut wallet, - online, - receive_data_2.batch_transfer_idx - )); - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.fail_transfers_single(receive_data_1.batch_transfer_idx)); + assert!(party.fail_transfers_single(receive_data_2.batch_transfer_idx)); + assert!(party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::Failed )); - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::Failed )); - show_unspent_colorings(&mut wallet, "run 2 before delete"); - assert!(test_delete_transfers(&wallet, None, true)); - show_unspent_colorings(&mut wallet, "run 2 after delete"); - let txn = wallet.database().begin_transaction().unwrap(); - let transfers = txn.iter_transfers().unwrap(); - txn.commit().unwrap(); + party.show_unspent_colorings("run 2 before delete"); + assert!(party.delete_transfers(None, true)); + party.show_unspent_colorings("run 2 after delete"); + let transfers = party.db_transfers(); assert_eq!(transfers.len(), 2); - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::Failed )); @@ -284,17 +200,17 @@ fn batch_success() { let amount = 66; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet_1, _rcv_online_1) = get_funded_wallet!(); - let (mut rcv_wallet_2, _rcv_online_2) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party_1 = get_funded_party!(); + let mut rcv_party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); let asset_id = asset.asset_id; // failed transfer can be deleted - let receive_data_1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_2 = test_blind_receive(&mut rcv_wallet_2); + let receive_data_1 = rcv_party_1.blind_receive(); + let receive_data_2 = rcv_party_2.blind_receive(); let recipient_map = HashMap::from([( asset_id.clone(), vec![ @@ -312,21 +228,13 @@ fn batch_success() { }, ], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); assert!(!send_result.txid.is_empty()); - test_fail_transfers_single(&mut wallet, online, send_result.batch_transfer_idx); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_before = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + party.fail_transfers_single(send_result.batch_transfer_idx); + let batch_transfers_before = party.db_batch_transfers(); assert_eq!(batch_transfers_before.len(), 2); - assert!(test_delete_transfers( - &wallet, - Some(send_result.batch_transfer_idx), - false - )); - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers_after = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); + assert!(party.delete_transfers(Some(send_result.batch_transfer_idx), false)); + let batch_transfers_after = party.db_batch_transfers(); assert_eq!(batch_transfers_after.len(), 1); } @@ -336,33 +244,34 @@ fn batch_success() { fn fail() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); - let receive_data = test_blind_receive(&mut wallet); + let receive_data = party.blind_receive(); // don't delete transfer not in Failed status - assert!(!check_test_transfer_status_recipient( - &wallet, - &receive_data.recipient_id, - TransferStatus::Failed - )); - let result = - test_delete_transfers_result(&wallet, Some(receive_data.batch_transfer_idx), false); + assert!( + !party.check_test_transfer_status_recipient( + &receive_data.recipient_id, + TransferStatus::Failed + ) + ); + let result = party.delete_transfers_result(Some(receive_data.batch_transfer_idx), false); assert!(matches!(result, Err(Error::CannotDeleteBatchTransfer))); // don't delete unknown transfer - let result = test_delete_transfers_result(&wallet, Some(UNKNOWN_IDX), false); + let result = party.delete_transfers_result(Some(UNKNOWN_IDX), false); assert!(matches!( result, Err(Error::BatchTransferNotFound { idx }) if idx == UNKNOWN_IDX )); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); - show_unspent_colorings(&mut wallet, "after issuance"); + let asset = party.issue_asset_nia(None); + party.show_unspent_colorings("after issuance"); // don't delete failed transfer with asset_id if no_asset_only is true - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset.asset_id), Assignment::Any, @@ -371,7 +280,7 @@ fn fail() { MIN_CONFIRMATIONS, ) .unwrap(); - test_fail_transfers_all(&mut wallet, online); - let result = test_delete_transfers_result(&wallet, Some(receive_data.batch_transfer_idx), true); + party.fail_transfers_all(); + let result = party.delete_transfers_result(Some(receive_data.batch_transfer_idx), true); assert!(matches!(result, Err(Error::CannotDeleteBatchTransfer))); } diff --git a/src/wallet/test/drain_to.rs b/src/wallet/test/drain_to.rs index 5309964a..3da7aacb 100644 --- a/src/wallet/test/drain_to.rs +++ b/src/wallet/test/drain_to.rs @@ -7,10 +7,10 @@ fn success() { initialize(); // receiver wallet - let mut rcv_wallet = get_test_wallet(true, None); + let mut rcv_party = offline_party!(get_test_wallet(true, None)); // drain funded wallet with no allocation UTXOs - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); let expected_balance = BtcBalance { vanilla: Balance { settled: 100000000, @@ -23,24 +23,20 @@ fn success() { spendable: 0, }, }; - wait_for_btc_balance(&mut wallet, online, &expected_balance); - let address = test_get_address(&mut rcv_wallet); // also updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - test_drain_to(&mut wallet, online, &address); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + party.wait_for_btc_balance(&expected_balance); + let address = rcv_party.get_address(); // also updates backup_info + let bak_info_before = party.db_backup_info(); + party.drain_to(&address); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); mine(false); - wait_for_unspents(&mut wallet, Some(online), false, 0); + party.wait_for_unspents(false, 0); // issue asset (to produce an RGB allocation) - fund_wallet(test_get_address(&mut wallet)); - test_create_utxos_default(&mut wallet, online); + fund_wallet(party.get_address()); + party.create_utxos_default(); mine(false); - test_issue_asset_nia(&mut wallet, online, None); + party.issue_asset_nia(None); // drain funded wallet with RGB allocations let expected_balance = BtcBalance { @@ -55,10 +51,10 @@ fn success() { spendable: 5000, }, }; - wait_for_btc_balance(&mut wallet, online, &expected_balance); - test_drain_to(&mut wallet, online, &test_get_address(&mut rcv_wallet)); + party.wait_for_btc_balance(&expected_balance); + party.drain_to(&rcv_party.get_address()); mine(false); - wait_for_unspents(&mut wallet, Some(online), false, 0); + party.wait_for_unspents(false, 0); } #[cfg(feature = "electrum")] @@ -70,15 +66,15 @@ fn pending_witness_receive() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); - let (mut drain_wallet, _drain_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); + let mut drain_party = get_empty_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -91,28 +87,28 @@ fn pending_witness_receive() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // refresh receiver (no UTXOs created) + sender (to broadcast) + mine - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); // receiver sees the new UTXO - let unspents = list_test_unspents(&mut rcv_wallet, "before draining"); + let unspents = rcv_party.list_unspents(false); assert_eq!(unspents.len(), 7); assert_eq!(unspents.iter().filter(|u| !u.utxo.exists).count(), 1); // drain receiver, which syncs the wallet, detecting (and draining) the new UTXO as well - let address = test_get_address(&mut drain_wallet); - test_drain_to(&mut rcv_wallet, rcv_online, &address); - let unspents = list_test_unspents(&mut rcv_wallet, "after draining"); + let address = drain_party.get_address(); + rcv_party.drain_to(&address); + let unspents = rcv_party.list_unspents(false); assert_eq!(unspents.len(), 0); // refresh receiver, if draining hadn't synced (before draining) a new UTXO would appear - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let unspents = list_test_unspents(&mut rcv_wallet, "after receiver refresh 2"); + rcv_party.wait_for_refresh(None); + let unspents = rcv_party.list_unspents(false); assert_eq!(unspents.len(), 0); } @@ -123,40 +119,38 @@ fn drain_to_begin_and_end_success() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let mut rcv_wallet = get_test_wallet(true, None); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = offline_party!(get_test_wallet(true, None)); - let address = test_get_address(&mut rcv_wallet); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let address = rcv_party.get_address(); + let bak_info_before = party.db_backup_info(); // drain_to_begin does not update backup_info - let unsigned_psbt = wallet - .drain_to_begin(online, address, FEE_RATE, true) + let unsigned_psbt = party + .wallet + .drain_to_begin(party.online, address, FEE_RATE, true) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after_begin = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after_begin = party.db_backup_info(); assert_eq!( bak_info_after_begin.last_operation_timestamp, bak_info_before.last_operation_timestamp ); // sign and broadcast via drain_to_end - let signed_psbt = wallet.sign_psbt(unsigned_psbt, None).unwrap(); - let txid = wallet.drain_to_end(online, signed_psbt).unwrap(); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt, None).unwrap(); + let txid = party + .wallet + .drain_to_end(party.online, signed_psbt) + .unwrap(); assert!(!txid.is_empty()); // drain_to_end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after_end = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after_end = party.db_backup_info(); assert!(bak_info_after_end.last_operation_timestamp > bak_info_before.last_operation_timestamp); // verify the drain was effective mine(false); - wait_for_unspents(&mut wallet, Some(online), false, 0); + party.wait_for_unspents(false, 0); } #[cfg(feature = "electrum")] @@ -166,11 +160,11 @@ fn fail() { initialize(); // wallets - let (mut wallet, online) = get_empty_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_empty_party!(); + let mut rcv_party = get_empty_party!(); // drain empty wallet - let result = test_drain_to_result(&mut wallet, online, &test_get_address(&mut rcv_wallet)); + let result = party.drain_to_result(&rcv_party.get_address()); assert!(matches!( result, Err(Error::InsufficientBitcoins { @@ -180,33 +174,30 @@ fn fail() { )); // bad online object - fund_wallet(test_get_address(&mut wallet)); - let result = test_drain_to_result(&mut wallet, rcv_online, &test_get_address(&mut rcv_wallet)); + fund_wallet(party.get_address()); + let good_online = party.online; + party.online = rcv_party.online; + let result = party.drain_to_result(&rcv_party.get_address()); + party.online = good_online; assert!(matches!(result, Err(Error::CannotChangeOnline))); // bad address - let result = test_drain_to_result(&mut wallet, online, "invalid address"); + let result = party.drain_to_result("invalid address"); assert!(matches!(result, Err(Error::InvalidAddress { details: _ }))); // fee min - fund_wallet(test_get_address(&mut wallet)); - let result = - test_drain_to_begin_result(&mut wallet, online, &test_get_address(&mut rcv_wallet), 0); + fund_wallet(party.get_address()); + let result = party.drain_to_begin_result(&rcv_party.get_address(), 0); assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW)); // fee overflow - fund_wallet(test_get_address(&mut wallet)); - let result = test_drain_to_begin_result( - &mut wallet, - online, - &test_get_address(&mut rcv_wallet), - u64::MAX, - ); + fund_wallet(party.get_address()); + let result = party.drain_to_begin_result(&rcv_party.get_address(), u64::MAX); assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_OVER)); // no private keys - let (mut wallet, online) = get_funded_noutxo_wallet(false, None); - let result = test_drain_to_result(&mut wallet, online, &test_get_address(&mut rcv_wallet)); + let mut wo_party = get_funded_noutxo_party(false, None); + let result = wo_party.drain_to_result(&rcv_party.get_address()); assert!(matches!(result, Err(Error::WatchOnly))); } @@ -217,13 +208,14 @@ fn reservation_interaction() { initialize(); // wallet with several vanilla UTXOs so they can be reserved - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); for _ in 0..3 { - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); } - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -233,18 +225,19 @@ fn reservation_interaction() { ) .unwrap(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); - let (mut drain_wallet, _drain_online) = get_empty_wallet!(); + let mut rcv_party = get_empty_party!(); + let mut drain_party = get_empty_party!(); // reserve all vanilla UTXO via drain_to_begin(dry_run=false) - let psbt = wallet - .drain_to_begin(online, test_get_address(&mut rcv_wallet), FEE_RATE, false) + let psbt = party + .wallet + .drain_to_begin(party.online, rcv_party.get_address(), FEE_RATE, false) .unwrap(); // check send_btc cannot spend the reserved UTXOs - let res = wallet.send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + let res = party.wallet.send_btc_begin( + party.online, + rcv_party.get_address(), 1000, FEE_RATE, true, @@ -260,13 +253,14 @@ fn reservation_interaction() { // cancel pending drain_to to unlock the reserved inputs let txid = Psbt::from_str(&psbt).unwrap().get_txid().to_string(); - wallet.abort_pending_vanilla_tx(txid).unwrap(); + party.wallet.abort_pending_vanilla_tx(txid).unwrap(); // reserve one (or more) vanilla UTXO via send_btc_begin(dry_run=false) - let send_psbt_str = wallet + let send_psbt_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), 1000, FEE_RATE, true, @@ -284,8 +278,9 @@ fn reservation_interaction() { // drain always spends all wallet UTXOs, including those reserved by in-flight vanilla // transactions - let drain_psbt_str = wallet - .drain_to_begin(online, test_get_address(&mut drain_wallet), FEE_RATE, true) + let drain_psbt_str = party + .wallet + .drain_to_begin(party.online, drain_party.get_address(), FEE_RATE, true) .unwrap(); let drain_psbt = Psbt::from_str(&drain_psbt_str).unwrap(); let drain_inputs: HashSet<(String, u32)> = drain_psbt @@ -308,45 +303,38 @@ fn reservation_interaction() { fn begin_end() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let address = test_get_address(&mut wallet); + let mut party = get_funded_noutxo_party!(); + let address = party.get_address(); // begin does not update backup_info with dry_run=true - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let _psbt = wallet - .drain_to_begin(online, address.clone(), FEE_RATE, true) + let bak_info_before = party.db_backup_info(); + let _psbt = party + .wallet + .drain_to_begin(party.online, address.clone(), FEE_RATE, true) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_before.last_operation_timestamp, bak_info_after.last_operation_timestamp ); // begin does update backup_info with dry_run=false - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let psbt = wallet - .drain_to_begin(online, address, FEE_RATE, false) + let bak_info_before = party.db_backup_info(); + let psbt = party + .wallet + .drain_to_begin(party.online, address, FEE_RATE, false) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let signed_psbt = wallet.sign_psbt(psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(psbt, None).unwrap(); // end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.drain_to_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party + .wallet + .drain_to_end(party.online, signed_psbt) + .unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); } diff --git a/src/wallet/test/fail_transfers.rs b/src/wallet/test/fail_transfers.rs index e6d6e686..1f01ae0e 100644 --- a/src/wallet/test/fail_transfers.rs +++ b/src/wallet/test/fail_transfers.rs @@ -9,57 +9,39 @@ fn success() { let amount = 66; let expiration_secs: u64 = 1; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // return false if no transfer has changed - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - assert!(!test_fail_transfers_all(&mut wallet, online)); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + assert!(!party.fail_transfers_all()); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // fail single transfer - let receive_data = test_blind_receive(&mut rcv_wallet); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + let receive_data = rcv_party.blind_receive(); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data.recipient_id, TransferStatus::WaitingCounterparty )); - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - assert!(test_fail_transfers_single( - &mut rcv_wallet, - rcv_online, - receive_data.batch_transfer_idx - )); - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = rcv_party.db_backup_info(); + assert!(rcv_party.fail_transfers_single(receive_data.batch_transfer_idx)); + let bak_info_after = rcv_party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // fail all expired WaitingCounterparty transfers - let receive_data_1 = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + expiration_secs as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); - let receive_data_2 = test_blind_receive(&mut rcv_wallet); - let receive_data_3 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive_asset_expiry( + None, + Some((now().unix_timestamp() + expiration_secs as i64) as u64), + ); + let receive_data_2 = rcv_party.blind_receive(); + let receive_data_3 = rcv_party.blind_receive(); // wait for expiration to be in the past std::thread::sleep(std::time::Duration::from_millis( expiration_secs * 1000 + 2000, @@ -73,74 +55,58 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); let _guard = stop_mining(); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - show_unspent_colorings(&mut rcv_wallet, "receiver run 1 after refresh 1"); - show_unspent_colorings(&mut wallet, "sender run 1 no refresh"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + rcv_party.wait_for_refresh(None); + rcv_party.show_unspent_colorings("receiver run 1 after refresh 1"); + party.show_unspent_colorings("sender run 1 no refresh"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(test_fail_transfers_all(&mut rcv_wallet, rcv_online)); - show_unspent_colorings(&mut rcv_wallet, "receiver run 1 after fail"); - show_unspent_colorings(&mut wallet, "sender run 1 after fail"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.fail_transfers_all()); + rcv_party.show_unspent_colorings("receiver run 1 after fail"); + party.show_unspent_colorings("sender run 1 after fail"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::Failed )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); // progress transfer to Settled - wait_for_refresh(&mut wallet, online, None, None); + party.wait_for_refresh(None); drop(_guard); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // fail all expired WaitingCounterparty transfers with no asset_id - let receive_data_1 = test_blind_receive(&mut rcv_wallet); - let receive_data_2 = rcv_wallet - .blind_receive( - Some(asset.asset_id.clone()), - Assignment::Any, - Some((now().unix_timestamp() + expiration_secs as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); - let receive_data_3 = test_blind_receive(&mut rcv_wallet); - let receive_data_4 = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + expiration_secs as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data_1 = rcv_party.blind_receive(); + let receive_data_2 = rcv_party.blind_receive_asset_expiry( + Some(asset.asset_id.clone()), + Some((now().unix_timestamp() + expiration_secs as i64) as u64), + ); + let receive_data_3 = rcv_party.blind_receive(); + let receive_data_4 = rcv_party.blind_receive_asset_expiry( + None, + Some((now().unix_timestamp() + expiration_secs as i64) as u64), + ); // wait for expiration to be in the past std::thread::sleep(std::time::Duration::from_millis( expiration_secs * 1000 + 2000, @@ -155,54 +121,44 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); + rcv_party.wait_for_refresh(None); - show_unspent_colorings(&mut rcv_wallet, "receiver run 2 after refresh 1"); - show_unspent_colorings(&mut wallet, "sender run 2 no refresh"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + rcv_party.show_unspent_colorings("receiver run 2 after refresh 1"); + party.show_unspent_colorings("sender run 2 no refresh"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_4.recipient_id, TransferStatus::WaitingCounterparty )); - rcv_wallet - .fail_transfers(rcv_online, None, true, false) - .unwrap(); - show_unspent_colorings(&mut rcv_wallet, "receiver run 2 after fail"); - show_unspent_colorings(&mut wallet, "sender run 2 after fail"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + rcv_party.fail_transfers(None, true, false).unwrap(); + rcv_party.show_unspent_colorings("receiver run 2 after fail"); + party.show_unspent_colorings("sender run 2 after fail"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_4.recipient_id, TransferStatus::Failed )); @@ -216,17 +172,17 @@ fn batch_success() { let amount = 66; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet_1, rcv_online_1) = get_funded_wallet!(); - let (mut rcv_wallet_2, _rcv_online_2) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party_1 = get_funded_party!(); + let mut rcv_party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); let asset_id = asset.asset_id; // transfer is in WaitingCounterparty status and can be failed - let receive_data_1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_2 = test_blind_receive(&mut rcv_wallet_2); + let receive_data_1 = rcv_party_1.blind_receive(); + let receive_data_2 = rcv_party_2.blind_receive(); let recipient_map = HashMap::from([( asset_id.clone(), vec![ @@ -244,31 +200,25 @@ fn batch_success() { }, ], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); let txid = send_result.txid; assert!(!txid.is_empty()); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_1, + assert!(rcv_party_1.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_2, + assert!(rcv_party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::WaitingCounterparty - )); - wallet - .fail_transfers(online, Some(send_result.batch_transfer_idx), false, false) + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::WaitingCounterparty)); + party + .fail_transfers(Some(send_result.batch_transfer_idx), false, false) .unwrap(); // transfer is still in WaitingCounterparty status after some recipients (but not all) replied with an ACK - let receive_data_1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_2 = test_blind_receive(&mut rcv_wallet_2); + let receive_data_1 = rcv_party_1.blind_receive(); + let receive_data_2 = rcv_party_2.blind_receive(); let recipient_map = HashMap::from([( asset_id, vec![ @@ -286,27 +236,21 @@ fn batch_success() { }, ], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); let txid = send_result.txid; assert!(!txid.is_empty()); - wait_for_refresh(&mut rcv_wallet_1, rcv_online_1, None, None); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_1, + rcv_party_1.wait_for_refresh(None); + assert!(rcv_party_1.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_2, + assert!(rcv_party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::WaitingCounterparty - )); - wallet - .fail_transfers(online, Some(send_result.batch_transfer_idx), false, false) + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::WaitingCounterparty)); + party + .fail_transfers(Some(send_result.batch_transfer_idx), false, false) .unwrap(); } @@ -317,15 +261,16 @@ fn fail() { initialize(); // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); let asset_id = asset.asset_id.clone(); // don't fail transfer with asset_id if no_asset_only is true - let receive_data = wallet + let receive_data = party + .wallet .blind_receive( Some(asset.asset_id), Assignment::Any, @@ -334,19 +279,18 @@ fn fail() { MIN_CONFIRMATIONS, ) .unwrap(); - let result = wallet.fail_transfers(online, Some(receive_data.batch_transfer_idx), true, false); + let result = party.fail_transfers(Some(receive_data.batch_transfer_idx), true, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.check_test_transfer_status_recipient( &receive_data.recipient_id, TransferStatus::WaitingCounterparty )); // fail pending transfer - let result = wallet.fail_transfers(online, Some(receive_data.batch_transfer_idx), false, false); + let result = party.fail_transfers(Some(receive_data.batch_transfer_idx), false, false); assert!(result.is_ok()); - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_id = receive_data.recipient_id; let batch_transfer_idx = receive_data.batch_transfer_idx; let recipient_map = HashMap::from([( @@ -358,85 +302,83 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); // check starting transfer status - assert!(check_test_transfer_status_recipient( - &rcv_wallet, - &recipient_id, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet, - &recipient_id, - TransferStatus::WaitingCounterparty - )); + assert!( + rcv_party.check_test_transfer_status_recipient( + &recipient_id, + TransferStatus::WaitingCounterparty + ) + ); + assert!( + party.check_test_transfer_status_recipient( + &recipient_id, + TransferStatus::WaitingCounterparty + ) + ); let _guard = stop_mining(); // don't fail unknown idx - let result = rcv_wallet.fail_transfers(rcv_online, Some(UNKNOWN_IDX), false, false); + let result = rcv_party.fail_transfers(Some(UNKNOWN_IDX), false, false); assert!(matches!( result, Err(Error::BatchTransferNotFound { idx }) if idx == UNKNOWN_IDX )); // don't fail incoming transfer: waiting counterparty -> confirmations - let result = rcv_wallet.fail_transfers(rcv_online, Some(batch_transfer_idx), false, false); + let result = rcv_party.fail_transfers(Some(batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, - &recipient_id, - TransferStatus::WaitingConfirmations - )); + assert!( + rcv_party.check_test_transfer_status_recipient( + &recipient_id, + TransferStatus::WaitingConfirmations + ) + ); // don't fail outgoing transfer: waiting counterparty -> confirmations - let result = wallet.fail_transfers(online, Some(send_result.batch_transfer_idx), false, false); + let result = party.fail_transfers(Some(send_result.batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &wallet, - &recipient_id, - TransferStatus::WaitingConfirmations - )); + assert!( + party.check_test_transfer_status_recipient( + &recipient_id, + TransferStatus::WaitingConfirmations + ) + ); // don't fail incoming transfer: waiting confirmations - let result = rcv_wallet.fail_transfers(rcv_online, Some(batch_transfer_idx), false, false); + let result = rcv_party.fail_transfers(Some(batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, - &recipient_id, - TransferStatus::WaitingConfirmations - )); + assert!( + rcv_party.check_test_transfer_status_recipient( + &recipient_id, + TransferStatus::WaitingConfirmations + ) + ); // don't fail outgoing transfer: waiting confirmations - let result = wallet.fail_transfers(online, Some(send_result.batch_transfer_idx), false, false); + let result = party.fail_transfers(Some(send_result.batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &wallet, - &recipient_id, - TransferStatus::WaitingConfirmations - )); + assert!( + party.check_test_transfer_status_recipient( + &recipient_id, + TransferStatus::WaitingConfirmations + ) + ); // mine and refresh so transfers can settle drop(_guard); mine(false); - wait_for_refresh(&mut wallet, online, Some(&asset_id), None); - wait_for_refresh(&mut rcv_wallet, rcv_online, Some(&asset_id), None); + party.wait_for_refresh(Some(&asset_id)); + rcv_party.wait_for_refresh(Some(&asset_id)); // don't fail incoming transfer: settled - let result = rcv_wallet.fail_transfers(rcv_online, Some(batch_transfer_idx), false, false); + let result = rcv_party.fail_transfers(Some(batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, - &recipient_id, - TransferStatus::Settled - )); + assert!(rcv_party.check_test_transfer_status_recipient(&recipient_id, TransferStatus::Settled)); // don't fail outgoing transfer: settled - let result = wallet.fail_transfers(online, Some(send_result.batch_transfer_idx), false, false); + let result = party.fail_transfers(Some(send_result.batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); - assert!(check_test_transfer_status_recipient( - &wallet, - &recipient_id, - TransferStatus::Settled - )); + assert!(party.check_test_transfer_status_recipient(&recipient_id, TransferStatus::Settled)); } #[cfg(feature = "electrum")] @@ -447,17 +389,17 @@ fn batch_fail() { let amount = 66; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet_1, _rcv_online_1) = get_funded_wallet!(); - let (mut rcv_wallet_2, _rcv_online_2) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party_1 = get_funded_party!(); + let mut rcv_party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT, AMOUNT * 2, AMOUNT * 3])); + let asset = party.issue_asset_nia(Some(&[AMOUNT, AMOUNT * 2, AMOUNT * 3])); let asset_id = asset.asset_id; // batch send as donation (doesn't wait for recipient confirmations) - let receive_data_1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_2 = test_blind_receive(&mut rcv_wallet_2); + let receive_data_1 = rcv_party_1.blind_receive(); + let receive_data_2 = rcv_party_2.blind_receive(); let recipient_map = HashMap::from([( asset_id, vec![ @@ -475,9 +417,10 @@ fn batch_fail() { }, ], )]); - wallet + party + .wallet .send( - online, + party.online, recipient_map, true, FEE_RATE, @@ -487,17 +430,11 @@ fn batch_fail() { .unwrap(); // transfer is in WaitingConfirmations status and cannot be failed - assert!(check_test_transfer_status_recipient( - &wallet, + assert!(party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingConfirmations )); - let result = wallet.fail_transfers( - online, - Some(receive_data_2.batch_transfer_idx), - false, - false, - ); + let result = party.fail_transfers(Some(receive_data_2.batch_transfer_idx), false, false); assert!(matches!(result, Err(Error::CannotFailBatchTransfer))); } @@ -510,42 +447,31 @@ fn skip_sync() { let amount = 66; let expiration_secs: u64 = 1; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // fail single transfer skipping sync - let receive_data = test_blind_receive(&mut rcv_wallet); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + let receive_data = rcv_party.blind_receive(); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data.recipient_id, TransferStatus::WaitingCounterparty )); assert!( - rcv_wallet - .fail_transfers( - rcv_online, - Some(receive_data.batch_transfer_idx), - false, - true - ) + rcv_party + .fail_transfers(Some(receive_data.batch_transfer_idx), false, true) .unwrap() ); // fail all expired WaitingCounterparty transfers - let receive_data_1 = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + expiration_secs as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); - let receive_data_2 = test_blind_receive(&mut rcv_wallet); - let receive_data_3 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive_asset_expiry( + None, + Some((now().unix_timestamp() + expiration_secs as i64) as u64), + ); + let receive_data_2 = rcv_party.blind_receive(); + let receive_data_3 = rcv_party.blind_receive(); // wait for expiration to be in the past std::thread::sleep(std::time::Duration::from_millis( expiration_secs * 1000 + 2000, @@ -559,78 +485,58 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); let _guard = stop_mining(); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - show_unspent_colorings(&mut rcv_wallet, "receiver run 1 after refresh 1"); - show_unspent_colorings(&mut wallet, "sender run 1 no refresh"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + rcv_party.wait_for_refresh(None); + rcv_party.show_unspent_colorings("receiver run 1 after refresh 1"); + party.show_unspent_colorings("sender run 1 no refresh"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); - assert!( - rcv_wallet - .fail_transfers(rcv_online, None, false, true) - .unwrap() - ); - show_unspent_colorings(&mut rcv_wallet, "receiver run 1 after fail"); - show_unspent_colorings(&mut wallet, "sender run 1 after fail"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.fail_transfers(None, false, true).unwrap()); + rcv_party.show_unspent_colorings("receiver run 1 after fail"); + party.show_unspent_colorings("sender run 1 after fail"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::Failed )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); // progress transfer to Settled - wait_for_refresh(&mut wallet, online, None, None); + party.wait_for_refresh(None); drop(_guard); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // fail all expired WaitingCounterparty transfers with no asset_id - let receive_data_1 = test_blind_receive(&mut rcv_wallet); - let receive_data_2 = rcv_wallet - .blind_receive( - Some(asset.asset_id.clone()), - Assignment::Any, - Some((now().unix_timestamp() + expiration_secs as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); - let receive_data_3 = test_blind_receive(&mut rcv_wallet); - let receive_data_4 = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + expiration_secs as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data_1 = rcv_party.blind_receive(); + let receive_data_2 = rcv_party.blind_receive_asset_expiry( + Some(asset.asset_id.clone()), + Some((now().unix_timestamp() + expiration_secs as i64) as u64), + ); + let receive_data_3 = rcv_party.blind_receive(); + let receive_data_4 = rcv_party.blind_receive_asset_expiry( + None, + Some((now().unix_timestamp() + expiration_secs as i64) as u64), + ); // wait for expiration to be in the past std::thread::sleep(std::time::Duration::from_millis( expiration_secs * 1000 + 2000, @@ -645,54 +551,44 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); + rcv_party.wait_for_refresh(None); - show_unspent_colorings(&mut rcv_wallet, "receiver run 2 after refresh 1"); - show_unspent_colorings(&mut wallet, "sender run 2 no refresh"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + rcv_party.show_unspent_colorings("receiver run 2 after refresh 1"); + party.show_unspent_colorings("sender run 2 no refresh"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_4.recipient_id, TransferStatus::WaitingCounterparty )); - rcv_wallet - .fail_transfers(rcv_online, None, true, true) - .unwrap(); - show_unspent_colorings(&mut rcv_wallet, "receiver run 2 after fail"); - show_unspent_colorings(&mut wallet, "sender run 2 after fail"); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + rcv_party.fail_transfers(None, true, true).unwrap(); + rcv_party.show_unspent_colorings("receiver run 2 after fail"); + party.show_unspent_colorings("sender run 2 after fail"); + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_3.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data_4.recipient_id, TransferStatus::Failed )); @@ -708,14 +604,14 @@ fn waiting_safe_height() { let amount_2: u64 = 33; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // 1st transfer: wallet 1 > wallet 2 - let receive_data_1 = test_blind_receive(&mut wallet_2); + let receive_data_1 = party_2.blind_receive(); let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -725,23 +621,23 @@ fn waiting_safe_height() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map_1); + let txid_1 = party_1.send_retry(&recipient_map_1); assert!(!txid_1.is_empty()); let _guard = stop_mining_when_alone(); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); force_mine_no_resume_when_alone(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::Settled )); // 2nd transfer: wallet 1 > wallet 2 with min_confirmations = 2 // txid_1 has only one confirmation, so transfer parks in WaitingSafeHeight - let receive_data_2 = wallet_2 + let receive_data_2 = party_2 + .wallet .blind_receive( None, Assignment::Any, @@ -759,30 +655,19 @@ fn waiting_safe_height() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_1, online_1, &recipient_map_2); + let txid_2 = party_1.send_retry(&recipient_map_2); assert!(!txid_2.is_empty()); // transfer parks in WaitingSafeHeight because it contains unsafe history - wait_for_refresh( - &mut wallet_2, - online_2, - None, - Some(&[receive_data_2.batch_transfer_idx]), - ); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_2.wait_for_refresh_raw(None, Some(&[receive_data_2.batch_transfer_idx])); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingSafeHeight )); // fail the receive transfer in WaitingSafeHeight - assert!(test_fail_transfers_single( - &mut wallet_2, - online_2, - receive_data_2.batch_transfer_idx - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.fail_transfers_single(receive_data_2.batch_transfer_idx)); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::Failed )); diff --git a/src/wallet/test/finalize_psbt.rs b/src/wallet/test/finalize_psbt.rs index 0801cb43..a3ca2b40 100644 --- a/src/wallet/test/finalize_psbt.rs +++ b/src/wallet/test/finalize_psbt.rs @@ -5,13 +5,17 @@ use super::*; #[parallel] fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let address = test_get_address(&mut wallet); - let unsigned_psbt_str = wallet - .send_btc_begin(online, address, AMOUNT, FEE_RATE, false, true) + let mut party = get_funded_party!(); + let address = party.get_address(); + let unsigned_psbt_str = party + .wallet + .send_btc_begin(party.online, address, AMOUNT, FEE_RATE, false, true) .unwrap(); - let signed_psbt = wallet.sign_psbt(unsigned_psbt_str.clone(), None).unwrap(); - let finalized_psbt = wallet.finalize_psbt(signed_psbt, None); + let signed_psbt = party + .wallet + .sign_psbt(unsigned_psbt_str.clone(), None) + .unwrap(); + let finalized_psbt = party.wallet.finalize_psbt(signed_psbt, None); assert!(finalized_psbt.is_ok()); } @@ -20,13 +24,14 @@ fn success() { #[parallel] fn fail() { initialize(); - let (mut wallet_1, online) = get_funded_wallet!(); - let result = wallet_1.finalize_psbt("rgb1invalid".to_string(), None); + let mut party = get_funded_party!(); + let result = party.wallet.finalize_psbt("rgb1invalid".to_string(), None); assert_matches!(result, Err(Error::InvalidPsbt { details: _ })); - let address = test_get_address(&mut wallet_1); - let unsigned_psbt_str = wallet_1 - .send_btc_begin(online, address, AMOUNT, FEE_RATE, false, true) + let address = party.get_address(); + let unsigned_psbt_str = party + .wallet + .send_btc_begin(party.online, address, AMOUNT, FEE_RATE, false, true) .unwrap(); let wallet_2 = get_test_wallet(true, None); let result = wallet_2.finalize_psbt(unsigned_psbt_str, None); diff --git a/src/wallet/test/get_address.rs b/src/wallet/test/get_address.rs index 6c0462cc..3c464366 100644 --- a/src/wallet/test/get_address.rs +++ b/src/wallet/test/get_address.rs @@ -3,19 +3,13 @@ use super::*; #[test] #[parallel] fn success() { - let mut wallet = get_test_wallet(false, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let mut party = offline_party!(get_test_wallet(false, None)); + let bak_info_before = party.db_backup_info_opt(); assert!(bak_info_before.is_none()); - let address = test_get_address(&mut wallet); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); - assert!(bak_info_after.is_some()); + let address = party.get_address(); + let bak_info_after = party.db_backup_info(); assert!( bak_info_after - .unwrap() .last_operation_timestamp .parse::() .unwrap() diff --git a/src/wallet/test/get_asset_balance.rs b/src/wallet/test/get_asset_balance.rs index 126ecd58..59eb8253 100644 --- a/src/wallet/test/get_asset_balance.rs +++ b/src/wallet/test/get_asset_balance.rs @@ -6,19 +6,15 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // issue an NIA asset - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // balances after issuance - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let asset_balance = test_get_asset_balance(&wallet, &asset.asset_id); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let asset_balance = party.get_asset_balance(&asset.asset_id); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -33,10 +29,10 @@ fn success() { ); // issue an CFA asset - let asset = test_issue_asset_cfa(&mut wallet, online, None, None); + let asset = party.issue_asset_cfa(None, None); // balances after issuance - let asset_balance = test_get_asset_balance(&wallet, &asset.asset_id); + let asset_balance = party.get_asset_balance(&asset.asset_id); assert_eq!( asset_balance, Balance { @@ -58,55 +54,22 @@ fn transfer_balances() { let amount_3: u64 = 11; // sender wallet with 3 UTXOs (both assets issued to the same UTXOs) - let (mut wallet_send, online_send) = get_funded_noutxo_wallet!(); - test_create_utxos( - &mut wallet_send, - online_send, - true, - Some(3), - None, - FEE_RATE, - None, - ); // recipient wallet with a single UTXO - let (mut wallet_recv, online_recv) = get_funded_noutxo_wallet!(); - test_create_utxos( - &mut wallet_recv, - online_recv, - true, - Some(1), - None, - FEE_RATE, - None, - ); + let mut send_party = get_funded_noutxo_party!(); + send_party.create_utxos(true, Some(3), None, FEE_RATE, None); + let mut recv_party = get_funded_noutxo_party!(); + recv_party.create_utxos(true, Some(1), None, FEE_RATE, None); // issue - let asset_1 = test_issue_asset_nia( - &mut wallet_send, - online_send, - Some(&[AMOUNT, AMOUNT, AMOUNT]), - ); - let asset_2 = test_issue_asset_cfa( - &mut wallet_send, - online_send, - Some(&[AMOUNT, AMOUNT, AMOUNT]), - None, - ); + let asset_1 = send_party.issue_asset_nia(Some(&[AMOUNT, AMOUNT, AMOUNT])); + let asset_2 = send_party.issue_asset_cfa(Some(&[AMOUNT, AMOUNT, AMOUNT]), None); // create 2 more UTXOs on the sender wallet - test_create_utxos( - &mut wallet_send, - online_send, - false, - Some(2), - None, - FEE_RATE, - None, - ); + send_party.create_utxos(false, Some(2), None, FEE_RATE, None); // balances after issuance - show_unspent_colorings(&mut wallet_send, "send after issuance"); - show_unspent_colorings(&mut wallet_recv, "recv after issuance"); + send_party.show_unspent_colorings("send after issuance"); + recv_party.show_unspent_colorings("recv after issuance"); let expected_balance_1 = Balance { settled: AMOUNT * 3, future: AMOUNT * 3, @@ -117,11 +80,11 @@ fn transfer_balances() { future: AMOUNT * 3, spendable: AMOUNT * 3, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance_1); - wait_for_asset_balance(&wallet_send, &asset_2.asset_id, &expected_balance_2); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); + send_party.wait_for_asset_balance(&asset_2.asset_id, &expected_balance_2); // receiver side after issuance (no asset yet) - let result_1 = test_get_asset_balance_result(&wallet_recv, &asset_1.asset_id); - let result_2 = test_get_asset_balance_result(&wallet_recv, &asset_2.asset_id); + let result_1 = recv_party.get_asset_balance_result(&asset_1.asset_id); + let result_2 = recv_party.get_asset_balance_result(&asset_2.asset_id); assert!(matches!( result_1, Err(Error::AssetNotFound { asset_id: _ }) @@ -135,12 +98,8 @@ fn transfer_balances() { // blind + fail to check failed blinds are not counted in balance // - let receive_data_fail = test_blind_receive(&mut wallet_recv); - test_fail_transfers_single( - &mut wallet_recv, - online_recv, - receive_data_fail.batch_transfer_idx, - ); + let receive_data_fail = recv_party.blind_receive(); + recv_party.fail_transfers_single(receive_data_fail.batch_transfer_idx); // // send + fail to check failed inputs + changes are not counted in balance @@ -156,11 +115,12 @@ fn transfer_balances() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let batch_transfer_idx = test_send_result(&mut wallet_send, online_send, &recipient_map) + let batch_transfer_idx = send_party + .send_result(&recipient_map) .unwrap() .batch_transfer_idx; // sender balances after send / before fail - show_unspent_colorings(&mut wallet_send, "send after send / before fail"); + send_party.show_unspent_colorings("send after send / before fail"); let expected_balance_1 = Balance { settled: AMOUNT * 3, future: AMOUNT * 3 - amount_1, @@ -171,12 +131,12 @@ fn transfer_balances() { future: AMOUNT * 3, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance_1); - wait_for_asset_balance(&wallet_send, &asset_2.asset_id, &expected_balance_2); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); + send_party.wait_for_asset_balance(&asset_2.asset_id, &expected_balance_2); // fail the transfer - test_fail_transfers_single(&mut wallet_send, online_send, batch_transfer_idx); + send_party.fail_transfers_single(batch_transfer_idx); // sender balances after fail - show_unspent_colorings(&mut wallet_send, "send after fail"); + send_party.show_unspent_colorings("send after fail"); let expected_balance_1 = Balance { settled: AMOUNT * 3, future: AMOUNT * 3, @@ -187,15 +147,15 @@ fn transfer_balances() { future: AMOUNT * 3, spendable: AMOUNT * 3, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance_1); - wait_for_asset_balance(&wallet_send, &asset_2.asset_id, &expected_balance_2); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); + send_party.wait_for_asset_balance(&asset_2.asset_id, &expected_balance_2); // // a 1st transfer (blinded) // // send - let receive_data_1 = test_blind_receive(&mut wallet_recv); + let receive_data_1 = recv_party.blind_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -205,11 +165,11 @@ fn transfer_balances() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - test_send(&mut wallet_send, online_send, &recipient_map); + send_party.send_retry(&recipient_map); // sender balance with transfer WaitingCounterparty (recipient doesn't know the asset yet) - show_unspent_colorings(&mut wallet_send, "send after 1st send"); - show_unspent_colorings(&mut wallet_recv, "recv after 1st send"); - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + send_party.show_unspent_colorings("send after 1st send"); + recv_party.show_unspent_colorings("recv after 1st send"); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.len(), 3); assert_eq!( transfers.last().unwrap().status, @@ -225,9 +185,9 @@ fn transfer_balances() { future: AMOUNT * 3, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance_1); - wait_for_asset_balance(&wallet_send, &asset_2.asset_id, &expected_balance_2); - let transfers_recv = test_list_transfers(&wallet_recv, None); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); + send_party.wait_for_asset_balance(&asset_2.asset_id, &expected_balance_2); + let transfers_recv = recv_party.list_transfers(None); assert_eq!(transfers_recv.len(), 2); assert_eq!( transfers_recv.last().unwrap().status, @@ -235,7 +195,7 @@ fn transfer_balances() { ); // asset_2 (extra) allocation should be recognized as unspendable - let receive_data_fail = test_blind_receive(&mut wallet_recv); + let receive_data_fail = recv_party.blind_receive(); let recipient_map_fail = HashMap::from([( asset_2.asset_id.clone(), vec![Recipient { @@ -245,7 +205,7 @@ fn transfer_balances() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet_send, online_send, &recipient_map_fail); + let result = send_party.send_begin_result(&recipient_map_fail); let assignments_collection = AssignmentsCollection { fungible: 1332, non_fungible: false, @@ -253,30 +213,16 @@ fn transfer_balances() { }; assert_matches!(result, Err(Error::InsufficientAssignments { asset_id, available }) if asset_id == asset_2.asset_id && available == assignments_collection ); // fail + delete blind receive - test_fail_transfers_single( - &mut wallet_recv, - online_recv, - receive_data_fail.batch_transfer_idx, - ); - test_delete_transfers( - &wallet_recv, - Some(receive_data_fail.batch_transfer_idx), - false, - ); + recv_party.fail_transfers_single(receive_data_fail.batch_transfer_idx); + recv_party.delete_transfers(Some(receive_data_fail.batch_transfer_idx), false); // take transfers from WaitingCounterparty to WaitingConfirmations - wait_for_refresh(&mut wallet_recv, online_recv, None, None); - wait_for_refresh(&mut wallet_send, online_send, Some(&asset_1.asset_id), None); + recv_party.wait_for_refresh(None); + send_party.wait_for_refresh(Some(&asset_1.asset_id)); // balances with transfer WaitingConfirmations - show_unspent_colorings( - &mut wallet_send, - "send after 1st send, WaitingConfirmations", - ); - show_unspent_colorings( - &mut wallet_recv, - "recv after 1st send, WaitingConfirmations", - ); - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + send_party.show_unspent_colorings("send after 1st send, WaitingConfirmations"); + recv_party.show_unspent_colorings("recv after 1st send, WaitingConfirmations"); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!( transfers.last().unwrap().status, TransferStatus::WaitingConfirmations @@ -291,9 +237,9 @@ fn transfer_balances() { future: AMOUNT * 3, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance_1); - wait_for_asset_balance(&wallet_send, &asset_2.asset_id, &expected_balance_2); - let transfers_recv = test_list_transfers(&wallet_recv, Some(&asset_1.asset_id)); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); + send_party.wait_for_asset_balance(&asset_2.asset_id, &expected_balance_2); + let transfers_recv = recv_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers_recv.len(), 1); assert_eq!( transfers_recv.last().unwrap().status, @@ -304,16 +250,16 @@ fn transfer_balances() { future: amount_1, spendable: 0, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance_1); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); // take transfers from WaitingConfirmations to Settled mine(false); - wait_for_refresh(&mut wallet_recv, online_recv, Some(&asset_1.asset_id), None); - wait_for_refresh(&mut wallet_send, online_send, Some(&asset_1.asset_id), None); + recv_party.wait_for_refresh(Some(&asset_1.asset_id)); + send_party.wait_for_refresh(Some(&asset_1.asset_id)); // balances with transfer Settled - show_unspent_colorings(&mut wallet_send, "send after 1st send, settled"); - show_unspent_colorings(&mut wallet_recv, "recv after 1st send, settled"); - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + send_party.show_unspent_colorings("send after 1st send, settled"); + recv_party.show_unspent_colorings("recv after 1st send, settled"); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.last().unwrap().status, TransferStatus::Settled); let expected_balance_1 = Balance { settled: AMOUNT * 3 - amount_1, @@ -325,9 +271,9 @@ fn transfer_balances() { future: AMOUNT * 3, spendable: AMOUNT * 3, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance_1); - wait_for_asset_balance(&wallet_send, &asset_2.asset_id, &expected_balance_2); - let transfers_recv = test_list_transfers(&wallet_recv, Some(&asset_1.asset_id)); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); + send_party.wait_for_asset_balance(&asset_2.asset_id, &expected_balance_2); + let transfers_recv = recv_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!( transfers_recv.last().unwrap().status, TransferStatus::Settled @@ -337,14 +283,14 @@ fn transfer_balances() { future: amount_1, spendable: amount_1, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance_1); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance_1); // // a 2nd transfer (blinded) // // send some assets - let receive_data_2 = test_blind_receive(&mut wallet_recv); + let receive_data_2 = recv_party.blind_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -354,13 +300,13 @@ fn transfer_balances() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - test_send(&mut wallet_send, online_send, &recipient_map); + send_party.send_retry(&recipient_map); - show_unspent_colorings(&mut wallet_send, "send after 2nd send"); - show_unspent_colorings(&mut wallet_recv, "recv after 2nd send"); + send_party.show_unspent_colorings("send after 2nd send"); + recv_party.show_unspent_colorings("recv after 2nd send"); // balances with transfer WaitingCounterparty - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.len(), 4); assert_eq!( transfers.last().unwrap().status, @@ -371,8 +317,8 @@ fn transfer_balances() { future: AMOUNT * 3 - amount_1 - amount_2, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance); - let transfers = test_list_transfers(&wallet_recv, None); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); + let transfers = recv_party.list_transfers(None); assert_eq!(transfers.len(), 2); assert_eq!( transfers.last().unwrap().status, @@ -383,14 +329,14 @@ fn transfer_balances() { future: amount_1, spendable: 0, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); // take transfers from WaitingCounterparty to WaitingConfirmations - wait_for_refresh(&mut wallet_recv, online_recv, None, None); - wait_for_refresh(&mut wallet_send, online_send, Some(&asset_1.asset_id), None); + recv_party.wait_for_refresh(None); + send_party.wait_for_refresh(Some(&asset_1.asset_id)); // balances with transfer WaitingConfirmations - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!( transfers.last().unwrap().status, TransferStatus::WaitingConfirmations @@ -400,8 +346,8 @@ fn transfer_balances() { future: AMOUNT * 3 - amount_1 - amount_2, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance); - let transfers_recv = test_list_transfers(&wallet_recv, Some(&asset_1.asset_id)); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); + let transfers_recv = recv_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers_recv.len(), 2); assert_eq!( transfers_recv.last().unwrap().status, @@ -412,26 +358,26 @@ fn transfer_balances() { future: amount_1 + amount_2, spendable: 0, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); // take transfers from WaitingConfirmations to Settled mine(false); - wait_for_refresh(&mut wallet_recv, online_recv, Some(&asset_1.asset_id), None); - wait_for_refresh(&mut wallet_send, online_send, Some(&asset_1.asset_id), None); + recv_party.wait_for_refresh(Some(&asset_1.asset_id)); + send_party.wait_for_refresh(Some(&asset_1.asset_id)); - show_unspent_colorings(&mut wallet_send, "send after 2nd send, settled"); - show_unspent_colorings(&mut wallet_recv, "recv after 2nd send, settled"); + send_party.show_unspent_colorings("send after 2nd send, settled"); + recv_party.show_unspent_colorings("recv after 2nd send, settled"); // balances with transfer Settled - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.last().unwrap().status, TransferStatus::Settled); let expected_balance = Balance { settled: AMOUNT * 3 - amount_1 - amount_2, future: AMOUNT * 3 - amount_1 - amount_2, spendable: AMOUNT * 3 - amount_1 - amount_2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance); - let transfers_recv = test_list_transfers(&wallet_recv, Some(&asset_1.asset_id)); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); + let transfers_recv = recv_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!( transfers_recv.last().unwrap().status, TransferStatus::Settled @@ -441,14 +387,14 @@ fn transfer_balances() { future: amount_1 + amount_2, spendable: amount_1 + amount_2, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); // // a 3rd transfer (witness, donation) // // send some assets, donation = true to broadcast right away - let receive_data_3 = test_witness_receive(&mut wallet_recv); + let receive_data_3 = recv_party.witness_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -461,9 +407,10 @@ fn transfer_balances() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - wallet_send + send_party + .wallet .send( - online_send, + send_party.online, recipient_map, true, FEE_RATE, @@ -473,18 +420,20 @@ fn transfer_balances() { .unwrap(); // sync the wallets - wallet_send + send_party + .wallet .sync( - online_send, + send_party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, }, ) .unwrap(); - wallet_recv + recv_party + .wallet .sync( - online_recv, + recv_party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -492,17 +441,17 @@ fn transfer_balances() { ) .unwrap(); - show_unspent_colorings(&mut wallet_send, "send after 3rd send"); - show_unspent_colorings(&mut wallet_recv, "recv after 3rd send"); + send_party.show_unspent_colorings("send after 3rd send"); + recv_party.show_unspent_colorings("recv after 3rd send"); // balances after sync but before refresh - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.len(), 5); assert_eq!( transfers.last().unwrap().status, TransferStatus::WaitingConfirmations // due to donation = true ); - let transfers = test_list_transfers(&wallet_recv, None); + let transfers = recv_party.list_transfers(None); assert_eq!(transfers.len(), 2); assert_eq!( transfers.last().unwrap().status, @@ -513,24 +462,24 @@ fn transfer_balances() { future: AMOUNT * 3 - amount_1 - amount_2 - amount_3, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); let expected_balance = Balance { settled: amount_1 + amount_2, future: amount_1 + amount_2, spendable: amount_1 + amount_2, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); // take recipient transfer from WaitingCounterparty to WaitingConfirmations - wait_for_refresh(&mut wallet_recv, online_recv, None, None); + recv_party.wait_for_refresh(None); // balances with transfer WaitingConfirmations - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!( transfers.last().unwrap().status, TransferStatus::WaitingConfirmations ); - let transfers = test_list_transfers(&wallet_recv, Some(&asset_1.asset_id)); + let transfers = recv_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.len(), 3); assert_eq!( transfers.last().unwrap().status, @@ -541,45 +490,45 @@ fn transfer_balances() { future: AMOUNT * 3 - amount_1 - amount_2 - amount_3, spendable: AMOUNT * 2, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); let expected_balance = Balance { settled: amount_1 + amount_2, future: amount_1 + amount_2 + amount_3, spendable: amount_1 + amount_2, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); // take transfers from WaitingConfirmations to Settled mine(false); - wait_for_refresh(&mut wallet_recv, online_recv, Some(&asset_1.asset_id), None); - wait_for_refresh(&mut wallet_send, online_send, Some(&asset_1.asset_id), None); + recv_party.wait_for_refresh(Some(&asset_1.asset_id)); + send_party.wait_for_refresh(Some(&asset_1.asset_id)); - show_unspent_colorings(&mut wallet_send, "send after 3rd send, settled"); - show_unspent_colorings(&mut wallet_recv, "recv after 3rd send, settled"); + send_party.show_unspent_colorings("send after 3rd send, settled"); + recv_party.show_unspent_colorings("recv after 3rd send, settled"); // balances with transfer Settled - let transfers = test_list_transfers(&wallet_send, Some(&asset_1.asset_id)); + let transfers = send_party.list_transfers(Some(&asset_1.asset_id)); assert_eq!(transfers.last().unwrap().status, TransferStatus::Settled); let expected_balance = Balance { settled: AMOUNT * 3 - amount_1 - amount_2 - amount_3, future: AMOUNT * 3 - amount_1 - amount_2 - amount_3, spendable: AMOUNT * 3 - amount_1 - amount_2 - amount_3, }; - wait_for_asset_balance(&wallet_send, &asset_1.asset_id, &expected_balance); + send_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); let expected_balance = Balance { settled: amount_1 + amount_2 + amount_3, future: amount_1 + amount_2 + amount_3, spendable: amount_1 + amount_2 + amount_3, }; - wait_for_asset_balance(&wallet_recv, &asset_1.asset_id, &expected_balance); + recv_party.wait_for_asset_balance(&asset_1.asset_id, &expected_balance); } #[test] #[parallel] fn fail() { - let wallet = get_test_wallet(true, None); + let party = offline_party!(get_test_wallet(true, None)); // bad asset_id returns an error - let result = test_get_asset_balance_result(&wallet, "rgb1inexistent"); + let result = party.get_asset_balance_result("rgb1inexistent"); assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ }))); } diff --git a/src/wallet/test/get_asset_metadata.rs b/src/wallet/test/get_asset_metadata.rs index 70236ef3..97d920c1 100644 --- a/src/wallet/test/get_asset_metadata.rs +++ b/src/wallet/test/get_asset_metadata.rs @@ -6,15 +6,15 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); - let asset_nia = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT, AMOUNT])); - let transfers = test_list_transfers(&wallet, Some(&asset_nia.asset_id)); + let asset_nia = party.issue_asset_nia(Some(&[AMOUNT, AMOUNT])); + let transfers = party.list_transfers(Some(&asset_nia.asset_id)); assert_eq!(transfers.len(), 1); let issuance = transfers.first().unwrap(); let timestamp = issuance.created_at; - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), vec![Recipient { @@ -24,15 +24,11 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - test_send(&mut wallet, online, &recipient_map); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let nia_metadata = test_get_asset_metadata(&rcv_wallet, &asset_nia.asset_id); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + party.send_retry(&recipient_map); + rcv_party.wait_for_refresh(None); + let bak_info_before = party.db_backup_info(); + let nia_metadata = rcv_party.get_asset_metadata(&asset_nia.asset_id); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -47,18 +43,13 @@ fn success() { assert!((timestamp - nia_metadata.timestamp) < 30); let image_str = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); - let asset_uda = test_issue_asset_uda( - &mut wallet, - online, - Some(DETAILS), - Some(FILE_STR), - vec![&image_str, FILE_STR], - ); - let transfers = test_list_transfers(&wallet, Some(&asset_uda.asset_id)); + let asset_uda = + party.issue_asset_uda(Some(DETAILS), Some(FILE_STR), vec![&image_str, FILE_STR]); + let transfers = party.list_transfers(Some(&asset_uda.asset_id)); assert_eq!(transfers.len(), 1); let issuance = transfers.first().unwrap(); let timestamp = issuance.created_at; - let uda_metadata = test_get_asset_metadata(&wallet, &asset_uda.asset_id); + let uda_metadata = party.get_asset_metadata(&asset_uda.asset_id); assert_eq!(uda_metadata.asset_schema, AssetSchema::Uda); assert_eq!(uda_metadata.initial_supply, 1); @@ -79,7 +70,8 @@ fn success() { assert!(token.reserves.is_none()); let details = None; - let asset_cfa = wallet + let asset_cfa = party + .wallet .issue_asset_cfa( NAME.to_string(), details.clone(), @@ -88,11 +80,11 @@ fn success() { Some(FILE_STR.to_string()), ) .unwrap(); - let transfers = test_list_transfers(&wallet, Some(&asset_cfa.asset_id)); + let transfers = party.list_transfers(Some(&asset_cfa.asset_id)); assert_eq!(transfers.len(), 1); let issuance = transfers.first().unwrap(); let timestamp = issuance.created_at; - let cfa_metadata = test_get_asset_metadata(&wallet, &asset_cfa.asset_id); + let cfa_metadata = party.get_asset_metadata(&asset_cfa.asset_id); assert_eq!(cfa_metadata.asset_schema, AssetSchema::Cfa); assert_eq!(cfa_metadata.initial_supply, AMOUNT * 2); @@ -109,8 +101,8 @@ fn success() { fn fail() { initialize(); - let wallet = get_test_wallet(true, None); + let party = offline_party!(get_test_wallet(true, None)); - let result = test_get_asset_metadata_result(&wallet, ""); + let result = party.get_asset_metadata_result(""); assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ }))); } diff --git a/src/wallet/test/get_btc_balance.rs b/src/wallet/test/get_btc_balance.rs index 01edb8b6..2662babf 100644 --- a/src/wallet/test/get_btc_balance.rs +++ b/src/wallet/test/get_btc_balance.rs @@ -6,17 +6,13 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); // empty balance - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info_opt(); assert!(bak_info_before.is_none()); - let balance = test_get_btc_balance(&mut wallet, online); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let balance = party.get_btc_balance_with_sync(); + let bak_info_after = party.db_backup_info_opt(); assert!(bak_info_after.is_none()); let expected_balance = BtcBalance { vanilla: Balance { @@ -34,7 +30,7 @@ fn success() { // future balance after funding let _guard = stop_mining(); - send_to_address(test_get_address(&mut wallet)); + send_to_address(party.get_address()); let expected_balance = BtcBalance { vanilla: Balance { settled: 0, @@ -47,7 +43,7 @@ fn success() { spendable: 0, }, }; - wait_for_btc_balance(&mut wallet, online, &expected_balance); + party.wait_for_btc_balance(&expected_balance); // settled balance after mining drop(_guard); @@ -64,11 +60,11 @@ fn success() { spendable: 0, }, }; - assert_eq!(test_get_btc_balance(&mut wallet, online), expected_balance); + assert_eq!(party.get_btc_balance_with_sync(), expected_balance); // future vanilla change + colored UTXOs balance let _guard = stop_mining(); - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); let expected_balance = BtcBalance { vanilla: Balance { settled: 0, @@ -81,7 +77,7 @@ fn success() { spendable: 5000, }, }; - assert_eq!(test_get_btc_balance(&mut wallet, online), expected_balance); + assert_eq!(party.get_btc_balance_with_sync(), expected_balance); // settled balance after mining drop(_guard); @@ -98,7 +94,7 @@ fn success() { spendable: 5000, }, }; - assert_eq!(test_get_btc_balance(&mut wallet, online), expected_balance); + assert_eq!(party.get_btc_balance_with_sync(), expected_balance); } #[cfg(feature = "electrum")] @@ -111,34 +107,28 @@ fn skip_sync() { let check_interval = 1000; fn get_check<'a>( - wallet: &'a mut Wallet, - online: Online, + party: &'a mut impl SigParty, expected_balance: &'a BtcBalance, sync: bool, ) -> impl FnMut() -> bool + 'a { move || -> bool { if sync { - wallet - .sync( - online, - SyncOptions { - keychain: SyncKeychain::Vanilla { - lookback: INDEXER_SYNC_LOOKBACK as u32, - }, - strategy: SyncStrategy::FastSync, - }, - ) - .unwrap(); + party.sync(SyncOptions { + keychain: SyncKeychain::Vanilla { + lookback: INDEXER_SYNC_LOOKBACK as u32, + }, + strategy: SyncStrategy::FastSync, + }); } - let balance = wallet.get_btc_balance(None, true).unwrap(); + let balance = party.get_btc_balance(); balance == *expected_balance } } - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); // empty balance - let balance = wallet.get_btc_balance(None, true).unwrap(); + let balance = party.get_btc_balance(); let expected_balance = BtcBalance { vanilla: Balance { settled: 0, @@ -155,7 +145,7 @@ fn skip_sync() { // future balance after funding let _guard = stop_mining(); - send_to_address(test_get_address(&mut wallet)); + send_to_address(party.get_address()); let expected_balance = BtcBalance { vanilla: Balance { settled: 0, @@ -170,13 +160,13 @@ fn skip_sync() { }; // no change to balance if sync is skipped assert!(!wait_for_function( - get_check(&mut wallet, online, &expected_balance, false), + get_check(&mut party, &expected_balance, false), check_timeout, check_interval, )); // balance updated after manual sync assert!(wait_for_function( - get_check(&mut wallet, online, &expected_balance, true), + get_check(&mut party, &expected_balance, true), check_timeout, check_interval, )); @@ -198,21 +188,22 @@ fn skip_sync() { }; // no change to balance if sync is skipped assert!(!wait_for_function( - get_check(&mut wallet, online, &expected_balance, false), + get_check(&mut party, &expected_balance, false), check_timeout, check_interval, )); // balance updated after manual sync assert!(wait_for_function( - get_check(&mut wallet, online, &expected_balance, true), + get_check(&mut party, &expected_balance, true), check_timeout, check_interval, )); // future vanilla change + colored UTXOs balance (create UTXOs skipping sync) let _guard = stop_mining(); - wallet - .create_utxos(online, false, None, None, FEE_RATE, true) + party + .wallet + .create_utxos(party.online, false, None, None, FEE_RATE, true) .unwrap(); let expected_balance = BtcBalance { vanilla: Balance { @@ -228,13 +219,13 @@ fn skip_sync() { }; // balance reflects the self-broadcast TX immediately (no manual sync needed) assert!(wait_for_function( - get_check(&mut wallet, online, &expected_balance, false), + get_check(&mut party, &expected_balance, false), check_timeout, check_interval, )); // still consistent after a manual sync assert!(wait_for_function( - get_check(&mut wallet, online, &expected_balance, true), + get_check(&mut party, &expected_balance, true), check_timeout, check_interval, )); @@ -256,13 +247,13 @@ fn skip_sync() { }; // no change to balance if sync is skipped assert!(!wait_for_function( - get_check(&mut wallet, online, &expected_balance, false), + get_check(&mut party, &expected_balance, false), check_timeout, check_interval, )); // balance updated after manual sync assert!(wait_for_function( - get_check(&mut wallet, online, &expected_balance, true), + get_check(&mut party, &expected_balance, true), check_timeout, check_interval, )); diff --git a/src/wallet/test/get_fee_estimation.rs b/src/wallet/test/get_fee_estimation.rs index 90712fcf..15501872 100644 --- a/src/wallet/test/get_fee_estimation.rs +++ b/src/wallet/test/get_fee_estimation.rs @@ -1,15 +1,16 @@ use super::*; #[cfg(any(feature = "electrum", feature = "esplora"))] -fn success_common(wallet: &mut Wallet, online: Online, esplora: bool) { - fn random_send_btc(wallet: &mut Wallet, online: Online) { +fn success_common(party: &mut SinglesigParty, esplora: bool) { + fn random_send_btc(party: &mut SinglesigParty) { let fee_rate = rand::rng().random_range(1..10); let amount = rand::rng().random_range(1000..5000); let mut attempts = 3; loop { - let addr = test_get_address(wallet).to_string(); - if wallet - .send_btc(online, addr, amount, fee_rate, true) + let addr = party.get_address().to_string(); + if party + .wallet + .send_btc(party.online, addr, amount, fee_rate, true) .is_err() { attempts -= 1; @@ -22,9 +23,10 @@ fn success_common(wallet: &mut Wallet, online: Online, esplora: bool) { break; } } - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -37,11 +39,11 @@ fn success_common(wallet: &mut Wallet, online: Online, esplora: bool) { for _ in 0..100 { for _ in 0..15 { - random_send_btc(wallet, online); + random_send_btc(party); } mine(esplora); for _ in 0..3 { - random_send_btc(wallet, online); + random_send_btc(party); } if estimate_smart_fee(esplora) { break; @@ -50,7 +52,7 @@ fn success_common(wallet: &mut Wallet, online: Online, esplora: bool) { let mut last_estimate = f64::MAX; for i in MIN_BLOCK_ESTIMATION..=MAX_BLOCK_ESTIMATION { - let estimate = wallet.get_fee_estimation(online, i).unwrap(); + let estimate = party.wallet.get_fee_estimation(party.online, i).unwrap(); assert!(estimate <= last_estimate); last_estimate = estimate; } @@ -63,9 +65,9 @@ fn success_common(wallet: &mut Wallet, online: Online, esplora: bool) { fn success_electrum() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); - success_common(&mut wallet, online, false); + success_common(&mut party, false); } #[cfg(feature = "esplora")] @@ -75,16 +77,16 @@ fn success_electrum() { fn success_esplora() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(ESPLORA_URL.to_string()); + let mut party = get_funded_noutxo_party!(ESPLORA_URL.to_string()); - success_common(&mut wallet, online, true); + success_common(&mut party, true); } #[cfg(any(feature = "electrum", feature = "esplora"))] -fn fail_common(wallet: &Wallet, online: Online, esplora: bool) { +fn fail_common(party: &SinglesigParty, esplora: bool) { for _ in 0..100 { mine_blocks(esplora, 100); - if let Err(e) = wallet.get_fee_estimation(online, 5) { + if let Err(e) = party.wallet.get_fee_estimation(party.online, 5) { assert!(matches!(e, Error::CannotEstimateFees)); return; } @@ -99,9 +101,9 @@ fn fail_common(wallet: &Wallet, online: Online, esplora: bool) { fn fail_electrum() { initialize(); - let (wallet, online) = get_empty_wallet!(); + let party = get_empty_party!(); - fail_common(&wallet, online, false) + fail_common(&party, false) } #[cfg(feature = "esplora")] @@ -111,9 +113,9 @@ fn fail_electrum() { fn fail_esplora() { initialize(); - let (wallet, online) = get_empty_wallet!(ESPLORA_URL.to_string()); + let party = get_empty_party!(ESPLORA_URL.to_string()); - fail_common(&wallet, online, true) + fail_common(&party, true) } #[cfg(feature = "electrum")] @@ -122,13 +124,17 @@ fn fail_esplora() { fn fail() { initialize(); - let (wallet, online) = get_empty_wallet!(); + let party = get_empty_party!(); // requested number of blocks too low - let result = wallet.get_fee_estimation(online, MIN_BLOCK_ESTIMATION - 1); + let result = party + .wallet + .get_fee_estimation(party.online, MIN_BLOCK_ESTIMATION - 1); assert!(matches!(result, Err(Error::InvalidEstimationBlocks))); // requested number of blocks too high - let result = wallet.get_fee_estimation(online, MAX_BLOCK_ESTIMATION + 1); + let result = party + .wallet + .get_fee_estimation(party.online, MAX_BLOCK_ESTIMATION + 1); assert!(matches!(result, Err(Error::InvalidEstimationBlocks))); } diff --git a/src/wallet/test/get_wallet_data.rs b/src/wallet/test/get_wallet_data.rs index a5a4b510..f1408ed1 100644 --- a/src/wallet/test/get_wallet_data.rs +++ b/src/wallet/test/get_wallet_data.rs @@ -20,7 +20,7 @@ fn success() { ) .unwrap(); - let wallet_1_data = test_get_wallet_data(&wallet_1); + let wallet_1_data = wallet_1.get_wallet_data(); assert_eq!(wallet_1_data.data_dir, test_data_dir_str); assert_eq!( wallet_1.get_wallet_dir().parent().unwrap(), @@ -42,7 +42,7 @@ fn success() { SinglesigKeys::from_keys_no_mnemonic(&keys, None), ) .unwrap(); - let wallet_2_data = test_get_wallet_data(&wallet_2); + let wallet_2_data = wallet_2.get_wallet_data(); assert_eq!(wallet_2_data.data_dir, test_data_dir_str); assert_eq!(wallet_2_data.bitcoin_network, BitcoinNetwork::Regtest); assert!(matches!(wallet_2_data.database_type, DatabaseType::Sqlite)); diff --git a/src/wallet/test/get_wallet_dir.rs b/src/wallet/test/get_wallet_dir.rs index 5948c6d9..b0f131df 100644 --- a/src/wallet/test/get_wallet_dir.rs +++ b/src/wallet/test/get_wallet_dir.rs @@ -14,6 +14,6 @@ fn success() { let expected_dir = fs::canonicalize(test_data_dir.join(keys.master_fingerprint)).unwrap(); - let wallet_dir = test_get_wallet_dir(&wallet); + let wallet_dir = wallet.get_wallet_dir(); assert_eq!(wallet_dir, expected_dir); } diff --git a/src/wallet/test/go_online.rs b/src/wallet/test/go_online.rs index 6932b0e8..727d16b4 100644 --- a/src/wallet/test/go_online.rs +++ b/src/wallet/test/go_online.rs @@ -6,31 +6,27 @@ use super::*; fn success() { initialize(); - let mut wallet = get_test_wallet(true, None); + let mut party = offline_party!(get_test_wallet(true, None)); // go online - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info_opt(); assert!(bak_info_before.is_none()); - let result_1 = test_go_online_result(&mut wallet, false, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let result_1 = party.go_online_result(false, None); + let bak_info_after = party.db_backup_info_opt(); assert!(bak_info_after.is_none()); assert!(result_1.is_ok()); // can go online again with the same electrum URL - let result_2 = test_go_online_result(&mut wallet, false, None); + let result_2 = party.go_online_result(false, None); assert!(result_2.is_ok()); assert_eq!(result_1.unwrap(), result_2.unwrap()); // can go online again with a different electrum URL - let result_3 = test_go_online_result(&mut wallet, false, Some(ELECTRUM_2_URL)); + let result_3 = party.go_online_result(false, Some(ELECTRUM_2_URL)); assert!(result_3.is_ok()); // can go online again with esplora URL - let result_4 = test_go_online_result(&mut wallet, false, Some(ESPLORA_URL)); + let result_4 = party.go_online_result(false, Some(ESPLORA_URL)); assert!(result_4.is_ok()); } @@ -41,11 +37,15 @@ fn fail() { initialize(); // wallets - let mut wallet = get_test_wallet(true, None); - let mut wallet_testnet = get_test_wallet_with_net(true, None, BitcoinNetwork::Testnet); + let mut party = offline_party!(get_test_wallet(true, None)); + let mut party_testnet = offline_party!(get_test_wallet_with_net( + true, + None, + BitcoinNetwork::Testnet + )); // cannot go online with an invalid indexer URL - let result = test_go_online_result(&mut wallet, false, Some("other:50001")); + let result = party.go_online_result(false, Some("other:50001")); let details = "not a valid electrum nor esplora server"; assert!(matches!(result, Err(Error::InvalidIndexer { details: m }) if m == details )); @@ -55,8 +55,8 @@ fn fail() { } else { ESPLORA_URL }; - test_go_online(&mut wallet, false, Some(indexer_url)); - let result = test_go_online_result(&mut wallet, false, Some("other:50001")); + party.go_online(false, Some(indexer_url)); + let result = party.go_online_result(false, Some("other:50001")); assert!(matches!(result, Err(Error::InvalidIndexer { details: m }) if m == details )); let details_another_chain = "resolver is for another chain-network pair"; @@ -64,13 +64,13 @@ fn fail() { #[cfg(feature = "electrum")] { // electrs wrong network - let result = test_go_online_result(&mut wallet_testnet, false, None); + let result = party_testnet.go_online_result(false, None); assert!( matches!(result, Err(Error::InvalidIndexer { details: m }) if m == details_another_chain ) ); // unsupported electrs variant - let result = test_go_online_result(&mut wallet, false, Some(ELECTRUM_BLOCKSTREAM_URL)); + let result = party.go_online_result(false, Some(ELECTRUM_BLOCKSTREAM_URL)); let details = "verbose transactions are unsupported by the provided electrum service"; assert!( matches!(result, Err(Error::InvalidIndexer { details: m }) if m.contains(details) ) @@ -80,7 +80,7 @@ fn fail() { #[cfg(feature = "esplora")] { // esplora wrong network - let result = test_go_online_result(&mut wallet_testnet, false, Some(ESPLORA_URL)); + let result = party_testnet.go_online_result(false, Some(ESPLORA_URL)); assert!( matches!(result, Err(Error::InvalidIndexer { details: m }) if m == details_another_chain ) ); @@ -88,7 +88,7 @@ fn fail() { // bad online object let wrong_online = Online { id: 1 }; - let result = wallet.check_online(wrong_online); + let result = party.wallet.check_online(wrong_online); assert!(matches!(result, Err(Error::CannotChangeOnline))); } @@ -99,8 +99,9 @@ fn invalid_chain_net() { initialize(); // URL for custom signet but wallet for default signet - let mut wallet_signet = get_test_wallet_with_net(true, None, BitcoinNetwork::Signet); - let result = test_go_online_result(&mut wallet_signet, false, Some(ELECTRUM_SIGNET_CUSTOM_URL)); + let mut party_signet = + offline_party!(get_test_wallet_with_net(true, None, BitcoinNetwork::Signet)); + let result = party_signet.go_online_result(false, Some(ELECTRUM_SIGNET_CUSTOM_URL)); let details = "resolver is for another chain-network pair"; assert!(matches!(result, Err(Error::InvalidIndexer { details: m }) if m.contains(details) )); } @@ -112,12 +113,12 @@ fn consistency_check_fail_bitcoins() { initialize(); // prepare test wallet with UTXOs + an asset - let (mut wallet_orig, online_orig) = get_funded_wallet!(); - test_issue_asset_nia(&mut wallet_orig, online_orig, None); + let mut orig_party = get_funded_party!(); + orig_party.issue_asset_nia(None); // get wallet data - let wallet_dir_orig = test_get_wallet_dir(&wallet_orig); - let keys = wallet_orig.get_keys(); + let wallet_dir_orig = orig_party.wallet.get_wallet_dir(); + let keys = orig_party.get_keys(); let fingerprint = keys.master_fingerprint.clone(); // prepare directories let data_dir_prefill_1 = get_test_data_dir_path().join("test_consistency.bitcoin.prefill_1"); @@ -162,36 +163,38 @@ fn consistency_check_fail_bitcoins() { // introduce asset inconsistency by spending UTXOs from other instance of the same wallet, // simulating a wallet used on multiple devices (which needs to be avoided to prevent asset // loss) - let mut wallet_empty = Wallet::new(wallet_data_empty, keys.clone()).unwrap(); - let online_empty = test_go_online(&mut wallet_empty, false, None); - let request = wallet_empty.bdk_wallet().start_full_scan(); - let update = wallet_empty.indexer().full_scan(request).unwrap(); - wallet_empty.bdk_wallet_mut().apply_update(update).unwrap(); + let mut party_empty = offline_party!(Wallet::new(wallet_data_empty, keys.clone()).unwrap()); + let online_empty = party_empty.go_online(false, None); + let mut party_empty = party!(party_empty.wallet, online_empty); + let request = party_empty.wallet.bdk_wallet().start_full_scan(); + let update = party_empty.wallet.indexer().full_scan(request).unwrap(); + party_empty + .wallet + .bdk_wallet_mut() + .apply_update(update) + .unwrap(); { - let (bdk_wallet, bdk_database) = wallet_empty.bdk_wallet_db_mut(); + let (bdk_wallet, bdk_database) = party_empty.wallet.bdk_wallet_db_mut(); bdk_wallet.persist(bdk_database).unwrap(); } - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); - test_drain_to( - &mut wallet_empty, - online_empty, - &test_get_address(&mut rcv_wallet), - ); + let mut rcv_party = get_funded_party!(); + party_empty.drain_to(&rcv_party.get_address()); // detect asset inconsistency let err = "spent bitcoins with another wallet"; - let mut wallet_prefill = Wallet::new(wallet_data_prefill, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill, false, None); + let mut party_prefill = offline_party!(Wallet::new(wallet_data_prefill, keys.clone()).unwrap()); + let result = party_prefill.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e.contains(err))); // make sure detection works multiple times (doesn't get reset on first failed check) - let mut wallet_prefill_2 = Wallet::new(wallet_data_prefill_2, keys.clone()).unwrap(); + let mut party_prefill_2 = + offline_party!(Wallet::new(wallet_data_prefill_2, keys.clone()).unwrap()); for file in &db_files { let src = PathBuf::from(&wallet_dir_prefill).join(file); let dst = PathBuf::from(&wallet_dir_prefill_2).join(file); fs::copy(src, dst).unwrap(); } - let result = test_go_online_result(&mut wallet_prefill_2, false, None); + let result = party_prefill_2.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e.contains(err))); } @@ -202,12 +205,12 @@ fn consistency_check_fail_utxos() { initialize(); // prepare test wallet with UTXOs + an asset - let (mut wallet_orig, online_orig) = get_funded_wallet!(); - test_issue_asset_nia(&mut wallet_orig, online_orig, None); + let mut orig_party = get_funded_party!(); + orig_party.issue_asset_nia(None); // get wallet data - let wallet_dir_orig = test_get_wallet_dir(&wallet_orig); - let keys = wallet_orig.get_keys(); + let wallet_dir_orig = orig_party.wallet.get_wallet_dir(); + let keys = orig_party.wallet.get_keys(); let fingerprint = keys.master_fingerprint.clone(); // prepare directories let data_dir_prefill_1 = get_test_data_dir_path().join("test_consistency.utxos.prefill_1"); @@ -252,36 +255,38 @@ fn consistency_check_fail_utxos() { // introduce asset inconsistency by spending UTXOs from other instance of the same wallet, // simulating a wallet used on multiple devices (which needs to be avoided to prevent asset // loss) - let mut wallet_empty = Wallet::new(wallet_data_empty, keys.clone()).unwrap(); - let online_empty = test_go_online(&mut wallet_empty, false, None); - let request = wallet_empty.bdk_wallet().start_full_scan(); - let update = wallet_empty.indexer().full_scan(request).unwrap(); - wallet_empty.bdk_wallet_mut().apply_update(update).unwrap(); + let mut party_empty = offline_party!(Wallet::new(wallet_data_empty, keys.clone()).unwrap()); + let online_empty = party_empty.go_online(false, None); + let mut party_empty = party!(party_empty.wallet, online_empty); + let request = party_empty.wallet.bdk_wallet().start_full_scan(); + let update = party_empty.wallet.indexer().full_scan(request).unwrap(); + party_empty + .wallet + .bdk_wallet_mut() + .apply_update(update) + .unwrap(); { - let (bdk_wallet, bdk_database) = wallet_empty.bdk_wallet_db_mut(); + let (bdk_wallet, bdk_database) = party_empty.wallet.bdk_wallet_db_mut(); bdk_wallet.persist(bdk_database).unwrap(); } - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); - test_drain_to( - &mut wallet_empty, - online_empty, - &test_get_address(&mut rcv_wallet), - ); + let mut rcv_party = get_funded_party!(); + party_empty.drain_to(&rcv_party.get_address()); // detect asset inconsistency let err = "spent bitcoins with another wallet"; - let mut wallet_prefill = Wallet::new(wallet_data_prefill, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill, false, None); + let mut party_prefill = offline_party!(Wallet::new(wallet_data_prefill, keys.clone()).unwrap()); + let result = party_prefill.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e.contains(err))); // make sure detection works multiple times (doesn't get reset on first failed check) - let mut wallet_prefill_2 = Wallet::new(wallet_data_prefill_2, keys.clone()).unwrap(); + let mut party_prefill_2 = + offline_party!(Wallet::new(wallet_data_prefill_2, keys.clone()).unwrap()); for file in &db_files { let src = PathBuf::from(&wallet_dir_prefill).join(file); let dst = PathBuf::from(&wallet_dir_prefill_2).join(file); fs::copy(src, dst).unwrap(); } - let result = test_go_online_result(&mut wallet_prefill_2, false, None); + let result = party_prefill_2.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e.contains(err))); } @@ -292,12 +297,12 @@ fn consistency_check_fail_asset_ids() { initialize(); // prepare test wallet with UTXOs + an asset - let (mut wallet_orig, online_orig) = get_funded_wallet!(); - test_issue_asset_nia(&mut wallet_orig, online_orig, None); + let mut orig_party = get_funded_party!(); + orig_party.issue_asset_nia(None); // get wallet data - let wallet_dir_orig = test_get_wallet_dir(&wallet_orig); - let keys = wallet_orig.get_keys(); + let wallet_dir_orig = orig_party.wallet.get_wallet_dir(); + let keys = orig_party.wallet.get_keys(); let fingerprint = keys.master_fingerprint.clone(); // prepare directories let data_dir_prefill_1 = get_test_data_dir_path().join("test_consistency.assets.prefill_1"); @@ -327,8 +332,9 @@ fn consistency_check_fail_asset_ids() { } // check the first wallet copy works ok - let mut wallet_prefill_1 = Wallet::new(wallet_data_prefill_1, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill_1, false, None); + let mut party_prefill_1 = + offline_party!(Wallet::new(wallet_data_prefill_1, keys.clone()).unwrap()); + let result = party_prefill_1.go_online_result(false, None); assert!(result.is_ok()); // introduce asset id inconsistency by removing RGB data from wallet dir @@ -336,15 +342,17 @@ fn consistency_check_fail_asset_ids() { // detect inconsistency let err = "DB assets do not match with ones stored in RGB"; - let mut wallet_prefill_2 = Wallet::new(wallet_data_prefill_2, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill_2, false, None); + let mut party_prefill_2 = + offline_party!(Wallet::new(wallet_data_prefill_2, keys.clone()).unwrap()); + let result = party_prefill_2.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e == err)); // make sure detection works multiple times let result = copy_dir::copy_dir(wallet_dir_prefill_2, wallet_dir_prefill_3); assert!(result.unwrap().is_empty()); - let mut wallet_prefill_3 = Wallet::new(wallet_data_prefill_3, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill_3, false, None); + let mut party_prefill_3 = + offline_party!(Wallet::new(wallet_data_prefill_3, keys.clone()).unwrap()); + let result = party_prefill_3.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e == err)); } @@ -355,17 +363,12 @@ fn consistency_check_fail_media() { initialize(); // prepare test wallet with UTXOs + an asset - let (mut wallet_orig, online_orig) = get_funded_wallet!(); - test_issue_asset_cfa( - &mut wallet_orig, - online_orig, - None, - Some(FILE_STR.to_string()), - ); + let mut orig_party = get_funded_party!(); + orig_party.issue_asset_cfa(None, Some(FILE_STR.to_string())); // get wallet data - let wallet_dir_orig = test_get_wallet_dir(&wallet_orig); - let keys = wallet_orig.get_keys(); + let wallet_dir_orig = orig_party.wallet.get_wallet_dir(); + let keys = orig_party.wallet.get_keys(); let fingerprint = keys.master_fingerprint.clone(); // prepare directories let data_dir_prefill_1 = get_test_data_dir_path().join("test_consistency.media.prefill_1"); @@ -395,8 +398,9 @@ fn consistency_check_fail_media() { } // check the first wallet copy works ok - let mut wallet_prefill_1 = Wallet::new(wallet_data_prefill_1, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill_1, false, None); + let mut party_prefill_1 = + offline_party!(Wallet::new(wallet_data_prefill_1, keys.clone()).unwrap()); + let result = party_prefill_1.go_online_result(false, None); assert!(result.is_ok()); // introduce media inconsistency by removing media dir @@ -404,15 +408,17 @@ fn consistency_check_fail_media() { // detect inconsistency let err = "DB media do not match with the ones stored in media directory"; - let mut wallet_prefill_2 = Wallet::new(wallet_data_prefill_2.clone(), keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill_2, false, None); + let mut party_prefill_2 = + offline_party!(Wallet::new(wallet_data_prefill_2.clone(), keys.clone()).unwrap()); + let result = party_prefill_2.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e == err)); // make sure detection works multiple times let result = copy_dir::copy_dir(wallet_dir_prefill_2, wallet_dir_prefill_3); assert!(result.unwrap().is_empty()); - let mut wallet_prefill_3 = Wallet::new(wallet_data_prefill_3, keys.clone()).unwrap(); - let result = test_go_online_result(&mut wallet_prefill_3, false, None); + let mut party_prefill_3 = + offline_party!(Wallet::new(wallet_data_prefill_3, keys.clone()).unwrap()); + let result = party_prefill_3.go_online_result(false, None); assert!(matches!(result, Err(Error::Inconsistency { details: e }) if e == err)); } @@ -423,17 +429,17 @@ fn on_off_online() { initialize(); // create wallet and go online - let mut wallet = get_test_wallet(true, None); - let wallet_data = wallet.get_wallet_data(); - let keys = wallet.get_keys(); - let _online = test_go_online(&mut wallet, false, None); + let mut party = offline_party!(get_test_wallet(true, None)); + let wallet_data = party.wallet.get_wallet_data(); + let keys = party.wallet.get_keys(); + let _online = party.go_online(false, None); // go offline and close wallet - drop(wallet); + drop(party); // re-instantiate wallet and go back online - let mut wallet = Wallet::new(wallet_data, keys.clone()).unwrap(); - test_go_online(&mut wallet, false, None); + let mut party = offline_party!(Wallet::new(wallet_data, keys.clone()).unwrap()); + party.go_online(false, None); } #[cfg(feature = "electrum")] @@ -443,10 +449,11 @@ fn offline() { initialize(); // don't go online and manually craft the Online object - let mut wallet = get_test_wallet(true, Some(MAX_ALLOCATIONS_PER_UTXO)); + let wallet = get_test_wallet(true, Some(MAX_ALLOCATIONS_PER_UTXO)); let online = Online { id: 0 }; + let mut party = party!(wallet, online); // the online check should report that the wallet is offline - let result = test_create_utxos_begin_result(&mut wallet, online, true, None, None, FEE_RATE); + let result = party.create_utxos_begin_result(true, None, None, FEE_RATE); assert!(matches!(result, Err(Error::Offline))); } diff --git a/src/wallet/test/inflate.rs b/src/wallet/test/inflate.rs index 780d4980..776afbfb 100644 --- a/src/wallet/test/inflate.rs +++ b/src/wallet/test/inflate.rs @@ -7,30 +7,25 @@ fn success() { initialize(); // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue let issue_amounts = [AMOUNT, AMOUNT]; let inflation_rights = [100, 500, 200]; - let asset = test_issue_asset_ifa( - &mut wallet, - online, - Some(&issue_amounts), - Some(&inflation_rights), - None, - ); - show_unspent_colorings(&mut wallet, "after issue"); + let asset = party.issue_asset_ifa(Some(&issue_amounts), Some(&inflation_rights), None); + party.show_unspent_colorings("after issue"); let initial_supply = issue_amounts.iter().sum::(); let total_inflatable = inflation_rights.iter().sum::(); let max_supply = initial_supply + total_inflatable; assert_eq!(asset.initial_supply, initial_supply); assert_eq!(asset.known_circulating_supply, initial_supply); assert_eq!(asset.max_supply, max_supply); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 1); assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance); - let unspents: Vec = test_list_unspents(&mut wallet, None, false) + let unspents: Vec = party + .list_unspents(false) .into_iter() .filter(|u| u.utxo.colorable) .collect(); @@ -38,21 +33,17 @@ fn success() { assert!(unspents.iter().all(|u| u.rgb_allocations.len() == 1)); // inflate - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); let inflation_amounts = [199, 42]; - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let res = test_inflate(&mut wallet, online, &asset.asset_id, &inflation_amounts); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let res = party.inflate(&asset.asset_id, &inflation_amounts); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - show_unspent_colorings(&mut wallet, "after inflate"); + party.show_unspent_colorings("after inflate"); let total_inflated = inflation_amounts.iter().sum::(); let total_issued = initial_supply + total_inflated; // check updated balance - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -64,10 +55,10 @@ fn success() { mine(false); - assert!(test_refresh_asset(&mut wallet, online, &asset.asset_id)); - show_unspent_colorings(&mut wallet, "after inflate mine + refresh"); + assert!(party.refresh_asset(&asset.asset_id)); + party.show_unspent_colorings("after inflate mine + refresh"); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 3); let mut created_at = None; let mut updated_at = None; @@ -124,7 +115,7 @@ fn success() { assert_eq!(receive_utxo_set.len(), inflation_amounts.len()); // check balance + remaining inflation rights - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -133,7 +124,7 @@ fn success() { spendable: total_issued, } ); - let unspents = test_list_unspents(&mut wallet, Some(online), false); + let unspents = party.list_unspents_with_sync(false); let inflation_allocations = unspents.iter().flat_map(|u| { u.rgb_allocations .iter() @@ -145,7 +136,7 @@ fn success() { assert_eq!(sum, total_inflatable - total_inflated); // send - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -155,22 +146,18 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after send"); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + party.show_unspent_colorings("after send"); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), 1); let ce = tte_data.first().unwrap(); assert_eq!(ce.1.endpoint, PROXY_URL); assert!(ce.0.used); // check balance (no assets left) + remaining inflation rights - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -179,7 +166,7 @@ fn success() { spendable: 0, } ); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let inflation_allocations = unspents.iter().flat_map(|u| { u.rgb_allocations .iter() @@ -191,13 +178,12 @@ fn success() { assert_eq!(sum, total_inflatable - total_inflated); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + rcv_party.wait_for_refresh(None); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _rcv_asset_transfer) = rcv_party.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(Some(&asset.asset_id)); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations @@ -205,7 +191,7 @@ fn success() { assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations); // asset has been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let ifa_assets = rcv_assets.ifa.unwrap(); assert_eq!(ifa_assets.len(), 1); let rcv_asset = ifa_assets.last().unwrap(); @@ -227,17 +213,17 @@ fn success() { rcv_asset.known_circulating_supply, initial_supply + total_inflated ); - show_unspent_colorings(&mut wallet, "after send refresh 1"); + party.show_unspent_colorings("after send refresh 1"); // transfers progress to status Settled after tx mining + refresh mine(false); std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - show_unspent_colorings(&mut wallet, "after send mine + refresh 2"); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + party.show_unspent_colorings("after send mine + refresh 2"); // check balance (no assets left) + remaining inflation rights - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -246,7 +232,7 @@ fn success() { spendable: 0, } ); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let inflation_allocations = unspents.iter().flat_map(|u| { u.rgb_allocations .iter() @@ -257,15 +243,15 @@ fn success() { .sum::(); assert_eq!(sum, total_inflatable - total_inflated); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.change_utxo, None); - let asset_metadata = test_get_asset_metadata(&rcv_wallet, &asset.asset_id); + let asset_metadata = rcv_party.get_asset_metadata(&asset.asset_id); assert_eq!(asset_metadata.initial_supply, initial_supply); assert_eq!(asset_metadata.max_supply, max_supply); assert_eq!( @@ -277,21 +263,16 @@ fn success() { assert!(transfer_data.change_utxo.is_none()); // exhaust all inflation rights by doing a last call to inflate - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); let remaining_inflatable = total_inflatable - total_inflated; let last_inflation_amounts = [remaining_inflatable]; - test_inflate( - &mut wallet, - online, - &asset.asset_id, - &last_inflation_amounts, - ); + party.inflate(&asset.asset_id, &last_inflation_amounts); mine(false); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - show_unspent_colorings(&mut wallet, "after last inflate mine + refresh"); + party.wait_for_refresh(Some(&asset.asset_id)); + party.show_unspent_colorings("after last inflate mine + refresh"); // check all inflation rights are exhausted - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let inflation_allocations = unspents.iter().flat_map(|u| { u.rgb_allocations .iter() @@ -303,7 +284,7 @@ fn success() { assert_eq!(sum, 0); // check balance reflects the last inflate - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!( balance, Balance { @@ -314,12 +295,12 @@ fn success() { ); // check known circulating supply equals max supply (all rights exhausted) - let asset_metadata = test_get_asset_metadata(&wallet, &asset.asset_id); + let asset_metadata = party.get_asset_metadata(&asset.asset_id); assert_eq!(asset_metadata.known_circulating_supply, max_supply); // send the last inflated tokens to rcv_wallet to validate the full consignment history, // including the inflate transition that had no inflation change - let receive_data_2 = test_blind_receive(&mut rcv_wallet); + let receive_data_2 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -329,17 +310,17 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid2 = test_send(&mut wallet, online, &recipient_map); + let txid2 = party.send_retry(&recipient_map); assert!(!txid2.is_empty()); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); - let (rcv_transfer_data_2, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (rcv_transfer_data_2, _) = rcv_party.get_test_transfer_data(&rcv_transfer_2); assert_eq!(rcv_transfer_data_2.status, TransferStatus::Settled); } @@ -351,9 +332,9 @@ fn fail() { let max_inflation = 1000; - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); - let asset_ifa = test_issue_asset_ifa(&mut wallet, online, None, Some(&[max_inflation]), None); + let asset_ifa = party.issue_asset_ifa(None, Some(&[max_inflation]), None); // don't check inflate input params (checked in _begin/_end sections below) @@ -361,7 +342,8 @@ fn fail() { // - watch-only (_check_xprv) let mut wallet_wo = get_test_wallet(false, None); let online_wo = wallet_wo.go_online(test_go_online_options(None)).unwrap(); - let result = test_inflate_result(&mut wallet_wo, online_wo, &asset_ifa.asset_id, &[1]); + let mut party_wo = party!(wallet_wo, online_wo); + let result = party_wo.inflate_result(&asset_ifa.asset_id, &[1]); assert_matches!(result, Err(Error::WatchOnly)); // - wrong online @@ -369,25 +351,22 @@ fn fail() { // inflate_begin input params // - check online is correct - let result = test_inflate_begin_result(&mut wallet, wrong_online, &asset_ifa.asset_id, &[1]); + let good_online = party.online; + party.online = wrong_online; + let result = party.inflate_begin_result(&asset_ifa.asset_id, &[1]); + party.online = good_online; assert_matches!(result, Err(Error::CannotChangeOnline)); // - invalid asset_id - let result = test_inflate_begin_result(&mut wallet, online, "malformed", &[]); + let result = party.inflate_begin_result("malformed", &[]); assert_matches!(result, Err(Error::AssetNotFound { asset_id: _ })); // - check empty inflation_amounts - let result = test_inflate_begin_result(&mut wallet, online, &asset_ifa.asset_id, &[]); + let result = party.inflate_begin_result(&asset_ifa.asset_id, &[]); assert_matches!(result, Err(Error::NoInflationAmounts)); // - check inflation_amounts sum > u64 max - let result = - test_inflate_begin_result(&mut wallet, online, &asset_ifa.asset_id, &[u64::MAX, 1]); + let result = party.inflate_begin_result(&asset_ifa.asset_id, &[u64::MAX, 1]); assert_matches!(result, Err(Error::TooHighInflationAmounts)); // - check inflation_amounts sum > max inflation - let result = test_inflate_begin_result( - &mut wallet, - online, - &asset_ifa.asset_id, - &[max_inflation + 1], - ); + let result = party.inflate_begin_result(&asset_ifa.asset_id, &[max_inflation + 1]); assert_matches!( result, Err(Error::InsufficientAssignments { @@ -397,8 +376,8 @@ fn fail() { ); // - check fee_rate // - low - let result = wallet.inflate_begin( - online, + let result = party.wallet.inflate_begin( + party.online, asset_ifa.asset_id.clone(), vec![1], 0, @@ -407,8 +386,8 @@ fn fail() { ); assert_matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW); // - overflow - let result = wallet.inflate_begin( - online, + let result = party.wallet.inflate_begin( + party.online, asset_ifa.asset_id.clone(), vec![1], u64::MAX, @@ -419,7 +398,7 @@ fn fail() { // inflate_begin errors // - inexistent asset - let result = test_inflate_begin_result(&mut wallet, online, "rgb1nexistent", &[]); + let result = party.inflate_begin_result("rgb1nexistent", &[]); assert_matches!(result, Err(Error::AssetNotFound { asset_id: _ })); // - schema not supported create_test_data_dir(); @@ -439,9 +418,10 @@ fn fail() { let online_nia = wallet_nia .go_online(test_go_online_options(Some(ELECTRUM_URL))) .unwrap(); - fund_wallet(wallet_nia.get_address().unwrap()); - test_create_utxos_default(&mut wallet_nia, online_nia); - let receive_data = test_blind_receive(&mut wallet_nia); + let mut party_nia = party!(wallet_nia, online_nia); + fund_wallet(party_nia.get_address()); + party_nia.create_utxos_default(); + let receive_data = party_nia.blind_receive(); let recipient_map = HashMap::from([( asset_ifa.asset_id.clone(), vec![Recipient { @@ -451,20 +431,20 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_nia, online_nia, None, None); - wait_for_refresh(&mut wallet, online, None, None); + party_nia.wait_for_refresh(None); + party.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_nia, online_nia, None, None); - wait_for_refresh(&mut wallet, online, None, None); - let transfer_recv = get_test_transfer_recipient(&wallet_nia, &receive_data.recipient_id); - let (transfer_send, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data_recv, _) = get_test_transfer_data(&wallet_nia, &transfer_recv); - let (transfer_data_send, _) = get_test_transfer_data(&wallet, &transfer_send); + party_nia.wait_for_refresh(None); + party.wait_for_refresh(None); + let transfer_recv = party_nia.get_test_transfer_recipient(&receive_data.recipient_id); + let (transfer_send, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data_recv, _) = party_nia.get_test_transfer_data(&transfer_recv); + let (transfer_data_send, _) = party.get_test_transfer_data(&transfer_send); assert_eq!(transfer_data_recv.status, TransferStatus::Settled); assert_eq!(transfer_data_send.status, TransferStatus::Settled); - drop(wallet_nia); + drop(party_nia); let mut wallet_nia = Wallet::new( WalletData { data_dir: get_test_data_dir_string(), @@ -479,12 +459,13 @@ fn fail() { let online_nia = wallet_nia .go_online(test_go_online_options(Some(ELECTRUM_URL))) .unwrap(); - let result = test_inflate_begin_result(&mut wallet_nia, online_nia, &asset_ifa.asset_id, &[1]); + let mut party_nia = party!(wallet_nia, online_nia); + let result = party_nia.inflate_begin_result(&asset_ifa.asset_id, &[1]); assert_matches!(result, Err(Error::UnsupportedSchema { asset_schema: _ })); // - inflation not supported - let asset_nia = test_issue_asset_nia(&mut wallet, online, None); - let asset_cfa = test_issue_asset_cfa(&mut wallet, online, None, None); - let asset_uda = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); + let asset_nia = party.issue_asset_nia(None); + let asset_cfa = party.issue_asset_cfa(None, None); + let asset_uda = party.issue_asset_uda(None, None, vec![]); let unsupported_asset_ids = [ (asset_nia.asset_id, AssetSchema::Nia), (asset_cfa.asset_id, AssetSchema::Cfa), @@ -492,41 +473,45 @@ fn fail() { ]; for (asset_id, schema) in unsupported_asset_ids { let inflation_amounts = vec![200, 42]; - let result = test_inflate_result(&mut wallet, online, &asset_id, &inflation_amounts); + let result = party.inflate_result(&asset_id, &inflation_amounts); assert_matches!(result, Err(Error::UnsupportedInflation { asset_schema }) if asset_schema == schema); } // - inflation amounts (none, zero) - let result = test_inflate_begin_result(&mut wallet, online, &asset_ifa.asset_id, &[]); + let result = party.inflate_begin_result(&asset_ifa.asset_id, &[]); assert_matches!(result, Err(Error::NoInflationAmounts)); - let result = test_inflate_begin_result(&mut wallet, online, &asset_ifa.asset_id, &[1, 0, 2]); + let result = party.inflate_begin_result(&asset_ifa.asset_id, &[1, 0, 2]); assert_matches!(result, Err(Error::InvalidAmountZero)); // inflate_end input params - let address = test_get_address(&mut wallet); - let unsigned_psbt = wallet - .send_btc_begin(online, address, 1000, FEE_RATE, false, true) + let address = party.get_address(); + let unsigned_psbt = party + .wallet + .send_btc_begin(party.online, address, 1000, FEE_RATE, false, true) .unwrap(); - let signed_psbt = wallet.sign_psbt(unsigned_psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt, None).unwrap(); // - check online is correct - let result = test_inflate_end_result(&mut wallet, wrong_online, &signed_psbt); + let good_online = party.online; + party.online = wrong_online; + let result = party.inflate_end_result(&signed_psbt); + party.online = good_online; assert_matches!(result, Err(Error::CannotChangeOnline)); // - check signed_psbt is valid - let result = test_inflate_end_result(&mut wallet, online, ""); + let result = party.inflate_end_result(""); assert_matches!(result, Err(Error::InvalidPsbt { details: _ })); // inflate_end errors // - no prior inflate_begin - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let unsigned_psbt = test_inflate_begin(&mut wallet, online, &asset_ifa.asset_id, &[1]); - let signed_psbt = wallet.sign_psbt(unsigned_psbt, None).unwrap(); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let unsigned_psbt = party.inflate_begin(&asset_ifa.asset_id, &[1]); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt, None).unwrap(); let psbt_txid = Psbt::from_str(&signed_psbt) .unwrap() .extract_tx() .unwrap() .compute_txid() .to_string(); - let (mut wallet_2, online_2) = get_empty_wallet!(); - let result = test_inflate_end_result(&mut wallet_2, online_2, &signed_psbt); + let mut empty_party = get_empty_party!(); + let result = empty_party.inflate_end_result(&signed_psbt); assert_matches!(result, Err(Error::UnknownTransfer { txid }) if txid == psbt_txid); } @@ -536,16 +521,15 @@ fn fail() { fn begin_end() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let asset = test_issue_asset_ifa(&mut wallet, online, None, Some(&[1000]), None); + let mut party = get_funded_party!(); + let asset = party.issue_asset_ifa(None, Some(&[1000]), None); // begin does not update backup_info with dry_run=true - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let _res = wallet + let bak_info_before = party.db_backup_info(); + let _res = party + .wallet .inflate_begin( - online, + party.online, asset.asset_id.clone(), vec![1000], FEE_RATE, @@ -553,21 +537,18 @@ fn begin_end() { true, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); // begin does update backup_info with dry_run=false - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let res = wallet + let bak_info_before = party.db_backup_info(); + let res = party + .wallet .inflate_begin( - online, + party.online, asset.asset_id.clone(), vec![1000], FEE_RATE, @@ -575,20 +556,14 @@ fn begin_end() { false, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let signed_psbt = wallet.sign_psbt(res.psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(res.psbt, None).unwrap(); // end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.inflate_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party.wallet.inflate_end(party.online, signed_psbt).unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); } diff --git a/src/wallet/test/issue_asset_cfa.rs b/src/wallet/test/issue_asset_cfa.rs index 86af794d..3d6eaa5d 100644 --- a/src/wallet/test/issue_asset_cfa.rs +++ b/src/wallet/test/issue_asset_cfa.rs @@ -8,26 +8,17 @@ fn success() { let image_str = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); // prepare UTXOs - test_create_utxos( - &mut wallet, - online, - true, - Some(2), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(2), Some(5000), FEE_RATE, None); // required fields only println!("\nasset 1"); let before_timestamp = now().unix_timestamp(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let asset_1 = wallet + let bak_info_before = party.db_backup_info(); + let asset_1 = party + .wallet .issue_asset_cfa( NAME.to_string(), None, @@ -36,13 +27,11 @@ fn success() { None, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema - let cfa_asset_list = test_list_assets(&wallet, &[AssetSchema::Cfa]).cfa.unwrap(); + let cfa_asset_list = party.list_assets(&[AssetSchema::Cfa]).cfa.unwrap(); assert!( cfa_asset_list .into_iter() @@ -50,11 +39,11 @@ fn success() { ); // add a pending operation to an UTXO so spendable balance will be != settled / future - let _receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "after issuance 1"); + let _receive_data = party.blind_receive(); + party.show_unspent_colorings("after issuance 1"); // checks - let balance_1 = test_get_asset_balance(&wallet, &asset_1.asset_id); + let balance_1 = party.get_asset_balance(&asset_1.asset_id); assert_eq!(asset_1.name, NAME.to_string()); assert_eq!(asset_1.details, None); assert_eq!(asset_1.precision, PRECISION); @@ -72,14 +61,9 @@ fn success() { // include a text file println!("\nasset 2"); - let asset_2 = test_issue_asset_cfa( - &mut wallet, - online, - Some(&[AMOUNT * 2]), - Some(FILE_STR.to_string()), - ); - show_unspent_colorings(&mut wallet, "after issuance 2"); - let balance_2 = test_get_asset_balance(&wallet, &asset_2.asset_id); + let asset_2 = party.issue_asset_cfa(Some(&[AMOUNT * 2]), Some(FILE_STR.to_string())); + party.show_unspent_colorings("after issuance 2"); + let balance_2 = party.get_asset_balance(&asset_2.asset_id); assert_eq!(asset_2.name, NAME.to_string()); assert_eq!(asset_2.details, Some(DETAILS.to_string())); assert_eq!(asset_2.precision, PRECISION); @@ -106,14 +90,9 @@ fn success() { // include an image file println!("\nasset 3"); - let asset_3 = test_issue_asset_cfa( - &mut wallet, - online, - Some(&[AMOUNT * 3]), - Some(image_str.to_string()), - ); - show_unspent_colorings(&mut wallet, "after issuance 3"); - let balance_3 = test_get_asset_balance(&wallet, &asset_3.asset_id); + let asset_3 = party.issue_asset_cfa(Some(&[AMOUNT * 3]), Some(image_str.to_string())); + party.show_unspent_colorings("after issuance 3"); + let balance_3 = party.get_asset_balance(&asset_3.asset_id); assert_eq!( balance_3, Balance { @@ -145,20 +124,16 @@ fn multi_success() { let amounts: Vec = vec![111, 222, 333, 444, 555]; let sum: u64 = amounts.iter().sum(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); - let asset = test_issue_asset_cfa( - &mut wallet, - online, - Some(&amounts), - Some(FILE_STR.to_string()), - ); + let asset = party.issue_asset_cfa(Some(&amounts), Some(FILE_STR.to_string())); // check balance is the sum of the amounts assert_eq!(asset.balance.settled, sum); // check each allocation ends up on a different UTXO - let unspents: Vec = test_list_unspents(&mut wallet, None, true) + let unspents: Vec = party + .list_unspents(true) .into_iter() .filter(|u| !u.rgb_allocations.is_empty()) .collect(); @@ -182,7 +157,7 @@ fn multi_success() { ); // check the allocated asset has one media - let cfa_asset_list = test_list_assets(&wallet, &[]).cfa.unwrap(); + let cfa_asset_list = party.list_assets(&[]).cfa.unwrap(); let cfa_asset = cfa_asset_list .into_iter() .find(|a| a.asset_id == asset.asset_id) @@ -198,24 +173,16 @@ fn no_issue_on_pending_send() { let amount: u64 = 66; - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); // prepare UTXO - test_create_utxos( - &mut wallet, - online, - true, - Some(1), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(1), Some(5000), FEE_RATE, None); // issue 1st asset - let asset_1 = test_issue_asset_cfa(&mut wallet, online, None, None); + let asset_1 = party.issue_asset_cfa(None, None); // get 1st issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_1 = unspents .iter() .find(|u| { @@ -225,7 +192,7 @@ fn no_issue_on_pending_send() { }) .unwrap(); // send 1st asset - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -238,19 +205,19 @@ fn no_issue_on_pending_send() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // issuing a 2nd asset fails due to missing free allocation slot - let result = test_issue_asset_cfa_result(&mut wallet, online, Some(&[AMOUNT * 2]), None); + let result = party.issue_asset_cfa_result(Some(&[AMOUNT * 2]), None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // create 1 more UTXO issue 2nd asset - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let asset_2 = test_issue_asset_cfa(&mut wallet, online, Some(&[AMOUNT * 2]), None); - show_unspent_colorings(&mut wallet, "after 2nd issuance"); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let asset_2 = party.issue_asset_cfa(Some(&[AMOUNT * 2]), None); + party.show_unspent_colorings("after 2nd issuance"); // get 2nd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_2 = unspents .iter() .find(|u| { @@ -263,14 +230,14 @@ fn no_issue_on_pending_send() { assert_ne!(unspent_1.utxo.outpoint, unspent_2.utxo.outpoint); // progress transfer to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); // issue 3rd asset - let asset_3 = test_issue_asset_cfa(&mut wallet, online, Some(&[AMOUNT * 3]), None); - show_unspent_colorings(&mut wallet, "after 3rd issuance"); + let asset_3 = party.issue_asset_cfa(Some(&[AMOUNT * 3]), None); + party.show_unspent_colorings("after 3rd issuance"); // get 3rd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_3 = unspents .iter() .find(|u| { @@ -290,15 +257,14 @@ fn fail() { initialize(); // wallet - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // supply overflow - let result = - test_issue_asset_cfa_result(&mut wallet, online, Some(&[u64::MAX, u64::MAX]), None); + let result = party.issue_asset_cfa_result(Some(&[u64::MAX, u64::MAX]), None); assert!(matches!(result, Err(Error::TooHighIssuanceAmounts))); // invalid name: empty - let result = wallet.issue_asset_cfa( + let result = party.wallet.issue_asset_cfa( s!(""), Some(DETAILS.to_string()), PRECISION, @@ -308,7 +274,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidName { details: m }) if m == EMPTY_MSG)); // invalid name: too long - let result = wallet.issue_asset_cfa( + let result = party.wallet.issue_asset_cfa( ("a").repeat(257), Some(DETAILS.to_string()), PRECISION, @@ -319,7 +285,7 @@ fn fail() { // invalid name: unicode characters let invalid_name = "name with ℧nicode characters"; - let result = wallet.issue_asset_cfa( + let result = party.wallet.issue_asset_cfa( invalid_name.to_string(), Some(DETAILS.to_string()), PRECISION, @@ -332,7 +298,7 @@ fn fail() { ); // invalid details: empty - let result = wallet.issue_asset_cfa( + let result = party.wallet.issue_asset_cfa( NAME.to_string(), Some(s!("")), PRECISION, @@ -342,7 +308,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidDetails { details: m }) if m == IDENT_EMPTY_MSG)); // invalid details: too long - let result = wallet.issue_asset_cfa( + let result = party.wallet.issue_asset_cfa( NAME.to_string(), Some(("a").repeat(256)), PRECISION, @@ -352,7 +318,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidDetails { details: m }) if m == IDENT_TOO_LONG_MSG)); // invalid precision - let result = wallet.issue_asset_cfa( + let result = party.wallet.issue_asset_cfa( NAME.to_string(), Some(DETAILS.to_string()), 19, @@ -365,17 +331,16 @@ fn fail() { )); // invalid amount list (no amounts) - let result = test_issue_asset_cfa_result(&mut wallet, online, Some(&[]), None); + let result = party.issue_asset_cfa_result(Some(&[]), None); assert!(matches!(result, Err(Error::NoIssuanceAmounts))); // invalid amount list (1+ amounts == 0) - let result = test_issue_asset_cfa_result(&mut wallet, online, Some(&[1, 0, 2]), None); + let result = party.issue_asset_cfa_result(Some(&[1, 0, 2]), None); assert!(matches!(result, Err(Error::InvalidAmountZero))); // invalid file_path let invalid_file_path = s!("invalid"); - let result = - test_issue_asset_cfa_result(&mut wallet, online, None, Some(invalid_file_path.clone())); + let result = party.issue_asset_cfa_result(None, Some(invalid_file_path.clone())); assert!(matches!( result, Err(Error::InvalidFilePath { file_path: t }) if t == invalid_file_path @@ -385,20 +350,20 @@ fn fail() { let empty_path = tempfile::NamedTempFile::with_prefix("issue_asset_cfa::fail_").unwrap(); fs::File::create(&empty_path).unwrap(); let empty_str = empty_path.path().to_str().unwrap().to_string(); - let result = test_issue_asset_cfa_result(&mut wallet, online, None, Some(empty_str.clone())); + let result = party.issue_asset_cfa_result(None, Some(empty_str.clone())); assert!(matches!(result, Err(Error::EmptyFile { file_path: t }) if t == empty_str)); // new wallet - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); // insufficient funds - let result = test_issue_asset_cfa_result(&mut wallet, online, None, None); + let result = party.issue_asset_cfa_result(None, None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); mine(false); // insufficient allocations - let result = test_issue_asset_cfa_result(&mut wallet, online, None, None); + let result = party.issue_asset_cfa_result(None, None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } diff --git a/src/wallet/test/issue_asset_ifa.rs b/src/wallet/test/issue_asset_ifa.rs index 1e9ff1a0..298aeadf 100644 --- a/src/wallet/test/issue_asset_ifa.rs +++ b/src/wallet/test/issue_asset_ifa.rs @@ -6,26 +6,20 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); let before_timestamp = now().unix_timestamp(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let asset = test_issue_asset_ifa( - &mut wallet, - online, + let bak_info_before = party.db_backup_info(); + let asset = party.issue_asset_ifa( Some(&[AMOUNT, AMOUNT]), Some(&[AMOUNT, AMOUNT, AMOUNT]), None, ); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema - let ifa_asset_list = test_list_assets(&wallet, &[AssetSchema::Ifa]).ifa.unwrap(); + let ifa_asset_list = party.list_assets(&[AssetSchema::Ifa]).ifa.unwrap(); assert!( ifa_asset_list .into_iter() @@ -33,11 +27,11 @@ fn success() { ); // add a pending operation to an UTXO so spendable balance will be != settled / future - let _receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "after issuance + blind receive"); + let _receive_data = party.blind_receive(); + party.show_unspent_colorings("after issuance + blind receive"); // checks - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!(asset.ticker, TICKER.to_string()); assert_eq!(asset.name, NAME.to_string()); assert_eq!(asset.details, None); @@ -52,7 +46,7 @@ fn success() { } ); assert!(before_timestamp <= asset.added_at && asset.added_at <= now().unix_timestamp()); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspents_fungible = unspents.iter().filter(|u| { u.rgb_allocations.iter().any(|a| { a.asset_id == Some(asset.asset_id.clone()) @@ -75,12 +69,12 @@ fn success() { fn noissue_someinflation() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); - let asset = test_issue_asset_ifa(&mut wallet, online, Some(&[]), Some(&[AMOUNT]), None); + let asset = party.issue_asset_ifa(Some(&[]), Some(&[AMOUNT]), None); // checks - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!(asset.initial_supply, 0); assert_eq!( balance, @@ -90,7 +84,7 @@ fn noissue_someinflation() { spendable: 0, } ); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspents_asset = unspents.iter().filter(|u| { u.rgb_allocations .iter() @@ -121,18 +115,19 @@ fn multi_success() { let amounts: Vec = vec![111, 222, 333, 444, 555]; let sum: u64 = amounts.iter().sum(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // create more UTXOs - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); - let asset = test_issue_asset_ifa(&mut wallet, online, Some(&amounts), None, None); + let asset = party.issue_asset_ifa(Some(&amounts), None, None); // check balance is the sum of the amounts assert_eq!(asset.balance.settled, sum); // check each allocation ends up on a different UTXO - let unspents: Vec = test_list_unspents(&mut wallet, None, true) + let unspents: Vec = party + .list_unspents(true) .into_iter() .filter(|u| { u.rgb_allocations @@ -169,25 +164,17 @@ fn no_issue_on_pending_send() { let amount: u64 = 66; let amount_inflation: u64 = 190; - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); // prepare UTXOs - test_create_utxos( - &mut wallet, - online, - true, - Some(2), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(2), Some(5000), FEE_RATE, None); // issue 1st asset - let asset_1 = test_issue_asset_ifa(&mut wallet, online, None, None, None); - show_unspent_colorings(&mut wallet, "after 1st issuance"); + let asset_1 = party.issue_asset_ifa(None, None, None); + party.show_unspent_colorings("after 1st issuance"); // get 1st issuance UTXOs - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_1_fungible = unspents .iter() .find(|u| { @@ -212,8 +199,8 @@ fn no_issue_on_pending_send() { ); // send 1st asset - let receive_data_1 = test_witness_receive(&mut rcv_wallet); - let receive_data_2 = test_witness_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.witness_receive(); + let receive_data_2 = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![ @@ -237,21 +224,20 @@ fn no_issue_on_pending_send() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after send"); + party.show_unspent_colorings("after send"); // issuing a 2nd asset fails due to insufficient allocation slots (pending transfers) - let result = - test_issue_asset_ifa_result(&mut wallet, online, Some(&[AMOUNT * 2]), Some(&[]), None); + let result = party.issue_asset_ifa_result(Some(&[AMOUNT * 2]), Some(&[]), None); assert_matches!(result, Err(Error::InsufficientAllocationSlots)); // create 1 more UTXO + issue 2nd asset - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let asset_2 = test_issue_asset_ifa(&mut wallet, online, Some(&[AMOUNT * 2]), Some(&[]), None); - show_unspent_colorings(&mut wallet, "after 2nd issuance"); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let asset_2 = party.issue_asset_ifa(Some(&[AMOUNT * 2]), Some(&[]), None); + party.show_unspent_colorings("after 2nd issuance"); // get 2nd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_2_fungible = unspents .iter() .find(|u| { @@ -268,14 +254,14 @@ fn no_issue_on_pending_send() { ); // progress transfer to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); // issue 3rd asset - let asset_3 = test_issue_asset_ifa(&mut wallet, online, Some(&[AMOUNT * 3]), Some(&[]), None); - show_unspent_colorings(&mut wallet, "after 3rd issuance"); + let asset_3 = party.issue_asset_ifa(Some(&[AMOUNT * 3]), Some(&[]), None); + party.show_unspent_colorings("after 3rd issuance"); // get 3rd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_3_fungible = unspents .iter() .find(|u| { @@ -303,30 +289,22 @@ fn fail() { initialize(); // wallet - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // supply overflow - let result = - test_issue_asset_ifa_result(&mut wallet, online, Some(&[u64::MAX, u64::MAX]), None, None); + let result = party.issue_asset_ifa_result(Some(&[u64::MAX, u64::MAX]), None, None); assert!(matches!(result, Err(Error::TooHighIssuanceAmounts))); // inflation overflow - let result = - test_issue_asset_ifa_result(&mut wallet, online, Some(&[1]), Some(&[u64::MAX]), None); + let result = party.issue_asset_ifa_result(Some(&[1]), Some(&[u64::MAX]), None); assert!(matches!(result, Err(Error::TooHighInflationAmounts))); // supply + inflation overflow - let result = test_issue_asset_ifa_result( - &mut wallet, - online, - Some(&[u64::MAX]), - Some(&[u64::MAX]), - None, - ); + let result = party.issue_asset_ifa_result(Some(&[u64::MAX]), Some(&[u64::MAX]), None); assert!(matches!(result, Err(Error::TooHighInflationAmounts))); // invalid ticker: empty - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( s!(""), NAME.to_string(), PRECISION, @@ -337,7 +315,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidTicker { details: m }) if m == EMPTY_MSG)); // invalid ticker: too long - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( s!("ABCDEFGHI"), NAME.to_string(), PRECISION, @@ -348,7 +326,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidTicker { details: m }) if m == IDENT_TOO_LONG_MSG)); // invalid ticker: lowercase - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( s!("TiCkEr"), NAME.to_string(), PRECISION, @@ -362,7 +340,7 @@ fn fail() { // invalid ticker: with space let invalid_ticker = "TICKER WITH SPACE"; - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( invalid_ticker.to_string(), NAME.to_string(), PRECISION, @@ -377,7 +355,7 @@ fn fail() { // invalid ticker: unicode characters let invalid_ticker = "TICKERWITH℧NICODE"; - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( invalid_ticker.to_string(), NAME.to_string(), PRECISION, @@ -392,7 +370,7 @@ fn fail() { // invalid ticker: starting with a number let invalid_ticker = "1TICKER"; - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( invalid_ticker.to_string(), NAME.to_string(), PRECISION, @@ -406,7 +384,7 @@ fn fail() { ); // invalid name: empty - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( TICKER.to_string(), s!(""), PRECISION, @@ -417,7 +395,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidName { details: m }) if m == EMPTY_MSG)); // invalid name: too long - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( TICKER.to_string(), ("a").repeat(257), PRECISION, @@ -429,7 +407,7 @@ fn fail() { // invalid name: unicode characters let invalid_name = "name with ℧nicode characters"; - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( TICKER.to_string(), invalid_name.to_string(), PRECISION, @@ -443,7 +421,7 @@ fn fail() { ); // invalid precision - let result = wallet.issue_asset_ifa( + let result = party.wallet.issue_asset_ifa( TICKER.to_string(), NAME.to_string(), 19, @@ -457,29 +435,28 @@ fn fail() { )); // invalid amount list (no issuance nor inflation amounts) - let result = test_issue_asset_ifa_result(&mut wallet, online, Some(&[]), Some(&[]), None); + let result = party.issue_asset_ifa_result(Some(&[]), Some(&[]), None); assert!(matches!(result, Err(Error::NoIssuanceAmounts))); // invalid amount list (1+ issuance amounts == 0) - let result = test_issue_asset_ifa_result(&mut wallet, online, Some(&[1, 0, 2]), None, None); + let result = party.issue_asset_ifa_result(Some(&[1, 0, 2]), None, None); assert!(matches!(result, Err(Error::InvalidAmountZero))); // invalid amount list (1+ inflation amounts == 0) - let result = - test_issue_asset_ifa_result(&mut wallet, online, Some(&[AMOUNT]), Some(&[1, 0, 2]), None); + let result = party.issue_asset_ifa_result(Some(&[AMOUNT]), Some(&[1, 0, 2]), None); assert!(matches!(result, Err(Error::InvalidAmountZero))); // new wallet - let (mut wallet, online) = get_empty_wallet!(); + let mut empty_party = get_empty_party!(); // insufficient funds - let result = test_issue_asset_ifa_result(&mut wallet, online, None, None, None); + let result = empty_party.issue_asset_ifa_result(None, None, None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(empty_party.get_address()); mine(false); // insufficient allocations - let result = test_issue_asset_ifa_result(&mut wallet, online, None, None, None); + let result = empty_party.issue_asset_ifa_result(None, None, None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } diff --git a/src/wallet/test/issue_asset_nia.rs b/src/wallet/test/issue_asset_nia.rs index 0090b275..4ed57f15 100644 --- a/src/wallet/test/issue_asset_nia.rs +++ b/src/wallet/test/issue_asset_nia.rs @@ -6,31 +6,19 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); // prepare UTXOs - test_create_utxos( - &mut wallet, - online, - true, - Some(2), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(2), Some(5000), FEE_RATE, None); let before_timestamp = now().unix_timestamp(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let asset = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT, AMOUNT])); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let asset = party.issue_asset_nia(Some(&[AMOUNT, AMOUNT])); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema - let nia_asset_list = test_list_assets(&wallet, &[AssetSchema::Nia]).nia.unwrap(); + let nia_asset_list = party.list_assets(&[AssetSchema::Nia]).nia.unwrap(); assert!( nia_asset_list .into_iter() @@ -38,11 +26,11 @@ fn success() { ); // add a pending operation to an UTXO so spendable balance will be != settled / future - let _receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "after issuance"); + let _receive_data = party.blind_receive(); + party.show_unspent_colorings("after issuance"); // checks - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + let balance = party.get_asset_balance(&asset.asset_id); assert_eq!(asset.ticker, TICKER.to_string()); assert_eq!(asset.name, NAME.to_string()); assert_eq!(asset.details, None); @@ -68,15 +56,16 @@ fn multi_success() { let amounts: Vec = vec![111, 222, 333, 444, 555]; let sum: u64 = amounts.iter().sum(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); - let asset = test_issue_asset_nia(&mut wallet, online, Some(&amounts)); + let asset = party.issue_asset_nia(Some(&amounts)); // check balance is the sum of the amounts assert_eq!(asset.balance.settled, sum); // check each allocation ends up on a different UTXO - let unspents: Vec = test_list_unspents(&mut wallet, None, true) + let unspents: Vec = party + .list_unspents(true) .into_iter() .filter(|u| !u.rgb_allocations.is_empty()) .collect(); @@ -108,24 +97,16 @@ fn no_issue_on_pending_send() { let amount: u64 = 66; - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); // prepare UTXO - test_create_utxos( - &mut wallet, - online, - true, - Some(1), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(1), Some(5000), FEE_RATE, None); // issue 1st asset - let asset_1 = test_issue_asset_nia(&mut wallet, online, None); + let asset_1 = party.issue_asset_nia(None); // get 1st issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_1 = unspents .iter() .find(|u| { @@ -135,7 +116,7 @@ fn no_issue_on_pending_send() { }) .unwrap(); // send 1st asset - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -148,19 +129,19 @@ fn no_issue_on_pending_send() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // issuing a 2nd asset fails due to missing free allocation slot - let result = test_issue_asset_nia_result(&mut wallet, online, Some(&[AMOUNT * 2])); + let result = party.issue_asset_nia_result(Some(&[AMOUNT * 2])); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // create 1 more UTXO issue 2nd asset - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let asset_2 = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT * 2])); - show_unspent_colorings(&mut wallet, "after 2nd issuance"); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let asset_2 = party.issue_asset_nia(Some(&[AMOUNT * 2])); + party.show_unspent_colorings("after 2nd issuance"); // get 2nd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_2 = unspents .iter() .find(|u| { @@ -173,14 +154,14 @@ fn no_issue_on_pending_send() { assert_ne!(unspent_1.utxo.outpoint, unspent_2.utxo.outpoint); // progress transfer to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); // issue 3rd asset - let asset_3 = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT * 3])); - show_unspent_colorings(&mut wallet, "after 3rd issuance"); + let asset_3 = party.issue_asset_nia(Some(&[AMOUNT * 3])); + party.show_unspent_colorings("after 3rd issuance"); // get 3rd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_3 = unspents .iter() .find(|u| { @@ -200,29 +181,37 @@ fn fail() { initialize(); // wallet - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // supply overflow - let result = test_issue_asset_nia_result(&mut wallet, online, Some(&[u64::MAX, u64::MAX])); + let result = party.issue_asset_nia_result(Some(&[u64::MAX, u64::MAX])); assert!(matches!(result, Err(Error::TooHighIssuanceAmounts))); // invalid ticker: empty - let result = wallet.issue_asset_nia(s!(""), NAME.to_string(), PRECISION, vec![AMOUNT]); + let result = party + .wallet + .issue_asset_nia(s!(""), NAME.to_string(), PRECISION, vec![AMOUNT]); assert!(matches!(result, Err(Error::InvalidTicker { details: m }) if m == EMPTY_MSG)); // invalid ticker: too long - let result = wallet.issue_asset_nia(s!("ABCDEFGHI"), NAME.to_string(), PRECISION, vec![AMOUNT]); + let result = + party + .wallet + .issue_asset_nia(s!("ABCDEFGHI"), NAME.to_string(), PRECISION, vec![AMOUNT]); assert!(matches!(result, Err(Error::InvalidTicker { details: m }) if m == IDENT_TOO_LONG_MSG)); // invalid ticker: lowercase - let result = wallet.issue_asset_nia(s!("TiCkEr"), NAME.to_string(), PRECISION, vec![AMOUNT]); + let result = + party + .wallet + .issue_asset_nia(s!("TiCkEr"), NAME.to_string(), PRECISION, vec![AMOUNT]); assert!( matches!(result, Err(Error::InvalidTicker { details: m }) if m == "ticker needs to be all uppercase") ); // invalid ticker: with space let invalid_ticker = "TICKER WITH SPACE"; - let result = wallet.issue_asset_nia( + let result = party.wallet.issue_asset_nia( invalid_ticker.to_string(), NAME.to_string(), PRECISION, @@ -235,7 +224,7 @@ fn fail() { // invalid ticker: unicode characters let invalid_ticker = "TICKERWITH℧NICODE"; - let result = wallet.issue_asset_nia( + let result = party.wallet.issue_asset_nia( invalid_ticker.to_string(), NAME.to_string(), PRECISION, @@ -248,7 +237,7 @@ fn fail() { // invalid ticker: starting with a number let invalid_ticker = "1TICKER"; - let result = wallet.issue_asset_nia( + let result = party.wallet.issue_asset_nia( invalid_ticker.to_string(), NAME.to_string(), PRECISION, @@ -260,11 +249,13 @@ fn fail() { ); // invalid name: empty - let result = wallet.issue_asset_nia(TICKER.to_string(), s!(""), PRECISION, vec![AMOUNT]); + let result = party + .wallet + .issue_asset_nia(TICKER.to_string(), s!(""), PRECISION, vec![AMOUNT]); assert!(matches!(result, Err(Error::InvalidName { details: m }) if m == EMPTY_MSG)); // invalid name: too long - let result = wallet.issue_asset_nia( + let result = party.wallet.issue_asset_nia( TICKER.to_string(), ("a").repeat(257), PRECISION, @@ -274,7 +265,7 @@ fn fail() { // invalid name: unicode characters let invalid_name = "name with ℧nicode characters"; - let result = wallet.issue_asset_nia( + let result = party.wallet.issue_asset_nia( TICKER.to_string(), invalid_name.to_string(), PRECISION, @@ -286,31 +277,34 @@ fn fail() { ); // invalid precision - let result = wallet.issue_asset_nia(TICKER.to_string(), NAME.to_string(), 19, vec![AMOUNT]); + let result = + party + .wallet + .issue_asset_nia(TICKER.to_string(), NAME.to_string(), 19, vec![AMOUNT]); assert!(matches!( result, Err(Error::InvalidPrecision { details: m }) if m == "precision is too high" )); // invalid amount list (no amounts) - let result = test_issue_asset_nia_result(&mut wallet, online, Some(&[])); + let result = party.issue_asset_nia_result(Some(&[])); assert!(matches!(result, Err(Error::NoIssuanceAmounts))); // invalid amount list (1+ amounts == 0) - let result = test_issue_asset_nia_result(&mut wallet, online, Some(&[1, 0, 2])); + let result = party.issue_asset_nia_result(Some(&[1, 0, 2])); assert!(matches!(result, Err(Error::InvalidAmountZero))); // new wallet - let (mut wallet, online) = get_empty_wallet!(); + let mut empty_party = get_empty_party!(); // insufficient funds - let result = test_issue_asset_nia_result(&mut wallet, online, None); + let result = empty_party.issue_asset_nia_result(None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(empty_party.get_address()); mine(false); // insufficient allocations - let result = test_issue_asset_nia_result(&mut wallet, online, None); + let result = empty_party.issue_asset_nia_result(None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } diff --git a/src/wallet/test/issue_asset_uda.rs b/src/wallet/test/issue_asset_uda.rs index 89cc27a1..eb3ca62e 100644 --- a/src/wallet/test/issue_asset_uda.rs +++ b/src/wallet/test/issue_asset_uda.rs @@ -9,33 +9,21 @@ fn success() { let settled = 1; let image_str = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); - let (mut wallet, online) = get_funded_noutxo_wallet!(); + let mut party = get_funded_noutxo_party!(); // prepare UTXOs - test_create_utxos( - &mut wallet, - online, - true, - Some(1), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(1), Some(5000), FEE_RATE, None); // required fields only println!("\nasset 1"); let before_timestamp = now().unix_timestamp(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let asset_1 = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let asset_1 = party.issue_asset_uda(None, None, vec![]); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); // check the asset has been saved with the correct schema - let uda_asset_list = test_list_assets(&wallet, &[AssetSchema::Uda]).uda.unwrap(); + let uda_asset_list = party.list_assets(&[AssetSchema::Uda]).uda.unwrap(); assert!( uda_asset_list .into_iter() @@ -43,11 +31,11 @@ fn success() { ); // add a pending operation to the UTXO so spendable balance will be != settled / future - let _receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "after issuance 1"); + let _receive_data = party.blind_receive(); + party.show_unspent_colorings("after issuance 1"); // checks - let balance_1 = test_get_asset_balance(&wallet, &asset_1.asset_id); + let balance_1 = party.get_asset_balance(&asset_1.asset_id); assert_eq!(asset_1.ticker, TICKER.to_string()); assert_eq!(asset_1.name, NAME.to_string()); assert_eq!(asset_1.details, None); @@ -73,15 +61,9 @@ fn success() { // include a token with a media and 2 attachments println!("\nasset 2"); - let asset_2 = test_issue_asset_uda( - &mut wallet, - online, - Some(DETAILS), - Some(FILE_STR), - vec![&image_str, FILE_STR], - ); - show_unspent_colorings(&mut wallet, "after issuance 2"); - let balance_2 = test_get_asset_balance(&wallet, &asset_2.asset_id); + let asset_2 = party.issue_asset_uda(Some(DETAILS), Some(FILE_STR), vec![&image_str, FILE_STR]); + party.show_unspent_colorings("after issuance 2"); + let balance_2 = party.get_asset_balance(&asset_2.asset_id); assert_eq!(asset_2.ticker, TICKER.to_string()); assert_eq!(asset_2.name, NAME.to_string()); assert_eq!(asset_2.details, Some(DETAILS.to_string())); @@ -130,9 +112,7 @@ fn success() { // maximum number of attachments println!("\nmatching max attachment number"); - let asset_3 = test_issue_asset_uda( - &mut wallet, - online, + let asset_3 = party.issue_asset_uda( None, None, [image_str.clone()] @@ -142,8 +122,8 @@ fn success() { .map(|a| a.as_str()) .collect(), ); - show_unspent_colorings(&mut wallet, "after issuance 3"); - let balance_3 = test_get_asset_balance(&wallet, &asset_3.asset_id); + party.show_unspent_colorings("after issuance 3"); + let balance_3 = party.get_asset_balance(&asset_3.asset_id); assert_eq!( balance_3, Balance { @@ -157,7 +137,8 @@ fn success() { assert_eq!(token.media, None); let attachments_bytes = std::fs::read(PathBuf::from(image_str.clone())).unwrap(); let attachment_digest = hash_bytes_hex(&attachments_bytes[..]); - let attachment_path = wallet + let attachment_path = party + .wallet .get_wallet_dir() .join(MEDIA_DIR) .join(&attachment_digest); @@ -181,24 +162,16 @@ fn success() { fn no_issue_on_pending_send() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); // prepare UTXO - test_create_utxos( - &mut wallet, - online, - true, - Some(1), - Some(5000), - FEE_RATE, - None, - ); + party.create_utxos(true, Some(1), Some(5000), FEE_RATE, None); // issue 1st asset - let asset_1 = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); + let asset_1 = party.issue_asset_uda(None, None, vec![]); // get 1st issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_1 = unspents .iter() .find(|u| { @@ -208,7 +181,7 @@ fn no_issue_on_pending_send() { }) .unwrap(); // send 1st asset - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -221,19 +194,19 @@ fn no_issue_on_pending_send() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // issuing a 2nd asset fails due to missing free allocation slot - let result = test_issue_asset_uda_result(&mut wallet, online, None, None, vec![]); + let result = party.issue_asset_uda_result(None, None, vec![]); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // create 1 more UTXO issue 2nd asset - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let asset_2 = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); - show_unspent_colorings(&mut wallet, "after 2nd issuance"); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let asset_2 = party.issue_asset_uda(None, None, vec![]); + party.show_unspent_colorings("after 2nd issuance"); // get 2nd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_2 = unspents .iter() .find(|u| { @@ -246,14 +219,14 @@ fn no_issue_on_pending_send() { assert_ne!(unspent_1.utxo.outpoint, unspent_2.utxo.outpoint); // progress transfer to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); // issue 3rd asset - let asset_3 = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); - show_unspent_colorings(&mut wallet, "after 3rd issuance"); + let asset_3 = party.issue_asset_uda(None, None, vec![]); + party.show_unspent_colorings("after 3rd issuance"); // get 3rd issuance UTXO - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspent_3 = unspents .iter() .find(|u| { @@ -279,14 +252,17 @@ fn fail() { let empty_str = empty_path.path().to_str().unwrap().to_string(); // wallet - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // invalid ticker: empty - let result = wallet.issue_asset_uda(s!(""), NAME.to_string(), None, PRECISION, None, vec![]); + let result = + party + .wallet + .issue_asset_uda(s!(""), NAME.to_string(), None, PRECISION, None, vec![]); assert!(matches!(result, Err(Error::InvalidTicker { details: m }) if m == EMPTY_MSG)); // invalid ticker: too long - let result = wallet.issue_asset_uda( + let result = party.wallet.issue_asset_uda( s!("ABCDEFGHI"), NAME.to_string(), None, @@ -297,7 +273,7 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidTicker { details: m }) if m == IDENT_TOO_LONG_MSG)); // invalid ticker: lowercase - let result = wallet.issue_asset_uda( + let result = party.wallet.issue_asset_uda( s!("TiCkEr"), NAME.to_string(), None, @@ -311,7 +287,7 @@ fn fail() { // invalid ticker: unicode characters let invalid_ticker = "TICKER WITH ℧NICODE CHARACTERS"; - let result = wallet.issue_asset_uda( + let result = party.wallet.issue_asset_uda( invalid_ticker.to_string(), NAME.to_string(), None, @@ -326,7 +302,7 @@ fn fail() { // invalid ticker: starting with a number let invalid_ticker = "1TICKER"; - let result = wallet.issue_asset_uda( + let result = party.wallet.issue_asset_uda( invalid_ticker.to_string(), NAME.to_string(), None, @@ -340,11 +316,14 @@ fn fail() { ); // invalid name: empty - let result = wallet.issue_asset_uda(TICKER.to_string(), s!(""), None, PRECISION, None, vec![]); + let result = + party + .wallet + .issue_asset_uda(TICKER.to_string(), s!(""), None, PRECISION, None, vec![]); assert!(matches!(result, Err(Error::InvalidName { details: m }) if m == EMPTY_MSG)); // invalid name: too long - let result = wallet.issue_asset_uda( + let result = party.wallet.issue_asset_uda( TICKER.to_string(), ("a").repeat(257), None, @@ -356,7 +335,7 @@ fn fail() { // invalid name: unicode characters let invalid_name = "name with ℧nicode characters"; - let result = wallet.issue_asset_uda( + let result = party.wallet.issue_asset_uda( TICKER.to_string(), invalid_name.to_string(), None, @@ -370,50 +349,50 @@ fn fail() { ); // invalid details - let result = test_issue_asset_uda_result(&mut wallet, online, Some(""), None, vec![]); + let result = party.issue_asset_uda_result(Some(""), None, vec![]); assert!(matches!(result, Err(Error::InvalidDetails { details: m }) if m == IDENT_EMPTY_MSG)); // invalid precision let result = - wallet.issue_asset_uda(TICKER.to_string(), NAME.to_string(), None, 19, None, vec![]); + party + .wallet + .issue_asset_uda(TICKER.to_string(), NAME.to_string(), None, 19, None, vec![]); assert!( matches!(result, Err(Error::InvalidPrecision { details: m }) if m == "precision is too high") ); // invalid media: missing - let result = test_issue_asset_uda_result(&mut wallet, online, None, Some(missing_str), vec![]); + let result = party.issue_asset_uda_result(None, Some(missing_str), vec![]); assert!(matches!(result, Err(Error::InvalidFilePath { file_path: m }) if m == missing_str)); // invalid media: empty - let result = test_issue_asset_uda_result(&mut wallet, online, None, Some(&empty_str), vec![]); + let result = party.issue_asset_uda_result(None, Some(&empty_str), vec![]); assert!(matches!(result, Err(Error::EmptyFile { file_path: m }) if m == empty_str)); // invalid attachment: missing - let result = test_issue_asset_uda_result(&mut wallet, online, None, None, vec![missing_str]); + let result = party.issue_asset_uda_result(None, None, vec![missing_str]); assert!(matches!(result, Err(Error::InvalidFilePath { file_path: m }) if m == missing_str)); // invalid attachment: empty - let result = test_issue_asset_uda_result(&mut wallet, online, None, None, vec![&empty_str]); + let result = party.issue_asset_uda_result(None, None, vec![&empty_str]); assert!(matches!(result, Err(Error::EmptyFile { file_path: m }) if m == empty_str)); // new wallet - let (mut wallet, online) = get_empty_wallet!(); + let mut empty_party = get_empty_party!(); // insufficient funds - let result = test_issue_asset_uda_result(&mut wallet, online, None, None, vec![]); + let result = empty_party.issue_asset_uda_result(None, None, vec![]); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(empty_party.get_address()); mine(false); // insufficient allocations - let result = test_issue_asset_uda_result(&mut wallet, online, None, None, vec![]); + let result = empty_party.issue_asset_uda_result(None, None, vec![]); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // too many attachments - let result = test_issue_asset_uda_result( - &mut wallet, - online, + let result = empty_party.issue_asset_uda_result( None, None, [attachment_str.clone()] diff --git a/src/wallet/test/list_assets.rs b/src/wallet/test/list_assets.rs index 847fa594..52b382a4 100644 --- a/src/wallet/test/list_assets.rs +++ b/src/wallet/test/list_assets.rs @@ -6,16 +6,12 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // no assets - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let assets = test_list_assets(&wallet, &[]); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let assets = party.list_assets(&[]); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -23,8 +19,8 @@ fn success() { assert_eq!(assets.nia.unwrap().len(), 0); // one issued NIA asset - let asset_1 = test_issue_asset_nia(&mut wallet, online, None); - let assets = test_list_assets(&wallet, &[]); + let asset_1 = party.issue_asset_nia(None); + let assets = party.list_assets(&[]); let nia_assets = assets.nia.unwrap(); let cfa_assets = assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 1); @@ -44,10 +40,11 @@ fn success() { ); // two issued NIA assets - let asset_2 = wallet + let asset_2 = party + .wallet .issue_asset_nia(s!("TICKER2"), s!("NAME2"), PRECISION * 2, vec![AMOUNT * 2]) .unwrap(); - let assets = test_list_assets(&wallet, &[]); + let assets = party.list_assets(&[]); let nia_assets = assets.nia.unwrap(); let cfa_assets = assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 2); @@ -67,8 +64,8 @@ fn success() { ); // three issued assets: 2x NIA + 1x CFA - let asset_3 = test_issue_asset_cfa(&mut wallet, online, Some(&[AMOUNT * 3]), None); - let assets = test_list_assets(&wallet, &[]); + let asset_3 = party.issue_asset_cfa(Some(&[AMOUNT * 3]), None); + let assets = party.list_assets(&[]); let nia_assets = assets.nia.unwrap(); let cfa_assets = assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 2); @@ -89,11 +86,11 @@ fn success() { assert_eq!(asset.media, None); // test filter by asset type - let assets = test_list_assets(&wallet, &[AssetSchema::Nia]); + let assets = party.list_assets(&[AssetSchema::Nia]); assert_eq!(assets.nia.unwrap().len(), 2); assert!(assets.cfa.is_none()); - let assets = test_list_assets(&wallet, &[AssetSchema::Cfa]); + let assets = party.list_assets(&[AssetSchema::Cfa]); assert!(assets.nia.is_none()); assert_eq!(assets.cfa.unwrap().len(), 1); } diff --git a/src/wallet/test/list_pending_vanilla_txs.rs b/src/wallet/test/list_pending_vanilla_txs.rs index 9bb6b984..416a6806 100644 --- a/src/wallet/test/list_pending_vanilla_txs.rs +++ b/src/wallet/test/list_pending_vanilla_txs.rs @@ -6,20 +6,21 @@ use super::*; fn success() { initialize(); - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); for _ in 0..3 { - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); } - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut rcv_party = get_empty_party!(); // empty to start - assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); + assert!(party.wallet.list_pending_vanilla_txs().unwrap().is_empty()); // one send_btc_begin(dry_run=false) creates a SendBtc pending entry - let send_psbt_str = wallet + let send_psbt_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), 1000, FEE_RATE, false, @@ -28,19 +29,20 @@ fn success() { .unwrap(); let send_psbt = Psbt::from_str(&send_psbt_str).unwrap(); let send_txid = send_psbt.unsigned_tx.compute_txid().to_string(); - let pending = wallet.list_pending_vanilla_txs().unwrap(); + let pending = party.wallet.list_pending_vanilla_txs().unwrap(); assert_eq!(pending.len(), 1); assert_eq!(pending[0].txid, send_txid); assert_eq!(pending[0].r#type, WalletTransactionType::SendBtc); // a concurrent create_utxos_begin(dry_run=false) adds a second pending entry // with CreateUtxos type - let create_psbt_str = wallet - .create_utxos_begin(online, false, Some(1), None, FEE_RATE, true, false) + let create_psbt_str = party + .wallet + .create_utxos_begin(party.online, false, Some(1), None, FEE_RATE, true, false) .unwrap(); let create_psbt = Psbt::from_str(&create_psbt_str).unwrap(); let create_txid = create_psbt.unsigned_tx.compute_txid().to_string(); - let pending = wallet.list_pending_vanilla_txs().unwrap(); + let pending = party.wallet.list_pending_vanilla_txs().unwrap(); assert_eq!(pending.len(), 2); assert!( pending @@ -54,9 +56,9 @@ fn success() { ); // completing the send_btc drops it from the list - let signed = wallet.sign_psbt(send_psbt_str, None).unwrap(); - let _ = wallet.send_btc_end(online, signed).unwrap(); - let pending = wallet.list_pending_vanilla_txs().unwrap(); + let signed = party.wallet.sign_psbt(send_psbt_str, None).unwrap(); + let _ = party.wallet.send_btc_end(party.online, signed).unwrap(); + let pending = party.wallet.list_pending_vanilla_txs().unwrap(); assert_eq!(pending.len(), 1); assert_eq!(pending[0].r#type, WalletTransactionType::CreateUtxos); assert_eq!(pending[0].txid, create_txid); diff --git a/src/wallet/test/list_transactions.rs b/src/wallet/test/list_transactions.rs index 4d223c2a..1c31272c 100644 --- a/src/wallet/test/list_transactions.rs +++ b/src/wallet/test/list_transactions.rs @@ -9,29 +9,25 @@ fn success() { let amount: u64 = 66; let _guard = stop_mining_when_alone(); - let (mut wallet, online) = get_empty_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_empty_party!(); + let mut rcv_party = get_empty_party!(); - send_to_address(test_get_address(&mut wallet)); - send_to_address(test_get_address(&mut rcv_wallet)); + send_to_address(party.get_address()); + send_to_address(rcv_party.get_address()); force_mine_no_resume_when_alone(false); - test_create_utxos_default(&mut wallet, online); - test_create_utxos_default(&mut rcv_wallet, rcv_online); + party.create_utxos_default(); + rcv_party.create_utxos_default(); force_mine_no_resume_when_alone(false); // don't sync wallet without online - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let transactions = test_list_transactions(&mut wallet, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let transactions = party.list_transactions(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); - let rcv_transactions = test_list_transactions(&mut wallet, None); + let rcv_transactions = party.list_transactions(); assert_eq!(transactions.len(), 2); assert_eq!(rcv_transactions.len(), 2); assert!( @@ -62,8 +58,8 @@ fn success() { ); // sync wallet when online is provided drop(_guard); - let transactions = test_list_transactions(&mut wallet, Some(online)); - let rcv_transactions = test_list_transactions(&mut rcv_wallet, Some(rcv_online)); + let transactions = party.list_transactions_with_sync(); + let rcv_transactions = rcv_party.list_transactions_with_sync(); assert!(transactions.iter().all(|t| t.confirmation_time.is_some())); assert!( rcv_transactions @@ -71,8 +67,8 @@ fn success() { .all(|t| t.confirmation_time.is_some()) ); - let asset = test_issue_asset_nia(&mut wallet, online, None); - let receive_data = test_witness_receive(&mut rcv_wallet); + let asset = party.issue_asset_nia(None); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id, vec![Recipient { @@ -85,15 +81,15 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - test_send(&mut wallet, online, &recipient_map); + party.send_retry(&recipient_map); // settle the transfer so the tx gets broadcasted and receiver sees the new UTXO - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); - let transactions = test_list_transactions(&mut wallet, Some(online)); - let rcv_transactions = test_list_transactions(&mut rcv_wallet, Some(rcv_online)); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); + let transactions = party.list_transactions_with_sync(); + let rcv_transactions = rcv_party.list_transactions_with_sync(); assert_eq!(transactions.len(), 3); assert_eq!(rcv_transactions.len(), 3); assert!( @@ -113,9 +109,9 @@ fn success() { .all(|t| t.confirmation_time.is_some()) ); - drain_wallet(&mut wallet, online); + party.drain_wallet(); mine(false); - let transactions = test_list_transactions(&mut wallet, Some(online)); + let transactions = party.list_transactions_with_sync(); assert_eq!(transactions.len(), 4); assert!( transactions @@ -134,20 +130,21 @@ fn skip_sync() { let check_timeout = 10; let check_interval = 1000; - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); - send_to_address(test_get_address(&mut wallet)); + send_to_address(party.get_address()); // transaction list doesn't report the TX if sync is skipped - let transactions = test_list_transactions(&mut wallet, None); + let transactions = party.list_transactions(); assert_eq!(transactions.len(), 0); // transaction list reports the TX after manually syncing assert!(wait_for_function( || { - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -156,7 +153,7 @@ fn skip_sync() { }, ) .unwrap(); - let transactions = test_list_transactions(&mut wallet, None); + let transactions = party.list_transactions(); transactions.len() == 1 }, check_timeout, diff --git a/src/wallet/test/list_transfers.rs b/src/wallet/test/list_transfers.rs index 5508d568..da3e9ab9 100644 --- a/src/wallet/test/list_transfers.rs +++ b/src/wallet/test/list_transfers.rs @@ -9,20 +9,16 @@ fn success() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue NIA asset - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // single transfer (issuance) - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let transfer_list = test_list_transfers(&wallet, Some(&asset.asset_id)); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let transfer_list = party.list_transfers(Some(&asset.asset_id)); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp @@ -34,13 +30,13 @@ fn success() { assert_eq!(transfer.status, TransferStatus::Settled); // new wallet - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // issue CFA asset - let asset = test_issue_asset_cfa(&mut wallet, online, None, None); + let asset = party.issue_asset_cfa(None, None); // single transfer (issuance) - let transfer_list = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfer_list = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfer_list.len(), 1); let transfer = transfer_list.first().unwrap(); assert_eq!(transfer.requested_assignment, None,); @@ -48,8 +44,8 @@ fn success() { assert_eq!(transfer.status, TransferStatus::Settled); // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); - let receive_data_2 = test_witness_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); + let receive_data_2 = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -70,11 +66,11 @@ fn success() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // multiple transfers (sender) - let transfer_list = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfer_list = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfer_list.len(), 3); let transfer_send_1 = transfer_list .iter() @@ -112,11 +108,11 @@ fn success() { assert_eq!(transfer_send_2.txid, Some(txid.clone())); // refresh once, so the asset appears on the receiver side - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // multiple transfers (receiver) - let transfer_list_rcv = test_list_transfers(&rcv_wallet, Some(&asset.asset_id)); + let transfer_list_rcv = rcv_party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfer_list_rcv.len(), 2); let transfer_recv_blind = transfer_list_rcv .iter() @@ -155,12 +151,12 @@ fn success() { // refresh a second time to settle the transfers mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // check all transfers are now in status Settled - let transfer_list = test_list_transfers(&wallet, Some(&asset.asset_id)); - let transfer_list_rcv = test_list_transfers(&rcv_wallet, Some(&asset.asset_id)); + let transfer_list = party.list_transfers(Some(&asset.asset_id)); + let transfer_list_rcv = rcv_party.list_transfers(Some(&asset.asset_id)); assert!( transfer_list .iter() @@ -176,9 +172,9 @@ fn success() { #[test] #[parallel] fn fail() { - let wallet = get_test_wallet(false, None); + let party = offline_party!(get_test_wallet(false, None)); // asset not found - let result = test_list_transfers_result(&wallet, Some("rgb1inexistent")); + let result = party.list_transfers_result(Some("rgb1inexistent")); assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ }))); } diff --git a/src/wallet/test/list_unspents.rs b/src/wallet/test/list_unspents.rs index 7c94c8c8..cd141dbe 100644 --- a/src/wallet/test/list_unspents.rs +++ b/src/wallet/test/list_unspents.rs @@ -9,40 +9,36 @@ fn success() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_empty_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_empty_party!(); + let mut rcv_party = get_funded_party!(); // no unspents - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info_opt(); assert!(bak_info_before.is_none()); - let unspent_list_settled = test_list_unspents(&mut wallet, None, true); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let unspent_list_settled = party.list_unspents(true); + let bak_info_after = party.db_backup_info_opt(); assert!(bak_info_after.is_none()); assert_eq!(unspent_list_settled.len(), 0); - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + let unspent_list_all = party.list_unspents(false); assert_eq!(unspent_list_all.len(), 0); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); mine(false); // one unspent, no RGB allocations - let unspent_list_settled = test_list_unspents(&mut wallet, Some(online), true); + let unspent_list_settled = party.list_unspents_with_sync(true); assert_eq!(unspent_list_settled.len(), 1); - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + let unspent_list_all = party.list_unspents(false); assert_eq!(unspent_list_all.len(), 1); assert!(unspent_list_all.iter().all(|u| !u.utxo.colorable)); - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); // multiple unspents, one settled RGB allocation - let asset = test_issue_asset_nia(&mut wallet, online, None); - let unspent_list_settled = test_list_unspents(&mut wallet, None, true); + let asset = party.issue_asset_nia(None); + let unspent_list_settled = party.list_unspents(true); assert_eq!(unspent_list_settled.len(), UTXO_NUM as usize + 1); - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + let unspent_list_all = party.list_unspents(false); assert_eq!(unspent_list_all.len(), UTXO_NUM as usize + 1); assert_eq!( unspent_list_all.iter().filter(|u| u.utxo.colorable).count(), @@ -73,21 +69,17 @@ fn success() { ); // multiple unspents, one failed blind, not listed - let receive_data_fail = test_blind_receive(&mut rcv_wallet); - test_fail_transfers_single( - &mut rcv_wallet, - rcv_online, - receive_data_fail.batch_transfer_idx, - ); - show_unspent_colorings(&mut rcv_wallet, "after blind fail"); - let unspent_list_all = test_list_unspents(&mut rcv_wallet, None, false); + let receive_data_fail = rcv_party.blind_receive(); + rcv_party.fail_transfers_single(receive_data_fail.batch_transfer_idx); + rcv_party.show_unspent_colorings("after blind fail"); + let unspent_list_all = rcv_party.list_unspents(false); let mut allocations = vec![]; unspent_list_all .iter() .for_each(|u| allocations.extend(u.rgb_allocations.clone())); assert_eq!(allocations.len(), 0); // one failed send, not listed - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -97,12 +89,12 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); let txid = send_result.txid; assert!(!txid.is_empty()); - test_fail_transfers_single(&mut wallet, online, send_result.batch_transfer_idx); - show_unspent_colorings(&mut wallet, "after send fail"); - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + party.fail_transfers_single(send_result.batch_transfer_idx); + party.show_unspent_colorings("after send fail"); + let unspent_list_all = party.list_unspents(false); assert_eq!( unspent_list_all .iter() @@ -142,12 +134,12 @@ fn success() { ); // new wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue + send some asset - let asset = test_issue_asset_nia(&mut wallet, online, None); - let receive_data = test_blind_receive(&mut rcv_wallet); + let asset = party.issue_asset_nia(None); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -157,19 +149,19 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut rcv_wallet, "receiver after send - WaitingCounterparty"); - show_unspent_colorings(&mut wallet, "sender after send - WaitingCounterparty"); + rcv_party.show_unspent_colorings("receiver after send - WaitingCounterparty"); + party.show_unspent_colorings("sender after send - WaitingCounterparty"); // check receiver lists no settled allocations - let rcv_unspent_list = test_list_unspents(&mut rcv_wallet, None, true); + let rcv_unspent_list = rcv_party.list_unspents(true); assert!( !rcv_unspent_list .iter() .any(|u| !u.rgb_allocations.is_empty()) ); // check receiver lists one pending blind - let rcv_unspent_list_all = test_list_unspents(&mut rcv_wallet, None, false); + let rcv_unspent_list_all = rcv_party.list_unspents(false); let mut allocations = vec![]; rcv_unspent_list_all .iter() @@ -190,7 +182,7 @@ fn success() { 1 ); // check sender lists one settled issue - let unspent_list_settled = test_list_unspents(&mut wallet, None, true); + let unspent_list_settled = party.list_unspents(true); let mut settled_allocations = vec![]; unspent_list_settled .iter() @@ -208,7 +200,7 @@ fn success() { && a.settled) ); // check sender lists one pending change (exists = false) + 1 settled issue - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + let unspent_list_all = party.list_unspents(false); assert_eq!( unspent_list_all .iter() @@ -262,22 +254,19 @@ fn success() { ); // transfer progresses to status WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - show_unspent_colorings( - &mut rcv_wallet, - "receiver after send - WaitingConfirmations", - ); - show_unspent_colorings(&mut wallet, "sender after send - WaitingConfirmations"); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + rcv_party.show_unspent_colorings("receiver after send - WaitingConfirmations"); + party.show_unspent_colorings("sender after send - WaitingConfirmations"); // check receiver lists no settled allocations - let rcv_unspent_list = test_list_unspents(&mut rcv_wallet, None, true); + let rcv_unspent_list = rcv_party.list_unspents(true); assert!( !rcv_unspent_list .iter() .any(|u| !u.rgb_allocations.is_empty()) ); // check receiver lists one pending blind - let rcv_unspent_list_all = test_list_unspents(&mut rcv_wallet, None, false); + let rcv_unspent_list_all = rcv_party.list_unspents(false); let mut allocations = vec![]; rcv_unspent_list_all .iter() @@ -296,7 +285,7 @@ fn success() { ); assert!(rcv_unspent_list_all.iter().all(|u| u.pending_blinded == 0)); // check sender lists one settled issue - let unspent_list_settled = test_list_unspents(&mut wallet, None, true); + let unspent_list_settled = party.list_unspents(true); let mut settled_allocations = vec![]; unspent_list_settled .iter() @@ -314,7 +303,7 @@ fn success() { && a.settled) ); // check sender lists one pending change (exists = true) - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + let unspent_list_all = party.list_unspents(false); let mut pending_allocations = vec![]; unspent_list_all .iter() @@ -340,12 +329,12 @@ fn success() { // transfer progresses to status Settled mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - show_unspent_colorings(&mut rcv_wallet, "receiver after send - Settled"); - show_unspent_colorings(&mut wallet, "sender after send - Settled"); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + rcv_party.show_unspent_colorings("receiver after send - Settled"); + party.show_unspent_colorings("sender after send - Settled"); // check receiver lists one settled allocation - let rcv_unspent_list = test_list_unspents(&mut rcv_wallet, None, true); + let rcv_unspent_list = rcv_party.list_unspents(true); let mut settled_allocations = vec![]; rcv_unspent_list .iter() @@ -363,14 +352,14 @@ fn success() { }) ); // check receiver lists no pending allocations - let rcv_unspent_list_all = test_list_unspents(&mut rcv_wallet, None, false); + let rcv_unspent_list_all = rcv_party.list_unspents(false); let mut allocations = vec![]; rcv_unspent_list_all .iter() .for_each(|u| allocations.extend(u.rgb_allocations.clone())); assert_eq!(allocations, settled_allocations); // check sender lists one settled change - let unspent_list_settled = test_list_unspents(&mut wallet, None, true); + let unspent_list_settled = party.list_unspents(true); let mut settled_allocations = vec![]; unspent_list_settled .iter() @@ -388,7 +377,7 @@ fn success() { && a.settled) ); // check sender lists no pending allocations - let unspent_list_all = test_list_unspents(&mut wallet, None, false); + let unspent_list_all = party.list_unspents(false); let mut allocations = vec![]; unspent_list_all .iter() @@ -402,18 +391,19 @@ fn success() { fn skip_sync() { initialize(); - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); // no unspents if skipping sync - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 0); // 1 unspent after manually syncing - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -422,6 +412,6 @@ fn skip_sync() { }, ) .unwrap(); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 1); } diff --git a/src/wallet/test/mod.rs b/src/wallet/test/mod.rs index 20c9413d..63169363 100644 --- a/src/wallet/test/mod.rs +++ b/src/wallet/test/mod.rs @@ -123,7 +123,7 @@ pub fn initialize() { } pub fn restart_multisig_hub() { - let serivce_name = "rgb-multisig-hub"; + let service_name = "rgb-multisig-hub"; let cmd_base = vec![s!("-f"), ["tests", "compose.yaml"].join(MAIN_SEPARATOR_STR)]; let mut cmd = cmd_base.clone(); cmd.extend([ @@ -131,7 +131,7 @@ pub fn restart_multisig_hub() { s!("-f"), s!("-s"), s!("-v"), - serivce_name.to_string(), + service_name.to_string(), ]); Command::new("docker") .stdin(Stdio::null()) @@ -151,7 +151,7 @@ pub fn restart_multisig_hub() { .output() .expect("failed to remove hub volume"); let mut cmd = cmd_base.clone(); - cmd.extend([s!("up"), s!("-d"), serivce_name.to_string()]); + cmd.extend([s!("up"), s!("-d"), service_name.to_string()]); Command::new("docker") .stdin(Stdio::null()) .stderr(Stdio::null()) @@ -164,32 +164,32 @@ pub fn restart_multisig_hub() { // the get_*_wallet! macros can be called with no arguments to use defaults #[cfg(any(feature = "electrum", feature = "esplora"))] -macro_rules! get_empty_wallet { +macro_rules! get_empty_party { ($i: expr) => { - get_empty_wallet(true, Some($i)) + get_empty_party(true, Some($i)) }; () => { - get_empty_wallet(true, None) + get_empty_party(true, None) }; } #[cfg(any(feature = "electrum", feature = "esplora"))] -macro_rules! get_funded_noutxo_wallet { +macro_rules! get_funded_noutxo_party { ($i: expr) => { - get_funded_noutxo_wallet(true, Some($i)) + get_funded_noutxo_party(true, Some($i)) }; () => { - get_funded_noutxo_wallet(true, None) + get_funded_noutxo_party(true, None) }; } #[cfg(any(feature = "electrum", feature = "esplora"))] -macro_rules! get_funded_wallet { +macro_rules! get_funded_party { ($i: expr) => { - get_funded_wallet(true, Some($i)) + get_funded_party(true, Some($i)) }; () => { - get_funded_wallet(true, None) + get_funded_party(true, None) }; } @@ -297,6 +297,7 @@ pub fn mock_vout(vout: Option) -> Option { } // test utilities +#[macro_use] mod utils; pub(crate) use utils::{api::*, chain::*, helpers::*}; diff --git a/src/wallet/test/multisig/mod.rs b/src/wallet/test/multisig/mod.rs index 82a79aa3..b5c9e4e4 100644 --- a/src/wallet/test/multisig/mod.rs +++ b/src/wallet/test/multisig/mod.rs @@ -222,11 +222,7 @@ fn success() { true, ); check_last_transaction( - &mut [ - wlt_1.multisig_mut(), - wlt_2.multisig_mut(), - wlt_3.multisig_mut(), - ], + &mut [&mut wlt_1, &mut wlt_2, &mut wlt_3], &op_init.psbt, &TransactionType::CreateUtxos, ); @@ -276,13 +272,12 @@ fn success() { unreachable!() }; - let (mut singlesig_wlt, singlesig_wlt_online) = get_funded_wallet!(); - let mut singlesig_wlt = party!(&mut singlesig_wlt, singlesig_wlt_online); + let mut singlesig_wlt = get_funded_party!(); println!("\n=== send UDA (wlt_1 → singlesig) ==="); sync_wallets_full(&mut [&mut wlt_4]); check_wallets_up_to_date(&mut [&mut wlt_1, &mut wlt_2, &mut wlt_3, &mut wlt_4]); - let rcv_data = test_blind_receive(singlesig_wlt.wallet); + let rcv_data = singlesig_wlt.blind_receive(); let recipient_map = HashMap::from([( uda_asset.asset_id.clone(), vec![Recipient { @@ -312,12 +307,13 @@ fn success() { true, ); check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - &singlesig_wlt as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], + &[Some(&uda_asset.asset_id)], + None, + TransferStatus::Settled, + ); + check_transfer_status( + &[&singlesig_wlt], &[Some(&uda_asset.asset_id)], None, TransferStatus::Settled, @@ -342,7 +338,7 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(singlesig_wlt.wallet, singlesig_wlt.online, &recipient_map); + let txid = singlesig_wlt.send_retry(&recipient_map); settle_transfer( &mut [&mut singlesig_wlt], &mut [&mut wlt_1, &mut wlt_2, &mut wlt_3], @@ -352,12 +348,13 @@ fn success() { true, ); check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - &singlesig_wlt as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], + &[Some(&uda_asset.asset_id)], + None, + TransferStatus::Settled, + ); + check_transfer_status( + &[&singlesig_wlt], &[Some(&uda_asset.asset_id)], None, TransferStatus::Settled, @@ -366,9 +363,9 @@ fn success() { check_asset_balance(&[&singlesig_wlt], &uda_asset.asset_id, (0, 0, 0)); println!("\n=== send RGB discarded (wlt_1 → singlesig) ==="); - let rcv_data_1 = test_witness_receive(singlesig_wlt.wallet); - let rcv_data_2 = test_blind_receive(singlesig_wlt.wallet); - let rcv_data_3 = test_blind_receive(singlesig_wlt.wallet); + let rcv_data_1 = singlesig_wlt.witness_receive(); + let rcv_data_2 = singlesig_wlt.blind_receive(); + let rcv_data_3 = singlesig_wlt.blind_receive(); let cfa_amount_witness = AMOUNT_SMALL; let cfa_amount_blind = 20; let recipient_map = HashMap::from([ @@ -412,7 +409,7 @@ fn success() { ); println!("\n=== blind receive new asset (singlesig → wlt_1) ==="); - let nia_asset_2 = test_issue_asset_nia(singlesig_wlt.wallet, singlesig_wlt.online, None); + let nia_asset_2 = singlesig_wlt.issue_asset_nia(None); let receive_data = wlt_1.blind_receive(); sync_wallets_full(&mut [&mut wlt_2, &mut wlt_3]); let recipient_map = HashMap::from([( @@ -424,7 +421,7 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(singlesig_wlt.wallet, singlesig_wlt.online, &recipient_map); + let txid = singlesig_wlt.send_retry(&recipient_map); settle_transfer( &mut [&mut singlesig_wlt], &mut [&mut wlt_1, &mut wlt_2, &mut wlt_3], @@ -434,12 +431,13 @@ fn success() { true, ); check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - &singlesig_wlt as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], + &[Some(&uda_asset.asset_id)], + None, + TransferStatus::Settled, + ); + check_transfer_status( + &[&singlesig_wlt], &[Some(&uda_asset.asset_id)], None, TransferStatus::Settled, @@ -457,10 +455,10 @@ fn success() { ); println!("\n=== send RGB (wlt_1 → singlesig) ==="); - let rcv_data_1 = test_witness_receive(singlesig_wlt.wallet); - let rcv_data_2 = test_blind_receive(singlesig_wlt.wallet); - let rcv_data_3 = test_blind_receive(singlesig_wlt.wallet); - let rcv_data_4 = test_blind_receive(singlesig_wlt.wallet); + let rcv_data_1 = singlesig_wlt.witness_receive(); + let rcv_data_2 = singlesig_wlt.blind_receive(); + let rcv_data_3 = singlesig_wlt.blind_receive(); + let rcv_data_4 = singlesig_wlt.blind_receive(); let cfa_amount_witness = AMOUNT_SMALL; let cfa_amount_blind = 20; let nia_2_amount = 30; @@ -531,12 +529,17 @@ fn success() { true, ); check_transfer_status( + &[&wlt_1, &wlt_2, &wlt_3], &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - &singlesig_wlt as &dyn SigParty, + Some(&cfa_asset.asset_id), + Some(&nia_asset_1.asset_id), + Some(&nia_asset_2.asset_id), ], + None, + TransferStatus::Settled, + ); + check_transfer_status( + &[&singlesig_wlt], &[ Some(&cfa_asset.asset_id), Some(&nia_asset_1.asset_id), @@ -578,7 +581,7 @@ fn success() { (uda_asset.asset_id.as_str(), (1, 1, 1, 3, TransferStatus::Settled)), ]); check_wallet_state( - wlt_1.multisig_mut(), + &mut wlt_1, &op_init_last_before_backup, &op_init_last_before_backup, btc_pre_backup_vanilla, @@ -607,7 +610,7 @@ fn success() { ); assert!(unspents_nia_asset_2.next().is_none()); // send the assets - let rcv_data = test_blind_receive(singlesig_wlt.wallet); + let rcv_data = singlesig_wlt.blind_receive(); let recipient_map = HashMap::from([( nia_asset_2.asset_id.clone(), vec![Recipient { @@ -634,12 +637,13 @@ fn success() { true, ); check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - &singlesig_wlt as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], + &[Some(&nia_asset_2.asset_id)], + None, + TransferStatus::Settled, + ); + check_transfer_status( + &[&singlesig_wlt], &[Some(&nia_asset_2.asset_id)], None, TransferStatus::Settled, @@ -755,7 +759,7 @@ fn success() { println!("\n=== send BTC (wlt_1 → singlesig) ==="); check_wallets_up_to_date(&mut [&mut wlt_1, &mut wlt_2, &mut wlt_3]); let amount = 1000; - let addr = test_get_address(singlesig_wlt.wallet); + let addr = singlesig_wlt.get_address(); let op_init = wlt_1.send_btc_init(&addr, amount); operation_complete::( op_init.operation_idx, @@ -765,20 +769,12 @@ fn success() { true, ); check_last_transaction( - &mut [ - wlt_1.multisig_mut(), - wlt_2.multisig_mut(), - wlt_3.multisig_mut(), - ], + &mut [&mut wlt_1, &mut wlt_2, &mut wlt_3], &op_init.psbt, &TransactionType::SendBtc, ); check_btc_balance( - &mut [ - wlt_1.multisig_mut(), - wlt_2.multisig_mut(), - wlt_3.multisig_mut(), - ], + &mut [&mut wlt_1, &mut wlt_2, &mut wlt_3], (0, 6442, 6442), (15366, 15366, 15366), ); @@ -797,18 +793,14 @@ fn success() { .unwrap(); sync_wallets_full(&mut [&mut wlt_2, &mut wlt_3]); check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], &[None], Some(receive_data.batch_transfer_idx), TransferStatus::Failed, ); println!("\n=== send failed (wlt_1) ==="); - let receive_data = test_blind_receive(singlesig_wlt.wallet); + let receive_data = singlesig_wlt.blind_receive(); let recipient_map = HashMap::from([( nia_asset_2.asset_id.clone(), vec![Recipient { @@ -827,11 +819,7 @@ fn success() { true, ); check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], &[Some(&nia_asset_2.asset_id)], None, TransferStatus::WaitingCounterparty, @@ -848,14 +836,10 @@ fn success() { ) .unwrap(); for wallet in [&mut wlt_2, &mut wlt_3] { - wallet.refresh(Some(&nia_asset_2.asset_id)); + wallet.wait_for_refresh(Some(&nia_asset_2.asset_id)); } check_transfer_status( - &[ - &wlt_1 as &dyn SigParty, - &wlt_2 as &dyn SigParty, - &wlt_3 as &dyn SigParty, - ], + &[&wlt_1, &wlt_2, &wlt_3], &[Some(&nia_asset_2.asset_id)], None, TransferStatus::Failed, @@ -888,7 +872,7 @@ fn success() { sync_wallets_full(&mut [&mut wlt_4]); check_wallets_up_to_date(&mut [&mut wlt_4]); check_wallet_state( - wlt_4.multisig_mut(), + &mut wlt_4, &op_init_last_successful, &op_init, btc_final_vanilla, @@ -901,7 +885,7 @@ fn success() { println!("\n=== watch-only sync ==="); watch_only_wallet_sync(&mut wlt_wo); check_wallet_state( - wlt_wo.multisig_mut(), + &mut wlt_wo, &op_init_last_successful, &op_init, btc_final_vanilla, @@ -922,7 +906,7 @@ fn success() { ); // post-restore checks check_wallet_state( - wlt_restored.multisig_mut(), + &mut wlt_restored, &op_init_last_before_backup, &op_init_last_before_backup, btc_pre_backup_vanilla, @@ -933,7 +917,7 @@ fn success() { // sync and check it aligns with other cosigners wlt_restored.sync_to_head(); check_wallet_state( - wlt_restored.multisig_mut(), + &mut wlt_restored, &op_init_last_successful, &op_init, btc_final_vanilla, @@ -1222,19 +1206,10 @@ fn fail() { let signed_psbt = wlt_2_singlesig .sign_psbt(unsigned_psbt.clone(), None) .unwrap(); - let txn = wlt_2.multisig.database().begin_transaction().unwrap(); - wlt_2 - .multisig_mut() - .sync_wallet( - &txn, - SyncOptions { - keychain: SyncKeychain::Colored, - strategy: SyncStrategy::FastSync, - }, - false, - ) - .unwrap(); - txn.commit().unwrap(); + wlt_2.sync(SyncOptions { + keychain: SyncKeychain::Colored, + strategy: SyncStrategy::FastSync, + }); wlt_2.respond_to_operation(op_idx_1, RespondToOperation::Ack(signed_psbt.clone())); let err = wlt_3 .respond_to_operation_res(op_idx_1, RespondToOperation::Nack) @@ -1245,7 +1220,7 @@ fn fail() { ); // respond with PSBT for the wrong operation (wrong TXID) - wlt_1.sync(); + wlt_1.sync_with_hub(); wlt_2.assert_up_to_date(); let op_init = wlt_1.create_utxos_init(false, Some(5), None, FEE_RATE); let op_idx_2 = op_init.operation_idx; @@ -1269,7 +1244,7 @@ fn fail() { // respond to an operation that's not the next one wlt_2.respond_to_operation(op_idx_2, RespondToOperation::Nack); - wlt_1.sync(); + wlt_1.sync_with_hub(); wlt_2.assert_up_to_date(); let op_init = wlt_1.create_utxos_init(false, Some(3), None, FEE_RATE); let op_idx_3 = op_init.operation_idx; diff --git a/src/wallet/test/multisig/utils.rs b/src/wallet/test/multisig/utils.rs index 7ac5b044..2d69db7a 100644 --- a/src/wallet/test/multisig/utils.rs +++ b/src/wallet/test/multisig/utils.rs @@ -201,11 +201,6 @@ fn sanitize_meta(meta: &mut Metadata) { // ---------------------------------------- // singlesig party (allows uniform access to some functionality via SigParty trait) -pub(super) struct SinglesigParty<'a> { - pub(super) wallet: &'a mut Wallet, - pub(super) online: Online, -} - // multisig party to be used for cosigners pub(super) struct MultisigParty<'a> { pub(super) signer: &'a Wallet, @@ -231,10 +226,7 @@ impl<'a> MultisigParty<'a> { } fn sign_and_ack(&mut self, psbt: &str, op_idx: i32) -> OperationInfo { - println!( - "sign and ack {op_idx} {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("sign and ack {op_idx} {}", self.data_dir()); let signed = self.sign(psbt); self.ack(&signed, op_idx) } @@ -259,61 +251,34 @@ macro_rules! ms_party { } // convenience macro to instantiate SinglesigParty -macro_rules! party { - ($wallet:expr, $online:expr) => { - SinglesigParty { - wallet: $wallet, - online: $online, - } - }; -} - // convenience trait to allow uniform access to common functionality from all parties -pub(super) trait SigParty { - fn get_asset_balance(&self, asset_id: &str) -> Balance; - - fn list_transfers(&self, asset_id: Option<&str>) -> Vec; - - fn refresh(&mut self, asset_id: Option<&str>); - - fn get_data_dir(&self) -> String; -} +impl OfflineSigParty for MultisigParty<'_> { + type W = MultisigWallet; -impl SigParty for MultisigParty<'_> { - fn get_asset_balance(&self, asset_id: &str) -> Balance { + fn wlt(&self) -> &MultisigWallet { self.multisig - .get_asset_balance(asset_id.to_string()) - .unwrap() - } - - fn list_transfers(&self, asset_id: Option<&str>) -> Vec { - test_list_transfers(self.multisig, asset_id) - } - - fn refresh(&mut self, asset_id: Option<&str>) { - wait_for_refresh(self.multisig, self.online, asset_id, None); } - fn get_data_dir(&self) -> String { - self.multisig.internals.wallet_data.data_dir.clone() + fn wlt_mut(&mut self) -> &mut MultisigWallet { + self.multisig } } -impl SigParty for SinglesigParty<'_> { - fn get_asset_balance(&self, asset_id: &str) -> Balance { - self.wallet.get_asset_balance(asset_id.to_string()).unwrap() +impl SigParty for MultisigParty<'_> { + fn party_online(&self) -> Online { + self.online } +} - fn list_transfers(&self, asset_id: Option<&str>) -> Vec { - test_list_transfers(self.wallet, asset_id) - } +impl OfflineSigParty for WatchOnlyParty<'_> { + type W = MultisigWallet; - fn refresh(&mut self, asset_id: Option<&str>) { - wait_for_refresh(self.wallet, self.online, asset_id, None); + fn wlt(&self) -> &MultisigWallet { + self.multisig } - fn get_data_dir(&self) -> String { - self.wallet.internals.wallet_data.data_dir.clone() + fn wlt_mut(&mut self) -> &mut MultisigWallet { + self.multisig } } @@ -334,10 +299,7 @@ pub(super) fn get_test_ms_wallet(keys: &MultisigKeys, dir: String) -> MultisigWa keys.clone(), ) .unwrap(); - println!( - "multisig wallet directory: {:?}", - test_get_wallet_dir(&wallet) - ); + println!("multisig wallet directory: {:?}", wallet.get_wallet_dir()); wallet } @@ -385,17 +347,14 @@ fn local_rgb_lib_version() -> String { static OP_COUNTER: AtomicU64 = AtomicU64::new(0); // convenience trait exposing multisig functionality -pub(super) trait MultisigOps { +pub(super) trait MultisigOps: OfflineSigParty { fn multisig_mut(&mut self) -> &mut MultisigWallet; fn multisig_ref(&self) -> &MultisigWallet; fn online(&self) -> Online; fn assert_up_to_date(&mut self) { - if self.sync_opt().is_some() { - panic!( - "wallet {} is not up to date", - self.multisig_ref().internals.wallet_data.data_dir - ); + if self.sync_with_hub_opt().is_some() { + panic!("wallet {} is not up to date", self.data_dir()); } let last_processed_op = self .multisig_ref() @@ -405,19 +364,9 @@ pub(super) trait MultisigOps { assert_eq!(last_processed_op, current_op); } - fn bak_info_opt(&mut self) -> Option> { - let txn = self.multisig_ref().database().begin_transaction().ok()?; - let bak_info = txn.get_backup_info().ok()?; - txn.commit().ok()?; - Some(bak_info) - } - fn bak_ts(&mut self) -> String { // using last_operation_timestamp instead of last_backup_timestamp for convenience - self.bak_info_opt() - .unwrap() - .unwrap() - .last_operation_timestamp + self.db_backup_info().last_operation_timestamp } fn hub_info(&mut self) -> HubInfo { @@ -426,10 +375,7 @@ pub(super) trait MultisigOps { } fn blind_receive(&mut self) -> ReceiveData { - println!( - "blind_receive {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("blind_receive {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.blind_receive_res().unwrap(); assert!(self.bak_ts() > bt_before); @@ -457,10 +403,7 @@ pub(super) trait MultisigOps { size: Option, fee_rate: u64, ) -> InitOperationResult { - println!( - "create_utxos init {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("create_utxos init {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self .create_utxos_init_res(up_to, num, size, fee_rate) @@ -511,10 +454,7 @@ pub(super) trait MultisigOps { } fn inflate_init(&mut self, asset_id: &str, inflation_amounts: &[u64]) -> InitOperationResult { - println!( - "inflate init {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("inflate init {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.inflate_init_res(asset_id, inflation_amounts).unwrap(); assert_eq!(self.bak_ts(), bt_before); @@ -539,10 +479,7 @@ pub(super) trait MultisigOps { } fn burn_init(&mut self, asset_id: &str, amount: u64) -> InitOperationResult { - println!( - "burn init {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("burn init {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.burn_init_res(asset_id, amount).unwrap(); assert_eq!(self.bak_ts(), bt_before); @@ -558,10 +495,7 @@ pub(super) trait MultisigOps { } fn issue_asset_cfa(&mut self, amounts: Option<&[u64]>, file_path: Option) -> AssetCFA { - println!( - "issue CFA asset {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("issue CFA asset {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.issue_asset_cfa_res(amounts, file_path).unwrap(); assert!(self.bak_ts() > bt_before); @@ -593,10 +527,7 @@ pub(super) trait MultisigOps { inflation_amounts: Option<&[u64]>, reject_list_url: Option, ) -> AssetIFA { - println!( - "issue IFA asset {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("issue IFA asset {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self .issue_asset_ifa_res(amounts, inflation_amounts, reject_list_url) @@ -629,10 +560,7 @@ pub(super) trait MultisigOps { } fn issue_asset_nia(&mut self, amounts: Option<&[u64]>) -> AssetNIA { - println!( - "issue NIA asset {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("issue NIA asset {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.issue_asset_nia_res(amounts).unwrap(); assert!(self.bak_ts() > bt_before); @@ -659,10 +587,7 @@ pub(super) trait MultisigOps { media_file_path: Option<&str>, attachments_file_paths: Vec<&str>, ) -> AssetUDA { - println!( - "issue UDA asset {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("issue UDA asset {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self .issue_asset_uda_res(details, media_file_path, attachments_file_paths) @@ -694,16 +619,8 @@ pub(super) trait MultisigOps { ) } - fn list_unspents(&mut self, settled_only: bool) -> Vec { - let online = self.online(); - test_list_unspents(self.multisig_mut(), Some(online), settled_only) - } - fn nack(&mut self, op_idx: i32) -> OperationInfo { - println!( - "nack {op_idx} {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("nack {op_idx} {}", self.data_dir()); self.respond_to_operation(op_idx, RespondToOperation::Nack) } @@ -726,10 +643,7 @@ pub(super) trait MultisigOps { } fn send_btc_init(&mut self, address: &str, amount: u64) -> InitOperationResult { - println!( - "send_btc init {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("send_btc init {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.send_btc_init_res(address, amount).unwrap(); assert_eq!(self.bak_ts(), bt_before); @@ -750,10 +664,7 @@ pub(super) trait MultisigOps { } fn send_init(&mut self, recipient_map: HashMap>) -> InitOperationResult { - println!( - "send init {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("send init {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.send_init_res(recipient_map).unwrap(); assert_eq!(self.bak_ts(), bt_before); @@ -772,12 +683,12 @@ pub(super) trait MultisigOps { .send_init(online, recipient_map, false, FEE_RATE, 1, None) } - fn sync(&mut self) -> OperationInfo { - self.sync_opt().unwrap() + fn sync_with_hub(&mut self) -> OperationInfo { + self.sync_with_hub_opt().unwrap() } - fn sync_opt(&mut self) -> Option { - println!("sync {}", self.multisig_mut().get_wallet_data().data_dir); + fn sync_with_hub_opt(&mut self) -> Option { + println!("sync {}", self.data_dir()); let online = self.online(); self.multisig_mut().sync_with_hub(online).unwrap() } @@ -797,7 +708,7 @@ pub(super) trait MultisigOps { assert!(last_hub_operation > last_processed); for i in (last_processed + 1)..=last_hub_operation { println!("syncing operation {i}"); - let op_info = self.sync(); + let op_info = self.sync_with_hub(); assert_eq!(op_info.operation_idx, i); } let final_processed = self @@ -809,10 +720,7 @@ pub(super) trait MultisigOps { } fn witness_receive(&mut self) -> ReceiveData { - println!( - "witness_receive {}", - self.multisig_mut().get_wallet_data().data_dir - ); + println!("witness_receive {}", self.data_dir()); let bt_before = self.bak_ts(); let res = self.witness_receive_res().unwrap(); assert!(self.bak_ts() > bt_before); @@ -934,8 +842,8 @@ pub(super) fn issue_asset( check_issuance(initiator, others, asset.asset_id(), schema); - let mut all_wallets: Vec<&mut MultisigWallet> = vec![initiator.multisig_mut()]; - all_wallets.extend(others.iter_mut().map(|w| w.multisig_mut())); + let mut all_wallets: Vec<&MultisigParty> = vec![&*initiator]; + all_wallets.extend(others.iter().map(|w| &**w)); check_asset_metadata( &all_wallets, asset.asset_id(), @@ -985,18 +893,18 @@ pub(super) fn check_asset_balance( if balance != expected { panic!( "wallet {} balance {balance:?} is not the expected {expected:?}", - wallet.get_data_dir() + wallet.data_dir() ) } } } -fn check_bak_ts_opt(wallet: &mut MultisigParty, before: Option>, same: bool) { - if let Some(Some(before)) = before { +fn check_bak_ts_opt(wallet: &mut MultisigParty, before: Option, same: bool) { + if let Some(before) = before { if before.last_operation_timestamp == "0" { eprintln!( "wallet {} has last operation timestamp 0", - wallet.get_data_dir() + wallet.data_dir() ); } if same { @@ -1007,8 +915,8 @@ fn check_bak_ts_opt(wallet: &mut MultisigParty, before: Option>( + wallets: &[&P], asset_id: &str, name: &str, precision: u8, @@ -1017,13 +925,13 @@ fn check_asset_metadata( schema: AssetSchema, ) { let mut content_1: Vec = vec![]; - let mut media_1: Option = None; + let mut media_1: Option = None; let mut digests_1: Vec = vec![]; let mut token_1: Option = None; - let mut token_db_1: Option = None; + let mut token_db_1: Option = None; for wallet in wallets { - let meta = wallet.get_asset_metadata(asset_id.to_string()).unwrap(); + let meta = wallet.get_asset_metadata(asset_id); assert_eq!(meta.asset_schema, schema); assert_eq!(meta.initial_supply, supply); assert_eq!(meta.known_circulating_supply, supply); @@ -1047,17 +955,15 @@ fn check_asset_metadata( match schema { AssetSchema::Cfa => { - let txn = wallet.database().begin_transaction().unwrap(); - let asset_db = txn.get_asset(asset_id.to_string()).unwrap().unwrap(); + let asset_db = wallet.db_asset(asset_id); assert!(asset_db.media_idx.is_some()); - let media = txn.get_media(asset_db.media_idx.unwrap()).unwrap().unwrap(); - txn.commit().unwrap(); + let media = wallet.db_media(asset_db.media_idx.unwrap()); if let Some(ref media_1) = media_1 { assert_eq!(media_1.digest, media.digest); } else { media_1 = Some(media.clone()); } - let media_file = wallet.media_dir().join(&media.digest); + let media_file = wallet.wlt().media_dir().join(&media.digest); assert!(media_file.exists()); let content = std::fs::read(&media_file).unwrap(); if !content_1.is_empty() { @@ -1077,30 +983,25 @@ fn check_asset_metadata( assert!(!meta_token.attachments.is_empty()); assert_eq!(meta_token.reserves, None); - let assets_uda = wallet - .list_assets(vec![AssetSchema::Uda]) - .unwrap() - .uda - .unwrap(); + let assets_uda = wallet.list_assets(&[AssetSchema::Uda]).uda.unwrap(); let asset_uda = assets_uda.iter().find(|a| a.asset_id == asset_id).unwrap(); let token = asset_uda.token.clone().unwrap(); assert_eq!(token.index, UDA_FIXED_INDEX); - let txn = wallet.database().begin_transaction().unwrap(); - let asset_db = txn.get_asset(asset_id.to_string()).unwrap().unwrap(); - let tokens = txn.iter_tokens().unwrap(); + let asset_db = wallet.db_asset(asset_id); + let tokens = wallet.db_tokens(); let token_db = tokens.iter().find(|t| t.asset_idx == asset_db.idx).unwrap(); if let Some(ref token_db_1) = token_db_1 { assert_eq!(token_db, token_db_1); } else { token_db_1 = Some(token_db.clone()); } - let token_medias = txn.iter_token_medias().unwrap(); - let token_media_entries: Vec<_> = token_medias + let token_media_entries: Vec<_> = wallet + .db_token_medias() .into_iter() .filter(|tm| tm.token_idx == token_db.idx) .collect(); assert_eq!(token_media_entries.len(), 3); - let medias = txn.iter_media().unwrap(); + let medias = wallet.db_medias(); let mut digests: Vec = token_media_entries .iter() .map(|tm| { @@ -1118,7 +1019,6 @@ fn check_asset_metadata( } else { digests_1 = digests; } - txn.commit().unwrap(); let attachments = &token.attachments; assert_eq!(attachments.len(), 2); if let Some(ref token_1) = token_1 { @@ -1138,8 +1038,8 @@ fn check_asset_metadata( } } -pub(super) fn check_btc_balance( - wallets: &mut [&mut MultisigWallet], +pub(super) fn check_btc_balance>( + wallets: &mut [&mut P], expected_vanilla: (u64, u64, u64), expected_colored: (u64, u64, u64), ) { @@ -1156,25 +1056,21 @@ pub(super) fn check_btc_balance( }, }; for wallet in wallets.iter_mut() { - let balance = wallet.get_btc_balance(None, true).unwrap(); + let balance = wallet.get_btc_balance(); if balance != expected { panic!( "wallet {} BTC balance {balance:?} is not the expected {expected:?}", - wallet.get_wallet_data().data_dir + wallet.data_dir() ) } } } pub(super) fn check_change_consistency(wlt_a: &mut MultisigParty, wlt_b: &mut MultisigParty) { - let txn = wlt_a.multisig.database().begin_transaction().unwrap(); - let wlt_a_txos = txn.iter_txos().unwrap(); - let wlt_a_colorings = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); - let txn = wlt_b.multisig.database().begin_transaction().unwrap(); - let wlt_b_txos = txn.iter_txos().unwrap(); - let wlt_b_colorings = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); + let wlt_a_txos = wlt_a.db_txos(); + let wlt_a_colorings = wlt_a.db_colorings(); + let wlt_b_txos = wlt_b.db_txos(); + let wlt_b_colorings = wlt_b.db_colorings(); let resolve_change_outpoints = |txos: &[DbTxo], colorings: &[DbColoring]| -> Vec { colorings .iter() @@ -1253,7 +1149,7 @@ fn check_issuance( .unwrap(); for wallet in others { let bt_before = wallet.bak_ts(); - let op_info = wallet.sync(); + let op_info = wallet.sync_with_hub(); assert!(wallet.bak_ts() > bt_before); assert_eq!( op_info.operation_idx, @@ -1274,28 +1170,28 @@ fn check_issuance( } } -pub(super) fn check_last_transaction( - wallets: &mut [&mut MultisigWallet], +pub(super) fn check_last_transaction>( + wallets: &mut [&mut P], psbt: &str, last_tx_type: &TransactionType, ) { let txid = Psbt::from_str(psbt).unwrap().get_txid().to_string(); for wallet in wallets { - let transactions = test_list_transactions(*wallet, None); + let transactions = wallet.list_transactions(); let transaction = transactions.first().unwrap(); assert_eq!(transaction.txid, txid); assert_eq!( transaction.transaction_type, *last_tx_type, "wallet {} last transaction type {:?} != expected {last_tx_type:?}", - wallet.get_wallet_data().data_dir, + wallet.data_dir(), transaction.transaction_type ); } } pub(super) fn check_transfer_status( - parties: &[&dyn SigParty], + parties: &[&impl SigParty], asset_ids: &[Option<&str>], batch_transfer_idx: Option, status: TransferStatus, @@ -1315,15 +1211,15 @@ pub(super) fn check_transfer_status( eprintln!( "checking xfer {} for asset {asset_id:?} for {}", transfer.batch_transfer_idx, - party.get_data_dir() + party.data_dir() ); assert_eq!(transfer.status, status); } } } -pub(super) fn check_wallet_state( - wallet: &mut MultisigWallet, +pub(super) fn check_wallet_state>( + wallet: &mut P, op_last_successful: &InitOperationResult, op_last: &InitOperationResult, btc_vanilla: (u64, u64, u64), @@ -1332,10 +1228,10 @@ pub(super) fn check_wallet_state( asset_expectations: &HashMap<&str, (u64, u64, u64, usize, TransferStatus)>, ) { // check BTC balance - check_btc_balance(&mut [wallet], btc_vanilla, btc_colored); + check_btc_balance(&mut [&mut *wallet], btc_vanilla, btc_colored); // get all assets let mut all_assets: Vec = vec![]; - let assets = wallet.list_assets(vec![]).unwrap(); + let assets = wallet.list_assets(&[]); #[rustfmt::skip] all_assets.extend(assets.cfa.unwrap_or_default().into_iter().map(|a| a.asset_id)); #[rustfmt::skip] @@ -1345,8 +1241,9 @@ pub(super) fn check_wallet_state( #[rustfmt::skip] all_assets.extend(assets.ifa.unwrap_or_default().into_iter().map(|a| a.asset_id)); // check asset state - let data_dir = wallet.get_wallet_data().data_dir; + let data_dir = wallet.data_dir(); for (asset_id, (settled, future, spendable, transfer_count, status)) in asset_expectations { + let asset_id = *asset_id; assert!( all_assets.contains(&asset_id.to_string()), "asset {asset_id} not found in wallet {data_dir}" @@ -1357,13 +1254,13 @@ pub(super) fn check_wallet_state( future: *future, spendable: *spendable, }; - let balance = wallet.get_asset_balance(asset_id.to_string()).unwrap(); + let balance = wallet.get_asset_balance(asset_id); assert_eq!( balance, expected, "wallet {data_dir} asset {asset_id} balance {balance:?} != expected {expected:?}", ); // asset transfer number and last transfer status - let transfers = test_list_transfers(wallet, Some(asset_id)); + let transfers = wallet.list_transfers(Some(asset_id)); assert_eq!( transfers.len(), *transfer_count, @@ -1378,9 +1275,12 @@ pub(super) fn check_wallet_state( ); } // check last TX ID and type - check_last_transaction(&mut [wallet], &op_last_successful.psbt, last_tx_type); + check_last_transaction(&mut [&mut *wallet], &op_last_successful.psbt, last_tx_type); // check last processed op ID - let last_processed_op = wallet.get_local_last_processed_operation_idx().unwrap(); + let last_processed_op = wallet + .wlt_mut() + .get_local_last_processed_operation_idx() + .unwrap(); assert_eq!( last_processed_op, op_last.operation_idx, "wallet {data_dir} op idx {last_processed_op} != expected {}", @@ -1399,7 +1299,7 @@ pub(super) fn check_wallets_up_to_date(wallets: &mut [&mut MultisigParty]) { // ---------------------------------------- pub(super) fn backup(multisig: &MultisigParty, label: &str) -> String { - println!("backup wallet {}", multisig.get_data_dir()); + println!("backup wallet {}", multisig.data_dir()); let bak_fpath = get_test_data_dir_path().join(format!("{label}_backup.rgb-lib_backup")); let backup_file = bak_fpath.to_str().unwrap(); let _ = std::fs::remove_file(backup_file); @@ -1749,8 +1649,8 @@ pub(super) fn operation_complete( if approve { // nack with nacker cosigners for nacker in nackers.iter_mut() { - let bt_before = nacker.bak_info_opt(); - let mut op_info = nacker.sync(); + let bt_before = nacker.db_backup_info_opt(); + let mut op_info = nacker.sync_with_hub(); check_bak_ts_opt(nacker, bt_before, false); op_info.operation.sanitize(); let status = MultisigVotingStatus { @@ -1760,7 +1660,7 @@ pub(super) fn operation_complete( my_response: None, }; assert_eq!(op_info.operation, get_op_review(&status)); - let bt_before = nacker.bak_info_opt(); + let bt_before = nacker.db_backup_info_opt(); let mut response = nacker.nack(op_info.operation_idx); check_bak_ts_opt(nacker, bt_before, false); nacked_by.insert(nacker.xpub.to_string()); @@ -1775,8 +1675,8 @@ pub(super) fn operation_complete( } // ack with acker cosigners for (i, acker) in ackers.iter_mut().enumerate() { - let bt_before = acker.bak_info_opt(); - let mut op_info = acker.sync(); + let bt_before = acker.db_backup_info_opt(); + let mut op_info = acker.sync_with_hub(); check_bak_ts_opt(acker, bt_before, false); op_info.operation.sanitize(); let status = MultisigVotingStatus { @@ -1786,7 +1686,7 @@ pub(super) fn operation_complete( my_response: None, }; assert_eq!(op_info.operation, get_op_review(&status)); - let bt_before = acker.bak_info_opt(); + let bt_before = acker.db_backup_info_opt(); let mut response = acker.sign_and_ack(&op_psbt.to_string(), op_info.operation_idx); check_bak_ts_opt(acker, bt_before, false); acked_by.insert(acker.xpub.to_string()); @@ -1806,8 +1706,8 @@ pub(super) fn operation_complete( } else { // ack with acker cosigners for acker in ackers.iter_mut() { - let bt_before = acker.bak_info_opt(); - let mut op_info = acker.sync(); + let bt_before = acker.db_backup_info_opt(); + let mut op_info = acker.sync_with_hub(); check_bak_ts_opt(acker, bt_before, false); let status = MultisigVotingStatus { acked_by: acked_by.clone(), @@ -1817,7 +1717,7 @@ pub(super) fn operation_complete( }; op_info.operation.sanitize(); assert_eq!(op_info.operation, get_op_review(&status)); - let bt_before = acker.bak_info_opt(); + let bt_before = acker.db_backup_info_opt(); let mut response = acker.sign_and_ack(&op_psbt.to_string(), op_info.operation_idx); check_bak_ts_opt(acker, bt_before, false); acked_by.insert(acker.xpub.to_string()); @@ -1832,8 +1732,8 @@ pub(super) fn operation_complete( } // nack with nacker cosigners for (i, nacker) in nackers.iter_mut().enumerate() { - let bt_before = nacker.bak_info_opt(); - let mut op_info = nacker.sync(); + let bt_before = nacker.db_backup_info_opt(); + let mut op_info = nacker.sync_with_hub(); check_bak_ts_opt(nacker, bt_before, false); op_info.operation.sanitize(); let status = MultisigVotingStatus { @@ -1843,7 +1743,7 @@ pub(super) fn operation_complete( my_response: None, }; assert_eq!(op_info.operation, get_op_review(&status)); - let bt_before = nacker.bak_info_opt(); + let bt_before = nacker.db_backup_info_opt(); let mut response = nacker.nack(op_info.operation_idx); check_bak_ts_opt(nacker, bt_before, false); nacked_by.insert(nacker.xpub.to_string()); @@ -1871,8 +1771,8 @@ pub(super) fn operation_complete( my_response: Some(true), }; for (i, acker) in ackers.iter_mut().enumerate() { - let bt_before = acker.bak_info_opt(); - let op_info_opt = acker.sync_opt(); + let bt_before = acker.db_backup_info_opt(); + let op_info_opt = acker.sync_with_hub_opt(); if approve && i == last_acker { assert!(op_info_opt.is_none()); check_bak_ts_opt(acker, bt_before, true); @@ -1891,8 +1791,8 @@ pub(super) fn operation_complete( my_response: Some(false), }; for (i, nacker) in nackers.iter_mut().enumerate() { - let bt_before = nacker.bak_info_opt(); - let op_info_opt = nacker.sync_opt(); + let bt_before = nacker.db_backup_info_opt(); + let op_info_opt = nacker.sync_with_hub_opt(); if !approve && i == last_nacker { assert!(op_info_opt.is_none()); check_bak_ts_opt(nacker, bt_before, true); @@ -1911,8 +1811,8 @@ pub(super) fn operation_complete( my_response: None, }; for other in others.iter_mut() { - let bt_before = other.bak_info_opt(); - let mut op_info = other.sync(); + let bt_before = other.db_backup_info_opt(); + let mut op_info = other.sync_with_hub(); check_bak_ts_opt(other, bt_before, false); op_info.operation.sanitize(); assert_eq!(op_info.operation, get_op_final(&status)); @@ -1929,10 +1829,10 @@ pub(super) fn settle_transfer( ) { if stage_1 { for wallet in &mut *receivers { - wallet.refresh(None); // always None as the recipient might not know the asset yet + wallet.wait_for_refresh(None); // always None as the recipient might not know the asset yet } for wallet in &mut *senders { - wallet.refresh(asset_id); + wallet.wait_for_refresh(asset_id); } } if let Some(psbt) = psbt { @@ -1944,16 +1844,16 @@ pub(super) fn settle_transfer( mine(false); } for wallet in &mut *receivers { - wallet.refresh(asset_id); + wallet.wait_for_refresh(asset_id); } for wallet in &mut *senders { - wallet.refresh(asset_id); + wallet.wait_for_refresh(asset_id); } } pub(super) fn sync_wallets_full(wallets: &mut [&mut MultisigParty]) { for wallet in wallets { - eprintln!("syncing wallet {}", wallet.get_data_dir()); + eprintln!("syncing wallet {}", wallet.data_dir()); let online = wallet.online(); let last_processed = wallet .multisig_mut() @@ -1971,7 +1871,7 @@ pub(super) fn sync_wallets_full(wallets: &mut [&mut MultisigParty]) { ); for i in (last_processed + 1)..=last_hub_operation { println!("syncing operation {i}"); - let op_info = wallet.sync(); + let op_info = wallet.sync_with_hub(); assert_eq!(op_info.operation_idx, i); } let final_processed = wallet diff --git a/src/wallet/test/new.rs b/src/wallet/test/new.rs index dea85aaa..c4250667 100644 --- a/src/wallet/test/new.rs +++ b/src/wallet/test/new.rs @@ -2,8 +2,12 @@ use super::*; use std::os::unix::fs::PermissionsExt; -fn check_wallet(wallet: &Wallet, network: BitcoinNetwork, keychain_vanilla: Option) { - let keychains: Vec<_> = wallet.bdk_wallet().keychains().collect(); +fn check_wallet( + party: &impl OfflineSigParty, + network: BitcoinNetwork, + keychain_vanilla: Option, +) { + let keychains: Vec<_> = party.wlt().bdk_wallet().keychains().collect(); assert_eq!(keychains.len(), 2); for (keychain_kind, extended_descriptor) in keychains { match keychain_kind { @@ -48,7 +52,7 @@ fn check_wallet(wallet: &Wallet, network: BitcoinNetwork, keychain_vanilla: Opti }, } } - assert_eq!(wallet.get_wallet_data().bitcoin_network, network); + assert_eq!(party.get_wallet_data().bitcoin_network, network); } #[test] @@ -57,32 +61,32 @@ fn success() { create_test_data_dir(); // with private keys - let wallet = get_test_wallet(true, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let party = offline_party!(get_test_wallet(true, None)); + let bak_info_after = party.db_backup_info_opt(); assert!(bak_info_after.is_none()); // without private keys - let wallet = get_test_wallet(false, None); - check_wallet(&wallet, BitcoinNetwork::Regtest, None); + let party = offline_party!(get_test_wallet(false, None)); + check_wallet(&party, BitcoinNetwork::Regtest, None); // with custom vanilla keychain let bitcoin_network = BitcoinNetwork::Regtest; let keys = generate_keys(bitcoin_network, WitnessVersion::Taproot); let vanilla_keychain = Some(u8::MAX); - let wallet = Wallet::new( - WalletData { - data_dir: get_test_data_dir_string(), - bitcoin_network, - database_type: DatabaseType::Sqlite, - max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, - supported_schemas: AssetSchema::VALUES.to_vec(), - }, - SinglesigKeys::from_keys(&keys, vanilla_keychain), - ) - .unwrap(); - check_wallet(&wallet, bitcoin_network, vanilla_keychain); + let party = offline_party!( + Wallet::new( + WalletData { + data_dir: get_test_data_dir_string(), + bitcoin_network, + database_type: DatabaseType::Sqlite, + max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, + supported_schemas: AssetSchema::VALUES.to_vec(), + }, + SinglesigKeys::from_keys(&keys, vanilla_keychain), + ) + .unwrap() + ); + check_wallet(&party, bitcoin_network, vanilla_keychain); } #[cfg(feature = "electrum")] @@ -92,12 +96,12 @@ fn signet_success() { create_test_data_dir(); let bitcoin_network = BitcoinNetwork::Signet; - let mut wallet = get_test_wallet_with_net(true, None, bitcoin_network); - check_wallet(&wallet, bitcoin_network, None); + let mut party = offline_party!(get_test_wallet_with_net(true, None, bitcoin_network)); + check_wallet(&party, bitcoin_network, None); let indexer_url = "ssl://electrum.iriswallet.com:50033"; - test_go_online(&mut wallet, false, Some(indexer_url)); - assert!(!wallet.watch_only()); - assert_eq!(wallet.get_wallet_data().bitcoin_network, bitcoin_network); + party.go_online(false, Some(indexer_url)); + assert!(!party.wallet.watch_only()); + assert_eq!(party.get_wallet_data().bitcoin_network, bitcoin_network); } #[cfg(feature = "electrum")] @@ -107,12 +111,12 @@ fn testnet_success() { create_test_data_dir(); let bitcoin_network = BitcoinNetwork::Testnet; - let mut wallet = get_test_wallet_with_net(true, None, bitcoin_network); - check_wallet(&wallet, bitcoin_network, None); + let mut party = offline_party!(get_test_wallet_with_net(true, None, bitcoin_network)); + check_wallet(&party, bitcoin_network, None); let indexer_url = "ssl://electrum.iriswallet.com:50013"; - test_go_online(&mut wallet, false, Some(indexer_url)); - assert!(!wallet.watch_only()); - assert_eq!(wallet.get_wallet_data().bitcoin_network, bitcoin_network); + party.go_online(false, Some(indexer_url)); + assert!(!party.wallet.watch_only()); + assert_eq!(party.get_wallet_data().bitcoin_network, bitcoin_network); } #[cfg(feature = "electrum")] @@ -122,12 +126,12 @@ fn testnet4_success() { create_test_data_dir(); let bitcoin_network = BitcoinNetwork::Testnet4; - let mut wallet = get_test_wallet_with_net(true, None, bitcoin_network); - check_wallet(&wallet, bitcoin_network, None); + let mut party = offline_party!(get_test_wallet_with_net(true, None, bitcoin_network)); + check_wallet(&party, bitcoin_network, None); let indexer_url = "ssl://electrum.iriswallet.com:50053"; - test_go_online(&mut wallet, false, Some(indexer_url)); - assert!(!wallet.watch_only()); - assert_eq!(wallet.get_wallet_data().bitcoin_network, bitcoin_network); + party.go_online(false, Some(indexer_url)); + assert!(!party.wallet.watch_only()); + assert_eq!(party.get_wallet_data().bitcoin_network, bitcoin_network); } #[cfg(feature = "electrum")] @@ -138,24 +142,26 @@ fn mainnet_success_electrum() { let bitcoin_network = BitcoinNetwork::Mainnet; let keys = generate_keys(bitcoin_network, WitnessVersion::Taproot); - let mut wallet = Wallet::new( - WalletData { - data_dir: get_test_data_dir_string(), - bitcoin_network, - database_type: DatabaseType::Sqlite, - max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, - // IFA not supported on mainnet - supported_schemas: vec![AssetSchema::Cfa, AssetSchema::Nia, AssetSchema::Uda], - }, - SinglesigKeys::from_keys(&keys, None), - ) - .unwrap(); + let mut party = offline_party!( + Wallet::new( + WalletData { + data_dir: get_test_data_dir_string(), + bitcoin_network, + database_type: DatabaseType::Sqlite, + max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, + // IFA not supported on mainnet + supported_schemas: vec![AssetSchema::Cfa, AssetSchema::Nia, AssetSchema::Uda], + }, + SinglesigKeys::from_keys(&keys, None), + ) + .unwrap() + ); - check_wallet(&wallet, bitcoin_network, None); + check_wallet(&party, bitcoin_network, None); let indexer_url = "ssl://electrum.iriswallet.com:50003"; - test_go_online(&mut wallet, false, Some(indexer_url)); - assert!(!wallet.watch_only()); - assert_eq!(wallet.get_wallet_data().bitcoin_network, bitcoin_network); + party.go_online(false, Some(indexer_url)); + assert!(!party.wallet.watch_only()); + assert_eq!(party.get_wallet_data().bitcoin_network, bitcoin_network); } #[cfg(feature = "esplora")] @@ -167,31 +173,33 @@ fn mainnet_success_esplora() { let bitcoin_network = BitcoinNetwork::Mainnet; let keys = generate_keys(bitcoin_network, WitnessVersion::Taproot); - let mut wallet = Wallet::new( - WalletData { - data_dir: get_test_data_dir_string(), - bitcoin_network, - database_type: DatabaseType::Sqlite, - max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, - // IFA not supported on mainnet - supported_schemas: vec![AssetSchema::Cfa, AssetSchema::Nia, AssetSchema::Uda], - }, - SinglesigKeys::from_keys(&keys, None), - ) - .unwrap(); + let mut party = offline_party!( + Wallet::new( + WalletData { + data_dir: get_test_data_dir_string(), + bitcoin_network, + database_type: DatabaseType::Sqlite, + max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, + // IFA not supported on mainnet + supported_schemas: vec![AssetSchema::Cfa, AssetSchema::Nia, AssetSchema::Uda], + }, + SinglesigKeys::from_keys(&keys, None), + ) + .unwrap() + ); - check_wallet(&wallet, bitcoin_network, None); + check_wallet(&party, bitcoin_network, None); let indexer_url = "https://blockstream.info/api"; - test_go_online(&mut wallet, false, Some(indexer_url)); - assert!(!wallet.watch_only()); - assert_eq!(wallet.get_wallet_data().bitcoin_network, bitcoin_network); + party.go_online(false, Some(indexer_url)); + assert!(!party.wallet.watch_only()); + assert_eq!(party.get_wallet_data().bitcoin_network, bitcoin_network); } #[test] #[parallel] fn fail() { let wallet = get_test_wallet(true, None); - let wallet_data = test_get_wallet_data(&wallet); + let wallet_data = wallet.get_wallet_data(); let keys = wallet.get_keys(); // inexistent data dir @@ -276,16 +284,16 @@ fn re_instantiate_wallet() { let amount: u64 = 66; // create wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); - let wallet_data = wallet.get_wallet_data().clone(); - let keys = wallet.get_keys(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); + let wallet_data = party.get_wallet_data().clone(); + let keys = party.get_keys(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -295,27 +303,28 @@ fn re_instantiate_wallet() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // drop wallet - drop(wallet); + drop(party); // re-instantiate wallet let mut wallet = Wallet::new(wallet_data.clone(), keys.clone()).unwrap(); - let _online = wallet.go_online(test_go_online_options(None)).unwrap(); + let online = wallet.go_online(test_go_online_options(None)).unwrap(); + let mut party = party!(wallet, online); // check wallet asset - check_test_wallet_data(&mut wallet, &asset, None, 1, amount); + party.check_test_wallet_data(&asset, None, 1, amount); // drop wallet - drop(wallet); + drop(party); // re-instantiate wallet in watch only mode let mut keys_bad = keys.clone(); @@ -348,6 +357,7 @@ fn watch_only_success() { let online_watch = wallet_watch .go_online(test_go_online_options(None)) .unwrap(); + let mut party_watch = party!(wallet_watch, online_watch); // signer wallet let mut wallet_sign = Wallet::new( @@ -363,31 +373,26 @@ fn watch_only_success() { .unwrap(); // check generated addresses are the same - let address_watch = wallet_watch.get_address().unwrap(); + let address_watch = party_watch.get_address(); let address_signer = wallet_sign.get_address().unwrap(); assert_eq!(address_watch, address_signer); // fund wallet fund_wallet(address_watch); mine(false); - let unspents = test_list_unspents(&mut wallet_watch, Some(online_watch), false); + let unspents = party_watch.list_unspents_with_sync(false); assert_eq!(unspents.len(), 1); // create UTXOs - let unsigned_psbt = test_create_utxos_begin_result( - &mut wallet_watch, - online_watch, - false, - None, - None, - FEE_RATE, - ) - .unwrap(); + let unsigned_psbt = party_watch + .create_utxos_begin_result(false, None, None, FEE_RATE) + .unwrap(); let signed_psbt = wallet_sign.sign_psbt(unsigned_psbt, None).unwrap(); - wallet_watch + party_watch + .wallet .create_utxos_end(online_watch, signed_psbt) .unwrap(); - let unspents = test_list_unspents(&mut wallet_watch, Some(online_watch), false); + let unspents = party_watch.list_unspents_with_sync(false); assert_eq!(unspents.len(), UTXO_NUM as usize + 1); } @@ -487,19 +492,19 @@ fn supported_schemas() { ) .unwrap(); let online_nia = wallet_nia.go_online(test_go_online_options(None)).unwrap(); - fund_wallet(wallet_nia.get_address().unwrap()); - test_create_utxos_default(&mut wallet_nia, online_nia); + let mut party_nia = party!(wallet_nia, online_nia); + fund_wallet(party_nia.get_address()); + party_nia.create_utxos_default(); // issue a NIA asset, should work - let asset_nia = test_issue_asset_nia(&mut wallet_nia, online_nia, Some(&[AMOUNT])); + let asset_nia = party_nia.issue_asset_nia(Some(&[AMOUNT])); // issue a different schema asset, should fail - let result = test_issue_asset_cfa_result(&mut wallet_nia, online_nia, Some(&[AMOUNT]), None); + let result = party_nia.issue_asset_cfa_result(Some(&[AMOUNT]), None); assert_matches!(result, Err(Error::UnsupportedSchema { asset_schema: _ })); - let result = - test_issue_asset_ifa_result(&mut wallet_nia, online_nia, Some(&[AMOUNT]), None, None); + let result = party_nia.issue_asset_ifa_result(Some(&[AMOUNT]), None, None); assert_matches!(result, Err(Error::UnsupportedSchema { asset_schema: _ })); - let result = test_issue_asset_uda_result(&mut wallet_nia, online_nia, None, None, vec![]); + let result = party_nia.issue_asset_uda_result(None, None, vec![]); assert_matches!(result, Err(Error::UnsupportedSchema { asset_schema: _ })); // recipient wallet (UDA schema supported) @@ -518,11 +523,12 @@ fn supported_schemas() { let rcv_online_uda = rcv_wallet_uda .go_online(test_go_online_options(None)) .unwrap(); - fund_wallet(rcv_wallet_uda.get_address().unwrap()); - test_create_utxos_default(&mut rcv_wallet_uda, rcv_online_uda); + let mut rcv_party_uda = party!(rcv_wallet_uda, rcv_online_uda); + fund_wallet(rcv_party_uda.get_address()); + rcv_party_uda.create_utxos_default(); // send asset unsupported by the recipient - let receive_data = test_blind_receive(&mut rcv_wallet_uda); + let receive_data = rcv_party_uda.blind_receive(); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), vec![Recipient { @@ -532,19 +538,19 @@ fn supported_schemas() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_nia, online_nia, &recipient_map); + let txid = party_nia.send_retry(&recipient_map); assert!(!txid.is_empty()); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet_uda, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet_uda, &rcv_transfer); + let rcv_transfer = rcv_party_uda.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party_uda.get_test_transfer_data(&rcv_transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingCounterparty ); // refresh the recipient, transfer should fail - test_refresh_all(&mut rcv_wallet_uda, rcv_online_uda); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet_uda, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet_uda, &rcv_transfer); + rcv_party_uda.refresh_all(); + let rcv_transfer = rcv_party_uda.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party_uda.get_test_transfer_data(&rcv_transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Failed); // wallet (CFA schema supported) @@ -560,9 +566,10 @@ fn supported_schemas() { ) .unwrap(); let online_cfa = wallet_cfa.go_online(test_go_online_options(None)).unwrap(); + let mut party_cfa = party!(wallet_cfa, online_cfa); // send asset unsupported by the sender - let receive_data = test_blind_receive(&mut rcv_wallet_uda); + let receive_data = rcv_party_uda.blind_receive(); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), vec![Recipient { @@ -572,7 +579,7 @@ fn supported_schemas() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_result(&mut wallet_cfa, online_cfa, &recipient_map); + let result = party_cfa.send_result(&recipient_map); assert_matches!(result, Err(Error::UnsupportedSchema { asset_schema: _ })); // wallet (no schema supported) diff --git a/src/wallet/test/refresh.rs b/src/wallet/test/refresh.rs index 6b93af19..6f35ea91 100644 --- a/src/wallet/test/refresh.rs +++ b/src/wallet/test/refresh.rs @@ -26,12 +26,12 @@ fn success() { incoming: false, }; - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset_1 = test_issue_asset_nia(&mut wallet_1, online_1, Some(&[AMOUNT, AMOUNT])); - let asset_2 = test_issue_asset_nia(&mut wallet_2, online_2, Some(&[AMOUNT * 2, AMOUNT * 2])); + let asset_1 = party_1.issue_asset_nia(Some(&[AMOUNT, AMOUNT])); + let asset_2 = party_2.issue_asset_nia(Some(&[AMOUNT * 2, AMOUNT * 2])); // per each wallet prepare: // - 1 WaitingCounterparty + 1 WaitingConfirmations ountgoing @@ -40,7 +40,7 @@ fn success() { let _guard = stop_mining(); // wallet 1 > wallet 2 WaitingConfirmations and vice versa - let receive_data_2a = test_blind_receive(&mut wallet_2); + let receive_data_2a = party_2.blind_receive(); let recipient_map_1a = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -51,20 +51,16 @@ fn success() { }], )]); // return false if no transfer has changed - let txn = wallet_2.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - assert!(!test_refresh_all(&mut wallet_2, online_2)); - let txn = wallet_2.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party_2.db_backup_info(); + assert!(!party_2.refresh_all()); + let bak_info_after = party_2.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); - let txid_1a = test_send(&mut wallet_1, online_1, &recipient_map_1a); + let txid_1a = party_1.send_retry(&recipient_map_1a); assert!(!txid_1a.is_empty()); - let receive_data_1a = test_blind_receive(&mut wallet_1); + let receive_data_1a = party_1.blind_receive(); let recipient_map_2a = HashMap::from([( asset_2.asset_id.clone(), vec![Recipient { @@ -74,29 +70,24 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2a = test_send(&mut wallet_2, online_2, &recipient_map_2a); + let txid_2a = party_2.send_retry(&recipient_map_2a); assert!(!txid_2a.is_empty()); - assert!(test_refresh_all(&mut wallet_1, online_1)); - let txn = wallet_2.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - assert!(test_refresh_all(&mut wallet_2, online_2)); - let txn = wallet_2.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + assert!(party_1.refresh_all()); + let bak_info_before = party_2.db_backup_info(); + assert!(party_2.refresh_all()); + let bak_info_after = party_2.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!( - test_refresh_result( - &mut wallet_1, - online_1, - Some(&asset_1.asset_id), - std::slice::from_ref(&filter_counter_out) - ) - .unwrap() - .transfers_changed() + party_1 + .refresh_result( + Some(&asset_1.asset_id), + std::slice::from_ref(&filter_counter_out), + ) + .unwrap() + .transfers_changed() ); // wallet 1 > 2, WaitingCounterparty and vice versa - let receive_data_2b = test_blind_receive(&mut wallet_2); + let receive_data_2b = party_2.blind_receive(); let recipient_map_1b = HashMap::from([( asset_1.asset_id, vec![Recipient { @@ -106,11 +97,11 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1b = test_send(&mut wallet_1, online_1, &recipient_map_1b); + let txid_1b = party_1.send_retry(&recipient_map_1b); assert!(!txid_1b.is_empty()); // wallet 2 > 1, WaitingCounterparty - let receive_data_1b = test_blind_receive(&mut wallet_1); - show_unspent_colorings(&mut wallet_1, "wallet 1 after blind 1b"); + let receive_data_1b = party_1.blind_receive(); + party_1.show_unspent_colorings("wallet 1 after blind 1b"); let recipient_map_2b = HashMap::from([( asset_2.asset_id, vec![Recipient { @@ -120,113 +111,83 @@ fn success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2b = test_send(&mut wallet_2, online_2, &recipient_map_2b); + let txid_2b = party_2.send_retry(&recipient_map_2b); assert!(!txid_2b.is_empty()); - show_unspent_colorings(&mut wallet_2, "wallet 2 after send 2b"); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + party_2.show_unspent_colorings("wallet 2 after send 2b"); + assert!( + party_1.check_test_transfer_status_sender(&txid_1a, TransferStatus::WaitingConfirmations) + ); + assert!( + party_1.check_test_transfer_status_sender(&txid_1b, TransferStatus::WaitingCounterparty) + ); + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1b.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!( + party_2.check_test_transfer_status_sender(&txid_2a, TransferStatus::WaitingConfirmations) + ); + assert!( + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingCounterparty) + ); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2b.recipient_id, TransferStatus::WaitingCounterparty )); // refresh incoming WaitingCounterparty only (wallet 1) assert!( - test_refresh_result(&mut wallet_1, online_1, None, &[filter_counter_in]) + party_1 + .refresh_result(None, &[filter_counter_in]) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_1, - "wallet 1 after refresh incoming WaitingCounterparty", + party_1.show_unspent_colorings("wallet 1 after refresh incoming WaitingCounterparty"); + assert!( + party_1.check_test_transfer_status_sender(&txid_1a, TransferStatus::WaitingConfirmations) ); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!( + party_1.check_test_transfer_status_sender(&txid_1b, TransferStatus::WaitingCounterparty) + ); + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1b.recipient_id, TransferStatus::WaitingConfirmations )); // refresh outgoing WaitingCounterparty only (wallet 2) - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingCounterparty - )); assert!( - test_refresh_result(&mut wallet_2, online_2, None, &[filter_counter_out]) + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingCounterparty) + ); + assert!( + party_2 + .refresh_result(None, &[filter_counter_out]) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_2, - "wallet 2 after refresh outgoing WaitingCounterparty", + party_2.show_unspent_colorings("wallet 2 after refresh outgoing WaitingCounterparty"); + assert!( + party_2.check_test_transfer_status_sender(&txid_2a, TransferStatus::WaitingConfirmations) ); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!( + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingConfirmations) + ); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2b.recipient_id, TransferStatus::WaitingCounterparty )); @@ -238,62 +199,44 @@ fn success() { // refresh incoming WaitingConfirmations only (wallet 2) assert!( - test_refresh_result(&mut wallet_2, online_2, None, &[filter_confirm_in]) + party_2 + .refresh_result(None, &[filter_confirm_in]) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_2, - "wallet 2 after refresh incoming WaitingConfirmations", + party_2.show_unspent_colorings("wallet 2 after refresh incoming WaitingConfirmations"); + assert!( + party_2.check_test_transfer_status_sender(&txid_2a, TransferStatus::WaitingConfirmations) ); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!( + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingConfirmations) + ); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2a.recipient_id, TransferStatus::Settled )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2b.recipient_id, TransferStatus::WaitingCounterparty )); // refresh outgoing WaitingConfirmations only (wallet 1) assert!( - test_refresh_result(&mut wallet_1, online_1, None, &[filter_confirm_out]) + party_1 + .refresh_result(None, &[filter_confirm_out]) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_1, - "wallet 1 after refresh outgoing WaitingConfirmations", + party_1.show_unspent_colorings("wallet 1 after refresh outgoing WaitingConfirmations"); + assert!(party_1.check_test_transfer_status_sender(&txid_1a, TransferStatus::Settled)); + assert!( + party_1.check_test_transfer_status_sender(&txid_1b, TransferStatus::WaitingCounterparty) ); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1a, - TransferStatus::Settled - )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1b.recipient_id, TransferStatus::WaitingConfirmations )); @@ -305,10 +248,10 @@ fn success() { fn fail() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // asset not found - let result = test_refresh_result(&mut wallet, online, Some("rgb1inexistent"), &[]); + let result = party.refresh_result(Some("rgb1inexistent"), &[]); assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ }))); } @@ -320,9 +263,9 @@ fn nia_with_media() { let amount: u64 = 66; - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); let fp = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); let fpath = std::path::Path::new(&fp); @@ -340,22 +283,16 @@ fn nia_with_media() { }; println!("setting MOCK_CONTRACT_DATA"); MOCK_CONTRACT_DATA.with_borrow_mut(|v| v.push(attachment.clone())); - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); - let media = Media::from_attachment(&attachment, wallet_1.get_media_dir()); - wallet_1.copy_media_file(fp, &media).unwrap(); - let txn = wallet_1.database().begin_transaction().unwrap(); - let media_idx = txn - .get_or_insert_media(media.get_digest(), media.mime.clone()) - .unwrap(); - let db_asset = txn.get_asset(asset.asset_id.clone()).unwrap().unwrap(); - txn.commit().unwrap(); + let asset = party_1.issue_asset_nia(None); + let media = Media::from_attachment(&attachment, party_1.wallet.get_media_dir()); + party_1.wallet.copy_media_file(fp, &media).unwrap(); + let media_idx = party_1.db_get_or_insert_media(&media.get_digest(), &media.mime); + let db_asset = party_1.db_asset(&asset.asset_id); let mut updated_asset: DbAssetActMod = db_asset.into(); updated_asset.media_idx = ActiveValue::Set(Some(media_idx)); - let txn = wallet_1.database().begin_transaction().unwrap(); - txn.update_asset(&mut updated_asset).unwrap(); - txn.commit().unwrap(); + party_1.db_update_asset(&mut updated_asset); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -365,18 +302,18 @@ fn nia_with_media() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let assets_list = test_list_assets(&wallet_2, &[]); + party_2.wait_for_refresh(None); + let assets_list = party_2.list_assets(&[]); assert!(assets_list.nia.unwrap()[0].media.is_some()); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id, vec![Recipient { @@ -386,20 +323,20 @@ fn nia_with_media() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_3, online_3, None, None); - let assets_list = test_list_assets(&wallet_3, &[]); + party_3.wait_for_refresh(None); + let assets_list = party_3.list_assets(&[]); assert!(assets_list.nia.unwrap()[0].media.is_some()); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let rcv_transfer = get_test_transfer_recipient(&wallet_3, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_3, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_2, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet_2, &transfer); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); + let rcv_transfer = party_3.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_3.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_2.get_test_transfer_sender(&txid); + let (transfer_data, _) = party_2.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); } @@ -414,22 +351,22 @@ fn nia_with_details() { let details_str = "mocked details"; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); // manually set the asset's details println!("setting MOCK_CONTRACT_DETAILS"); MOCK_CONTRACT_DETAILS.replace(Some(details_str.to_string())); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // check asset details have been set assert_eq!(asset.details, Some(details_str.to_string())); // send 1->2 - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -439,18 +376,18 @@ fn nia_with_details() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfer - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // send 2->3 - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id, vec![Recipient { @@ -460,24 +397,24 @@ fn nia_with_details() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfer - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let rcv_transfer = get_test_transfer_recipient(&wallet_3, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_3, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_2, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet_2, &transfer); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); + let rcv_transfer = party_3.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_3.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_2.get_test_transfer_sender(&txid); + let (transfer_data, _) = party_2.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // check asset details on the final recipient - let asset_list = test_list_assets(&wallet_3, &[]); + let asset_list = party_3.list_assets(&[]); assert_eq!( asset_list.nia.unwrap()[0].details, Some(details_str.to_string()) @@ -490,9 +427,9 @@ fn nia_with_details() { fn uda_with_media() { initialize(); - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); let fp = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); let fpath = std::path::Path::new(&fp); @@ -510,22 +447,15 @@ fn uda_with_media() { }; println!("setting MOCK_CONTRACT_DATA"); MOCK_CONTRACT_DATA.with_borrow_mut(|v| v.push(attachment.clone())); - let asset = test_issue_asset_uda(&mut wallet_1, online_1, None, Some(FILE_STR), vec![]); - let media = Media::from_attachment(&attachment, wallet_1.get_media_dir()); - wallet_1.copy_media_file(fp, &media).unwrap(); - let txn = wallet_1.database().begin_transaction().unwrap(); - let media_idx = txn - .get_or_insert_media(media.get_digest(), media.mime.clone()) - .unwrap(); - let db_asset = txn.get_asset(asset.asset_id.clone()).unwrap().unwrap(); - txn.commit().unwrap(); - let mut updated_asset: DbAssetActMod = db_asset.into(); + let asset = party_1.issue_asset_uda(None, Some(FILE_STR), vec![]); + let media = Media::from_attachment(&attachment, party_1.wallet.get_media_dir()); + party_1.wallet.copy_media_file(fp, &media).unwrap(); + let media_idx = party_1.db_get_or_insert_media(&media.get_digest(), &media.mime); + let mut updated_asset: DbAssetActMod = party_1.db_asset(&asset.asset_id).into(); updated_asset.media_idx = ActiveValue::Set(Some(media_idx)); - let txn = wallet_1.database().begin_transaction().unwrap(); - txn.update_asset(&mut updated_asset).unwrap(); - txn.commit().unwrap(); + party_1.db_update_asset(&mut updated_asset); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -535,18 +465,18 @@ fn uda_with_media() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let assets_list = test_list_assets(&wallet_2, &[]); + party_2.wait_for_refresh(None); + let assets_list = party_2.list_assets(&[]); assert!(assets_list.uda.unwrap()[0].media.is_some()); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id, vec![Recipient { @@ -556,20 +486,20 @@ fn uda_with_media() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_3, online_3, None, None); - let assets_list = test_list_assets(&wallet_3, &[]); + party_3.wait_for_refresh(None); + let assets_list = party_3.list_assets(&[]); assert!(assets_list.uda.unwrap()[0].media.is_some()); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let rcv_transfer = get_test_transfer_recipient(&wallet_3, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_3, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_2, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet_2, &transfer); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); + let rcv_transfer = party_3.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_3.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_2.get_test_transfer_sender(&txid); + let (transfer_data, _) = party_2.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); } @@ -580,9 +510,9 @@ fn uda_with_media() { fn uda_with_preview_and_reserves() { initialize(); - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); let index_int = 7; let data = vec![1u8, 3u8, 9u8]; @@ -608,9 +538,9 @@ fn uda_with_preview_and_reserves() { }; println!("setting MOCK_TOKEN_DATA"); MOCK_TOKEN_DATA.with_borrow_mut(|v| v.push(token_data.clone())); - let asset = test_issue_asset_uda(&mut wallet_1, online_1, Some(DETAILS), None, vec![]); + let asset = party_1.issue_asset_uda(Some(DETAILS), None, vec![]); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -620,11 +550,11 @@ fn uda_with_preview_and_reserves() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let assets_list = test_list_assets(&wallet_2, &[]); + party_2.wait_for_refresh(None); + let assets_list = party_2.list_assets(&[]); assert!( assets_list.uda.unwrap()[0] .token @@ -633,12 +563,12 @@ fn uda_with_preview_and_reserves() { .media .is_none() ); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -648,11 +578,11 @@ fn uda_with_preview_and_reserves() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); - wait_for_refresh(&mut wallet_3, online_3, None, None); - let assets_list = test_list_assets(&wallet_3, &[]); + party_3.wait_for_refresh(None); + let assets_list = party_3.list_assets(&[]); let uda = assets_list.uda.unwrap(); let token = uda[0].token.as_ref().unwrap(); assert_eq!(token.index, index_int); @@ -663,18 +593,18 @@ fn uda_with_preview_and_reserves() { assert!(token.media.is_none()); assert_eq!(token.attachments, HashMap::new()); assert!(token.reserves); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); - let rcv_transfer = get_test_transfer_recipient(&wallet_3, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_3, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_2, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet_2, &transfer); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); + let rcv_transfer = party_3.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_3.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_2.get_test_transfer_sender(&txid); + let (transfer_data, _) = party_2.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); - let uda_metadata = test_get_asset_metadata(&wallet_3, &asset.asset_id); + let uda_metadata = party_3.get_asset_metadata(&asset.asset_id); assert_eq!(uda_metadata.asset_schema, AssetSchema::Uda); assert_eq!(uda_metadata.initial_supply, 1); assert_eq!(uda_metadata.name, NAME.to_string()); @@ -716,12 +646,12 @@ fn skip_sync() { incoming: false, }; - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset_1 = test_issue_asset_nia(&mut wallet_1, online_1, Some(&[AMOUNT, AMOUNT])); - let asset_2 = test_issue_asset_nia(&mut wallet_2, online_2, Some(&[AMOUNT * 2, AMOUNT * 2])); + let asset_1 = party_1.issue_asset_nia(Some(&[AMOUNT, AMOUNT])); + let asset_2 = party_2.issue_asset_nia(Some(&[AMOUNT * 2, AMOUNT * 2])); // per each wallet prepare: // - 1 WaitingCounterparty + 1 WaitingConfirmations ountgoing @@ -730,7 +660,7 @@ fn skip_sync() { let _guard = stop_mining(); // wallet 1 > wallet 2 WaitingConfirmations and vice versa - let receive_data_2a = test_blind_receive(&mut wallet_2); + let receive_data_2a = party_2.blind_receive(); let recipient_map_1a = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -742,14 +672,16 @@ fn skip_sync() { )]); // refresh skipping sync > no transfer has changed so return false before and after syncing assert!( - !wallet_2 - .refresh(online_2, None, vec![], true) + !party_2 + .wallet + .refresh(party_2.online, None, vec![], true) .unwrap() .transfers_changed() ); - wallet_2 + party_2 + .wallet .sync( - online_2, + party_2.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -757,14 +689,15 @@ fn skip_sync() { ) .unwrap(); assert!( - !wallet_2 - .refresh(online_2, None, vec![], true) + !party_2 + .wallet + .refresh(party_2.online, None, vec![], true) .unwrap() .transfers_changed() ); - let txid_1a = test_send(&mut wallet_1, online_1, &recipient_map_1a); + let txid_1a = party_1.send_retry(&recipient_map_1a); assert!(!txid_1a.is_empty()); - let receive_data_1a = test_blind_receive(&mut wallet_1); + let receive_data_1a = party_1.blind_receive(); let recipient_map_2a = HashMap::from([( asset_2.asset_id.clone(), vec![Recipient { @@ -774,25 +707,28 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2a = test_send(&mut wallet_2, online_2, &recipient_map_2a); + let txid_2a = party_2.send_retry(&recipient_map_2a); assert!(!txid_2a.is_empty()); // refresh skipping sync > transfers have changed so return true assert!( - wallet_1 - .refresh(online_1, None, vec![], true) + party_1 + .wallet + .refresh(party_1.online, None, vec![], true) .unwrap() .transfers_changed() ); assert!( - wallet_2 - .refresh(online_2, None, vec![], true) + party_2 + .wallet + .refresh(party_2.online, None, vec![], true) .unwrap() .transfers_changed() ); assert!( - wallet_1 + party_1 + .wallet .refresh( - online_1, + party_1.online, Some(asset_1.asset_id.to_string()), vec![filter_counter_out.clone()], true, @@ -802,7 +738,7 @@ fn skip_sync() { ); // wallet 1 > 2, WaitingCounterparty and vice versa - let receive_data_2b = test_blind_receive(&mut wallet_2); + let receive_data_2b = party_2.blind_receive(); let recipient_map_1b = HashMap::from([( asset_1.asset_id, vec![Recipient { @@ -812,11 +748,11 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1b = test_send(&mut wallet_1, online_1, &recipient_map_1b); + let txid_1b = party_1.send_retry(&recipient_map_1b); assert!(!txid_1b.is_empty()); // wallet 2 > 1, WaitingCounterparty - let receive_data_1b = test_blind_receive(&mut wallet_1); - show_unspent_colorings(&mut wallet_1, "wallet 1 after blind 1b"); + let receive_data_1b = party_1.blind_receive(); + party_1.show_unspent_colorings("wallet 1 after blind 1b"); let recipient_map_2b = HashMap::from([( asset_2.asset_id, vec![Recipient { @@ -826,110 +762,82 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2b = test_send(&mut wallet_2, online_2, &recipient_map_2b); + let txid_2b = party_2.send_retry(&recipient_map_2b); assert!(!txid_2b.is_empty()); - show_unspent_colorings(&mut wallet_2, "wallet 2 after send 2b"); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + party_2.show_unspent_colorings("wallet 2 after send 2b"); + assert!( + party_1.check_test_transfer_status_sender(&txid_1a, TransferStatus::WaitingConfirmations) + ); + assert!( + party_1.check_test_transfer_status_sender(&txid_1b, TransferStatus::WaitingCounterparty) + ); + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1b.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!( + party_2.check_test_transfer_status_sender(&txid_2a, TransferStatus::WaitingConfirmations) + ); + assert!( + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingCounterparty) + ); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2b.recipient_id, TransferStatus::WaitingCounterparty )); // refresh incoming WaitingCounterparty only (wallet 1), skipping sync assert!( - wallet_1 - .refresh(online_1, None, vec![filter_counter_in], true) + party_1 + .wallet + .refresh(party_1.online, None, vec![filter_counter_in], true) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_1, - "wallet 1 after refresh incoming WaitingCounterparty", + party_1.show_unspent_colorings("wallet 1 after refresh incoming WaitingCounterparty"); + assert!( + party_1.check_test_transfer_status_sender(&txid_1a, TransferStatus::WaitingConfirmations) ); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!( + party_1.check_test_transfer_status_sender(&txid_1b, TransferStatus::WaitingCounterparty) + ); + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1b.recipient_id, TransferStatus::WaitingConfirmations )); // refresh outgoing WaitingCounterparty only (wallet 2), skipping sync assert!( - wallet_2 - .refresh(online_2, None, vec![filter_counter_out], true) + party_2 + .wallet + .refresh(party_2.online, None, vec![filter_counter_out], true) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_2, - "wallet 2 after refresh outgoing WaitingCounterparty", + party_2.show_unspent_colorings("wallet 2 after refresh outgoing WaitingCounterparty"); + assert!( + party_2.check_test_transfer_status_sender(&txid_2a, TransferStatus::WaitingConfirmations) + ); + assert!( + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingConfirmations) ); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2b.recipient_id, TransferStatus::WaitingCounterparty )); @@ -939,64 +847,46 @@ fn skip_sync() { // refresh incoming WaitingConfirmations only (wallet 2), skipping sync assert!( - wallet_2 - .refresh(online_2, None, vec![filter_confirm_in], true) + party_2 + .wallet + .refresh(party_2.online, None, vec![filter_confirm_in], true) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_2, - "wallet 2 after refresh incoming WaitingConfirmations", + party_2.show_unspent_colorings("wallet 2 after refresh incoming WaitingConfirmations"); + assert!( + party_2.check_test_transfer_status_sender(&txid_2a, TransferStatus::WaitingConfirmations) ); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2a, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_sender( - &wallet_2, - &txid_2b, - TransferStatus::WaitingConfirmations - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!( + party_2.check_test_transfer_status_sender(&txid_2b, TransferStatus::WaitingConfirmations) + ); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2a.recipient_id, TransferStatus::Settled )); - assert!(check_test_transfer_status_recipient( - &wallet_2, + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2b.recipient_id, TransferStatus::WaitingCounterparty )); // refresh outgoing WaitingConfirmations only (wallet 1), skipping sync assert!( - wallet_1 - .refresh(online_1, None, vec![filter_confirm_out], true) + party_1 + .wallet + .refresh(party_1.online, None, vec![filter_confirm_out], true) .unwrap() .transfers_changed() ); - show_unspent_colorings( - &mut wallet_1, - "wallet 1 after refresh outgoing WaitingConfirmations", + party_1.show_unspent_colorings("wallet 1 after refresh outgoing WaitingConfirmations"); + assert!(party_1.check_test_transfer_status_sender(&txid_1a, TransferStatus::Settled)); + assert!( + party_1.check_test_transfer_status_sender(&txid_1b, TransferStatus::WaitingCounterparty) ); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1a, - TransferStatus::Settled - )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1b, - TransferStatus::WaitingCounterparty - )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1a.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_recipient( - &wallet_1, + assert!(party_1.check_test_transfer_status_recipient( &receive_data_1b.recipient_id, TransferStatus::WaitingConfirmations )); diff --git a/src/wallet/test/rust_only.rs b/src/wallet/test/rust_only.rs index 54a827d0..c068d518 100644 --- a/src/wallet/test/rust_only.rs +++ b/src/wallet/test/rust_only.rs @@ -10,32 +10,19 @@ fn success() { let blinding = 777; // wallets - let (mut wallet_send, online_send) = get_funded_noutxo_wallet!(); - let (mut wallet_recv, _online_recv) = get_empty_wallet!(); + let mut party_send = get_funded_noutxo_party!(); + let mut recv_party = get_empty_party!(); // create 1 UTXO and send the rest - test_create_utxos( - &mut wallet_send, - online_send, - false, - Some(1), - None, - FEE_RATE, - None, - ); - test_send_btc( - &mut wallet_send, - online_send, - &test_get_address(&mut wallet_recv), - 99_998_200, - ); + party_send.create_utxos(false, Some(1), None, FEE_RATE, None); + party_send.send_btc(&recv_party.get_address(), 99_998_200); // issue - let asset = test_issue_asset_nia(&mut wallet_send, online_send, Some(&[AMOUNT])); + let asset = party_send.issue_asset_nia(Some(&[AMOUNT])); // prepare PSBT - let address = BdkAddress::from_str(&test_get_address(&mut wallet_recv)).unwrap(); - let mut tx_builder = wallet_send.bdk_wallet_mut().build_tx(); + let address = BdkAddress::from_str(&recv_party.get_address()).unwrap(); + let mut tx_builder = party_send.wallet.bdk_wallet_mut().build_tx(); tx_builder .add_recipient( address.assume_checked().script_pubkey(), @@ -78,7 +65,8 @@ fn success() { static_blinding: Some(blinding), nonce: None, }; - let (fascia, beneficiaries) = wallet_send + let (fascia, beneficiaries) = party_send + .wallet .color_psbt(&mut psbt, coloring_info.clone()) .unwrap(); @@ -125,7 +113,8 @@ fn success() { assert_eq!(seal.blinding, blinding); // color PSBT and consume - let transfers = wallet_send + let transfers = party_send + .wallet .color_psbt_and_consume(&mut psbt_copy, coloring_info) .unwrap(); @@ -134,7 +123,7 @@ fn success() { // push consignment to proxy let txid = psbt_copy.unsigned_tx.compute_txid().to_string(); - let transfers_dir = wallet_send.get_transfers_dir().join(&txid); + let transfers_dir = party_send.wallet.get_transfers_dir().join(&txid); let consignment_path = transfers_dir.join(CONSIGNMENT_FILE); std::fs::create_dir_all(&transfers_dir).unwrap(); assert_eq!(transfers.len(), 1); @@ -143,7 +132,8 @@ fn success() { .unwrap() .save_file(&consignment_path) .unwrap(); - wallet_send + party_send + .wallet .post_consignment( PROXY_URL, txid.clone(), @@ -155,12 +145,13 @@ fn success() { // accept transfer let consignment_endpoint = RgbTransport::from_str(&PROXY_ENDPOINT).unwrap(); - wallet_recv + recv_party + .wallet .accept_transfer(txid.clone(), vout, consignment_endpoint, blinding) .unwrap(); // consume fascia - wallet_send.consume_fascia(fascia, None).unwrap(); + party_send.wallet.consume_fascia(fascia, None).unwrap(); } #[cfg(feature = "electrum")] @@ -170,44 +161,40 @@ fn list_unspents_vanilla_success() { initialize(); // wallets - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); // no unspents - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info_opt(); assert!(bak_info_before.is_none()); - let unspent_list = test_list_unspents_vanilla(&mut wallet, online, None); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap(); - txn.commit().unwrap(); + let unspent_list = party.list_unspents_vanilla(None); + let bak_info_after = party.db_backup_info_opt(); assert!(bak_info_after.is_none()); assert_eq!(unspent_list.len(), 0); let _guard = stop_mining(); - send_to_address(test_get_address(&mut wallet)); + send_to_address(party.get_address()); // one unspent, no confirmations - let unspent_list = test_list_unspents_vanilla(&mut wallet, online, None); + let unspent_list = party.list_unspents_vanilla(None); assert_eq!(unspent_list.len(), 0); - let unspent_list = test_list_unspents_vanilla(&mut wallet, online, Some(0)); + let unspent_list = party.list_unspents_vanilla(Some(0)); assert_eq!(unspent_list.len(), 1); drop(_guard); mine(false); // one unspent, 1 confirmation - let unspent_list = test_list_unspents_vanilla(&mut wallet, online, None); + let unspent_list = party.list_unspents_vanilla(None); assert_eq!(unspent_list.len(), 1); - let unspent_list = test_list_unspents_vanilla(&mut wallet, online, Some(0)); + let unspent_list = party.list_unspents_vanilla(Some(0)); assert_eq!(unspent_list.len(), 1); - test_create_utxos_default(&mut wallet, online); + party.create_utxos_default(); // one unspent (change), colored unspents not listed mine(false); - let unspent_list = test_list_unspents_vanilla(&mut wallet, online, None); + let unspent_list = party.list_unspents_vanilla(None); assert_eq!(unspent_list.len(), 1); } @@ -217,20 +204,22 @@ fn list_unspents_vanilla_success() { fn list_unspents_vanilla_skip_sync() { initialize(); - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); // no unspents if skipping sync - let unspents = wallet - .list_unspents_vanilla(online, MIN_CONFIRMATIONS, true) + let unspents = party + .wallet + .list_unspents_vanilla(party.online, MIN_CONFIRMATIONS, true) .unwrap(); assert_eq!(unspents.len(), 0); // 1 unspent after manually syncing - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -239,8 +228,9 @@ fn list_unspents_vanilla_skip_sync() { }, ) .unwrap(); - let unspents = wallet - .list_unspents_vanilla(online, MIN_CONFIRMATIONS, true) + let unspents = party + .wallet + .list_unspents_vanilla(party.online, MIN_CONFIRMATIONS, true) .unwrap(); assert_eq!(unspents.len(), 1); } @@ -253,22 +243,18 @@ fn save_new_asset_success() { let asset_amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // NIA - let nia_asset = test_issue_asset_nia(&mut wallet, online, None); - test_save_new_asset( - &mut wallet, - online, - &mut rcv_wallet, + let nia_asset = party.issue_asset_nia(None); + party.check_save_new_asset( + &mut rcv_party, &nia_asset.asset_id, Assignment::Fungible(asset_amount), ); - let txn = rcv_wallet.database().begin_transaction().unwrap(); - assert!(txn.check_asset_exists(nia_asset.asset_id.clone()).is_ok()); - let asset_model = txn.get_asset(nia_asset.asset_id.clone()).unwrap().unwrap(); - txn.commit().unwrap(); + assert!(rcv_party.db_check_asset_exists(&nia_asset.asset_id).is_ok()); + let asset_model = rcv_party.db_asset(&nia_asset.asset_id); assert_eq!(asset_model.id, nia_asset.asset_id); assert_eq!(asset_model.initial_supply, AMOUNT.to_string()); assert_eq!(asset_model.name, NAME); @@ -277,18 +263,14 @@ fn save_new_asset_success() { assert_eq!(asset_model.schema, AssetSchema::Nia); // CFA - let cfa_asset = test_issue_asset_cfa(&mut wallet, online, None, None); - test_save_new_asset( - &mut wallet, - online, - &mut rcv_wallet, + let cfa_asset = party.issue_asset_cfa(None, None); + party.check_save_new_asset( + &mut rcv_party, &cfa_asset.asset_id, Assignment::Fungible(asset_amount), ); - let txn = rcv_wallet.database().begin_transaction().unwrap(); - assert!(txn.check_asset_exists(cfa_asset.asset_id.clone()).is_ok()); - let asset_model = txn.get_asset(cfa_asset.asset_id.clone()).unwrap().unwrap(); - txn.commit().unwrap(); + assert!(rcv_party.db_check_asset_exists(&cfa_asset.asset_id).is_ok()); + let asset_model = rcv_party.db_asset(&cfa_asset.asset_id); assert_eq!(asset_model.id, cfa_asset.asset_id); assert_eq!(asset_model.initial_supply, AMOUNT.to_string()); assert_eq!(asset_model.name, NAME); @@ -298,25 +280,12 @@ fn save_new_asset_success() { // UDA let image_str = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); - let uda_asset = test_issue_asset_uda( - &mut wallet, - online, - Some(DETAILS), - Some(FILE_STR), - vec![&image_str, FILE_STR], - ); - test_create_utxos(&mut wallet, online, false, None, None, FEE_RATE, None); - test_save_new_asset( - &mut wallet, - online, - &mut rcv_wallet, - &uda_asset.asset_id, - Assignment::NonFungible, - ); - let txn = rcv_wallet.database().begin_transaction().unwrap(); - assert!(txn.check_asset_exists(uda_asset.asset_id.clone()).is_ok()); - let asset_model = txn.get_asset(uda_asset.asset_id.clone()).unwrap().unwrap(); - txn.commit().unwrap(); + let uda_asset = + party.issue_asset_uda(Some(DETAILS), Some(FILE_STR), vec![&image_str, FILE_STR]); + party.create_utxos(false, None, None, FEE_RATE, None); + party.check_save_new_asset(&mut rcv_party, &uda_asset.asset_id, Assignment::NonFungible); + assert!(rcv_party.db_check_asset_exists(&uda_asset.asset_id).is_ok()); + let asset_model = rcv_party.db_asset(&uda_asset.asset_id); assert_eq!(asset_model.id, uda_asset.asset_id); assert_eq!(asset_model.initial_supply, 1.to_string()); assert_eq!(asset_model.name, NAME); @@ -334,28 +303,15 @@ fn color_psbt_uda() { let nonce = 42u64; // wallets - let (mut wallet_send, online_send) = get_funded_noutxo_wallet!(); - let (mut wallet_recv, _online_recv) = get_empty_wallet!(); + let mut party_send = get_funded_noutxo_party!(); // create 1 UTXO and send the rest - test_create_utxos( - &mut wallet_send, - online_send, - false, - Some(1), - None, - FEE_RATE, - None, - ); - test_send_btc( - &mut wallet_send, - online_send, - &test_get_address(&mut wallet_recv), - 99_998_200, - ); + party_send.create_utxos(false, Some(1), None, FEE_RATE, None); + let mut recv_party = get_empty_party!(); + party_send.send_btc(&recv_party.get_address(), 99_998_200); // issue - let asset = test_issue_asset_uda(&mut wallet_send, online_send, None, None, vec![]); + let asset = party_send.issue_asset_uda(None, None, vec![]); // create a custom BDK wallet with p2wpkh descriptor to avoid p2tr outputs, // so that the OP_RETURN is appended at the end @@ -375,7 +331,7 @@ fn color_psbt_uda() { .address; // prepare PSBT: drain all wallet UTXOs to the p2wpkh address (no p2tr outputs, no change) - let mut tx_builder = wallet_send.bdk_wallet_mut().build_tx(); + let mut tx_builder = party_send.wallet.bdk_wallet_mut().build_tx(); tx_builder .drain_wallet() .drain_to(p2wpkh_addr.script_pubkey()) @@ -407,7 +363,10 @@ fn color_psbt_uda() { static_blinding: None, nonce: Some(nonce), }; - let (fascia, beneficiaries) = wallet_send.color_psbt(&mut psbt, coloring_info).unwrap(); + let (fascia, beneficiaries) = party_send + .wallet + .color_psbt(&mut psbt, coloring_info) + .unwrap(); // check PSBT: OP_RETURN is appended at the end assert!( @@ -464,32 +423,19 @@ fn color_psbt_fail() { let blinding = 777; // wallets - let (mut wallet_send, online_send) = get_funded_noutxo_wallet!(); - let (mut wallet_recv, _online_recv) = get_empty_wallet!(); + let mut party_send = get_funded_noutxo_party!(); + let mut recv_party = get_empty_party!(); // create 1 UTXO and send the rest - test_create_utxos( - &mut wallet_send, - online_send, - false, - Some(1), - None, - FEE_RATE, - None, - ); - test_send_btc( - &mut wallet_send, - online_send, - &test_get_address(&mut wallet_recv), - 99_998_200, - ); + party_send.create_utxos(false, Some(1), None, FEE_RATE, None); + party_send.send_btc(&recv_party.get_address(), 99_998_200); // issue - let asset = test_issue_asset_nia(&mut wallet_send, online_send, Some(&[AMOUNT])); + let asset = party_send.issue_asset_nia(Some(&[AMOUNT])); // prepare PSBT - let address = BdkAddress::from_str(&test_get_address(&mut wallet_recv)).unwrap(); - let mut tx_builder = wallet_send.bdk_wallet_mut().build_tx(); + let address = BdkAddress::from_str(&recv_party.get_address()).unwrap(); + let mut tx_builder = party_send.wallet.bdk_wallet_mut().build_tx(); tx_builder .add_recipient( address.assume_checked().script_pubkey(), @@ -523,7 +469,7 @@ fn color_psbt_fail() { static_blinding: Some(blinding), nonce: None, }; - let result = wallet_send.color_psbt(&mut psbt, coloring_info); + let result = party_send.wallet.color_psbt(&mut psbt, coloring_info); assert!( matches!(result, Err(Error::Internal { details: m }) if m.contains(&format!("contract {fake_cid} is unknown"))) ); @@ -543,7 +489,7 @@ fn color_psbt_fail() { static_blinding: Some(blinding), nonce: None, }; - let result = wallet_send.color_psbt(&mut psbt, coloring_info); + let result = party_send.wallet.color_psbt(&mut psbt, coloring_info); let msg = "invalid vout in output_map, does not exist in the given PSBT"; assert!(matches!(result, Err(Error::InvalidColoringInfo { details: m }) if m == msg)); @@ -562,7 +508,9 @@ fn color_psbt_fail() { static_blinding: Some(blinding), nonce: None, }; - let result = wallet_send.color_psbt(&mut psbt, coloring_info.clone()); + let result = party_send + .wallet + .color_psbt(&mut psbt, coloring_info.clone()); let msg = "total amount in output_map (999) greater than available (666)"; assert!(matches!(result, Err(Error::InvalidColoringInfo { details: m }) if m == msg)); } @@ -574,18 +522,18 @@ fn post_consignment_fail() { initialize(); // wallets - let wallet = get_test_wallet(false, None); + let party = get_empty_party!(); // fake data let fake_txid = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - let transfers_dir = wallet.get_transfers_dir().join(fake_txid); + let transfers_dir = party.wallet.get_transfers_dir().join(fake_txid); let consignment_path = transfers_dir.join(CONSIGNMENT_FILE); std::fs::create_dir_all(&transfers_dir).unwrap(); std::fs::File::create(&consignment_path).unwrap(); // proxy error let invalid_proxy_url = "http://127.6.6.6:7777/json-rpc"; - let result = wallet.post_consignment( + let result = party.wallet.post_consignment( invalid_proxy_url, fake_txid.to_string(), consignment_path.clone(), @@ -600,7 +548,7 @@ fn post_consignment_fail() { // invalid transport endpoint let invalid_proxy_url = &format!("http://{PROXY_HOST_MOD_API}"); - let result = wallet.post_consignment( + let result = party.wallet.post_consignment( invalid_proxy_url, fake_txid.to_string(), consignment_path.clone(), @@ -683,11 +631,13 @@ fn check_proxy_url_fail() { fn accept_transfer_fail() { initialize(); - let (mut wallet, _online) = get_empty_wallet!(); + let mut party = get_empty_party!(); // invalid txid let consignment_endpoint = RgbTransport::from_str(&PROXY_ENDPOINT).unwrap(); - let result = wallet.accept_transfer(s!("invalidTxid"), 0, consignment_endpoint, 0); + let result = party + .wallet + .accept_transfer(s!("invalidTxid"), 0, consignment_endpoint, 0); assert_matches!(result, Err(Error::InvalidTxid)); } @@ -697,10 +647,10 @@ fn accept_transfer_fail() { fn get_tx_height_fail() { initialize(); - let (wallet, _online) = get_empty_wallet!(); + let party = get_empty_party!(); // invalid txid - let result = wallet.get_tx_height(s!("invalidTxid")); + let result = party.wallet.get_tx_height(s!("invalidTxid")); assert_matches!(result, Err(Error::InvalidTxid)); } @@ -710,9 +660,9 @@ fn get_tx_height_fail() { fn update_witnesses_success() { initialize(); - let (wallet, _online) = get_empty_wallet!(); + let party = get_empty_party!(); - let result = wallet.update_witnesses(0, vec![]); + let result = party.wallet.update_witnesses(0, vec![]); assert!(result.is_ok()); } @@ -722,10 +672,11 @@ fn update_witnesses_success() { fn upsert_witness_success() { initialize(); - let (wallet, _online) = get_empty_wallet!(); + let party = get_empty_party!(); - let result = - wallet.upsert_witness(RgbTxid::from_str(FAKE_TXID).unwrap(), WitnessOrd::Tentative); + let result = party + .wallet + .upsert_witness(RgbTxid::from_str(FAKE_TXID).unwrap(), WitnessOrd::Tentative); assert!(result.is_ok()); } @@ -735,19 +686,11 @@ fn upsert_witness_success() { fn create_consignments_success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); - - let asset = test_issue_asset_nia(&mut wallet, online, None); - let receive_data = rcv_wallet - .blind_receive( - None, - Assignment::Any, - None, - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); + + let asset = party.issue_asset_nia(None); + let receive_data = rcv_party.blind_receive_asset_expiry(None, None); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -757,15 +700,14 @@ fn create_consignments_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let psbt = test_send_begin_result(&mut wallet, online, &recipient_map) - .unwrap() - .psbt; - let result = wallet.create_consignments(psbt.clone()); + let psbt = party.send_begin_result(&recipient_map).unwrap().psbt; + let result = party.wallet.create_consignments(psbt.clone()); assert!(result.is_ok()); let psbt = Psbt::from_str(&psbt).unwrap(); let txid = psbt.extract_tx().unwrap().compute_txid().to_string(); - let consignment_path = wallet - .get_asset_transfer_dir(wallet.get_transfers_dir().join(txid), &asset.asset_id) + let consignment_path = party + .wallet + .get_asset_transfer_dir(party.wallet.get_transfers_dir().join(txid), &asset.asset_id) .join(CONSIGNMENT_FILE); assert!(consignment_path.is_file()); } diff --git a/src/wallet/test/send.rs b/src/wallet/test/send.rs index ae9fe2ea..4e4237ea 100644 --- a/src/wallet/test/send.rs +++ b/src/wallet/test/send.rs @@ -10,17 +10,17 @@ fn success() { let expiration_secs = 60i64; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let asset = party.issue_asset_nia(None); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 1); assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance); // send - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -31,46 +31,28 @@ fn success() { }], )]); let expiration_timestamp = (now().unix_timestamp() + expiration_secs) as u64; - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let operation_result = wallet - .send( - online, - recipient_map.clone(), - false, - FEE_RATE, - MIN_CONFIRMATIONS, - Some(expiration_timestamp), - ) - .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let operation_result = party.send(recipient_map, FEE_RATE, Some(expiration_timestamp)); + let bak_info_after = party.db_backup_info(); let txid = operation_result.txid; assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(!txid.is_empty()); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), 1); let ce = tte_data.first().unwrap(); assert_eq!(ce.1.endpoint, PROXY_URL); assert!(ce.0.used); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( transfer_data.expiration_timestamp, Some(expiration_timestamp as i64) ); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, asset_transfer) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, rcv_asset_transfer) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, asset_transfer) = party.get_test_transfer_data(&transfer); // ack is None assert_eq!(rcv_transfer.ack, None); @@ -124,13 +106,12 @@ fn success() { // transfers progress to status WaitingConfirmations after a refresh std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + rcv_party.wait_for_refresh(None); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, rcv_asset_transfer) = rcv_party.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(Some(&asset.asset_id)); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, @@ -153,7 +134,7 @@ fn success() { assert!(updated_at > transfer_data.created_at); // asset has been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let nia_assets = rcv_assets.nia.unwrap(); let cfa_assets = rcv_assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 1); @@ -175,13 +156,13 @@ fn success() { // transfers progress to status Settled after tx mining + refresh mine(false); std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // update timestamp has been updated @@ -189,7 +170,7 @@ fn success() { assert!(transfer_data.updated_at > updated_at); // change is unspent once transfer is Settled - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo); @@ -202,15 +183,8 @@ fn success() { format!("rpc://{PROXY_HOST_MOD_PROTO}"), format!("rpc://{PROXY_HOST}"), ]; - let receive_data_api_proto = rcv_wallet - .blind_receive( - None, - Assignment::Any, - None, - transport_endpoints.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data_api_proto = + rcv_party.blind_receive_with_endpoints(None, transport_endpoints.clone()); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -220,16 +194,12 @@ fn success() { transport_endpoints, }], )]); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspents_color_count_before = unspents.iter().filter(|u| u.utxo.colorable).count(); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), 3); let mut tte_data_iter = tte_data.iter(); let (ce_0, ce_1, ce_2) = ( @@ -259,19 +229,18 @@ fn success() { .unwrap(); assert!(consignment.result.is_some()); // settle transfer - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let rcv_transfer = - get_test_transfer_recipient(&rcv_wallet, &receive_data_api_proto.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_api_proto.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspents_color_count_after = unspents.iter().filter(|u| u.utxo.colorable).count(); assert_eq!(unspents_color_count_after, unspents_color_count_before); @@ -282,15 +251,10 @@ fn success() { format!("rpc://127.6.6.6:7777/json-rpc"), format!("rpc://{PROXY_HOST}"), ]; - let receive_data_invalid_unreachable = rcv_wallet - .blind_receive( - None, - Assignment::Any, - None, - transport_endpoints.clone().into_iter().skip(1).collect(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data_invalid_unreachable = rcv_party.blind_receive_with_endpoints( + None, + transport_endpoints.clone().into_iter().skip(1).collect(), + ); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -300,19 +264,12 @@ fn success() { transport_endpoints, }], )]); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspents_color_count_before = unspents.iter().filter(|u| u.utxo.colorable).count(); - let txid = wallet - .send(online, recipient_map, false, 7, MIN_CONFIRMATIONS, None) - .unwrap() - .txid; + let txid = party.send(recipient_map, 7, None).txid; assert!(!txid.is_empty()); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), 3); let mut tte_data_iter = tte_data.iter(); let (ce_0, ce_1, ce_2) = ( @@ -335,15 +292,15 @@ fn success() { .unwrap(); assert!(consignment.result.is_some()); // settle transfer - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(transfer_data.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let unspents_color_count_after = unspents.iter().filter(|u| u.utxo.colorable).count(); assert_eq!(unspents_color_count_after, unspents_color_count_before - 2); } @@ -355,21 +312,16 @@ fn spend_all() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); + party.create_utxos(false, Some(1), None, FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); - let asset_extra = test_issue_asset_cfa( - &mut wallet, - online, - Some(&[AMOUNT * 2]), - Some(FILE_STR.to_string()), - ); + let asset = party.issue_asset_nia(None); + let asset_extra = party.issue_asset_cfa(Some(&[AMOUNT * 2]), Some(FILE_STR.to_string())); // check both assets are allocated to the same UTXO - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let unspents_with_rgb_allocations: Vec = unspents .into_iter() .filter(|u| !u.rgb_allocations.is_empty()) @@ -387,8 +339,8 @@ fn spend_all() { assert!(allocation_asset_ids.contains(&asset_extra.asset_id)); // send - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let receive_data = test_blind_receive(&mut rcv_wallet); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -398,17 +350,16 @@ fn spend_all() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, rcv_asset_transfer) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfers, asset_transfers, _) = party.get_test_transfers_sender(&txid); let transfers_for_asset = transfers.get(&asset.asset_id).unwrap(); assert_eq!(transfers_for_asset.len(), 1); let transfer = transfers_for_asset.first().unwrap(); - let (transfer_data, _) = get_test_transfer_data(&wallet, transfer); + let (transfer_data, _) = party.get_test_transfer_data(transfer); assert_eq!(asset_transfers.len(), 2); let asset_transfer = asset_transfers .iter() @@ -436,16 +387,16 @@ fn spend_all() { assert!(!asset_extra_asset_transfer.user_driven); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); + rcv_party.wait_for_refresh(None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(Some(&asset.asset_id)); + let (transfers, _, _) = party.get_test_transfers_sender(&txid); let transfers_for_asset = transfers.get(&asset.asset_id).unwrap(); assert_eq!(transfers_for_asset.len(), 1); let transfer = transfers_for_asset.first().unwrap(); - let (transfer_data, _) = get_test_transfer_data(&wallet, transfer); + let (transfer_data, _) = party.get_test_transfer_data(transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations @@ -454,21 +405,21 @@ fn spend_all() { // transfers progress to status Settled after tx mining + refresh mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfers, _, _) = party.get_test_transfers_sender(&txid); let transfers_for_asset = transfers.get(&asset.asset_id).unwrap(); assert_eq!(transfers_for_asset.len(), 1); let transfer = transfers_for_asset.first().unwrap(); - let (transfer_data, _) = get_test_transfer_data(&wallet, transfer); + let (transfer_data, _) = party.get_test_transfer_data(transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // check the completely spent asset doesn't show up in unspents anymore - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let found = unspents.iter().any(|u| { u.rgb_allocations .iter() @@ -476,7 +427,7 @@ fn spend_all() { }); assert!(!found); // check the extra asset shows up in unspents - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let found = unspents.iter().any(|u| { u.rgb_allocations .iter() @@ -495,18 +446,18 @@ fn send_twice_success() { let amount_2: u64 = 33; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // // 1st transfer // // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -516,21 +467,21 @@ fn send_twice_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet, online, &recipient_map); + let txid_1 = party.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // transfer 1 checks - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_1); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_1); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.assignments, vec![Assignment::Fungible(amount_1)] @@ -542,7 +493,7 @@ fn send_twice_success() { assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo) @@ -559,7 +510,7 @@ fn send_twice_success() { // // send - let receive_data_2 = test_blind_receive(&mut rcv_wallet); + let receive_data_2 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -569,21 +520,21 @@ fn send_twice_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet, online, &recipient_map); + let txid_2 = party.send_retry(&recipient_map); assert!(!txid_2.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // transfer 2 checks - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_2); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_2); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.assignments, vec![Assignment::Fungible(amount_2)] @@ -595,7 +546,7 @@ fn send_twice_success() { assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo) @@ -623,19 +574,19 @@ fn send_extra_success() { let amount_5: u64 = amount_1 + amount_2; // wallets - let (mut wallet_1, online_1) = get_funded_noutxo_wallet!(); - let (mut wallet_2, online_2) = get_funded_noutxo_wallet!(); + let mut party_1 = get_funded_noutxo_party!(); + let mut party_2 = get_funded_noutxo_party!(); // start with 1 UTXO only so blind receives all use the same one - test_create_utxos(&mut wallet_1, online_1, true, Some(1), None, FEE_RATE, None); - test_create_utxos(&mut wallet_2, online_2, true, Some(1), None, FEE_RATE, None); + party_1.create_utxos(true, Some(1), None, FEE_RATE, None); + party_2.create_utxos(true, Some(1), None, FEE_RATE, None); // issue - let asset_nia = test_issue_asset_nia(&mut wallet_1, online_1, None); - let asset_cfa = test_issue_asset_cfa(&mut wallet_1, online_1, Some(&[supply_cfa]), None); + let asset_nia = party_1.issue_asset_nia(None); + let asset_cfa = party_1.issue_asset_cfa(Some(&[supply_cfa]), None); // check both assets are allocated to the same UTXO - let unspents = test_list_unspents(&mut wallet_1, None, true); + let unspents = party_1.list_unspents(true); let unspents_with_rgb_allocations: Vec = unspents .into_iter() .filter(|u| !u.rgb_allocations.is_empty()) @@ -651,7 +602,7 @@ fn send_extra_success() { .collect(); assert!(allocation_asset_ids.contains(&asset_nia.asset_id)); assert!(allocation_asset_ids.contains(&asset_cfa.asset_id)); - show_unspent_colorings(&mut wallet_1, "wallet 1 after issuance"); + party_1.show_unspent_colorings("wallet 1 after issuance"); // // 1st transfer, asset_nia: wallet 1 > wallet 2 @@ -659,7 +610,7 @@ fn send_extra_success() { // send println!("\n=== send 1"); - let receive_data_1 = test_blind_receive(&mut wallet_2); + let receive_data_1 = party_2.blind_receive(); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), vec![Recipient { @@ -669,21 +620,21 @@ fn send_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_1 = party_1.send_retry(&recipient_map); assert!(!txid_1.is_empty()); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send 1, WaitingCounterparty"); + party_1.show_unspent_colorings("wallet 1 after send 1, WaitingCounterparty"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // transfer 1 checks - let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_nia.asset_id)); + let transfers_w1 = party_1.list_transfers(Some(&asset_nia.asset_id)); let transfer_w1 = transfers_w1.last().unwrap(); - let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_nia.asset_id)); + let transfers_w2 = party_2.list_transfers(Some(&asset_nia.asset_id)); let transfer_w2 = transfers_w2.last().unwrap(); // transfers data assert_eq!(transfer_w1.status, TransferStatus::Settled); @@ -704,15 +655,15 @@ fn send_extra_success() { ); assert_eq!(transfer_w2.kind, TransferKind::ReceiveBlind); // check balances - let balance_nia_w1 = test_get_asset_balance(&wallet_1, &asset_nia.asset_id); - let balance_cfa_w1 = test_get_asset_balance(&wallet_1, &asset_cfa.asset_id); + let balance_nia_w1 = party_1.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w1 = party_1.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w1.settled, supply_nia - amount_1); assert_eq!(balance_cfa_w1.settled, supply_cfa); - let balance_nia_w2 = test_get_asset_balance(&wallet_2, &asset_nia.asset_id); + let balance_nia_w2 = party_2.get_asset_balance(&asset_nia.asset_id); assert_eq!(balance_nia_w2.settled, amount_1); // sender change let change_utxo = transfer_w1.change_utxo.as_ref().unwrap(); - let unspents = test_list_unspents(&mut wallet_1, None, true); + let unspents = party_1.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| u.utxo.outpoint == *change_utxo) @@ -741,7 +692,7 @@ fn send_extra_success() { // 2nd transfer, asset_nia: wallet 1 > wallet 2 (re-using the same recipient UTXO) // - let receive_data_1b = test_blind_receive(&mut wallet_2); + let receive_data_1b = party_2.blind_receive(); println!("\n=== send 2"); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), @@ -752,21 +703,21 @@ fn send_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_2 = party_1.send_retry(&recipient_map); assert!(!txid_2.is_empty()); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send 2, WaitingCounterparty"); + party_1.show_unspent_colorings("wallet 1 after send 2, WaitingCounterparty"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // transfer 2 checks - let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_nia.asset_id)); + let transfers_w1 = party_1.list_transfers(Some(&asset_nia.asset_id)); let transfer_w1 = transfers_w1.last().unwrap(); - let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_nia.asset_id)); + let transfers_w2 = party_2.list_transfers(Some(&asset_nia.asset_id)); let transfer_w2 = transfers_w2.last().unwrap(); // transfers data assert_eq!(transfer_w1.status, TransferStatus::Settled); @@ -787,15 +738,15 @@ fn send_extra_success() { ); assert_eq!(transfer_w2.kind, TransferKind::ReceiveBlind); // check balances - let balance_nia_w1 = test_get_asset_balance(&wallet_1, &asset_nia.asset_id); - let balance_cfa_w1 = test_get_asset_balance(&wallet_1, &asset_cfa.asset_id); + let balance_nia_w1 = party_1.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w1 = party_1.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w1.settled, supply_nia - amount_1 - amount_2); assert_eq!(balance_cfa_w1.settled, supply_cfa); - let balance_nia_w2 = test_get_asset_balance(&wallet_2, &asset_nia.asset_id); + let balance_nia_w2 = party_2.get_asset_balance(&asset_nia.asset_id); assert_eq!(balance_nia_w2.settled, amount_1 + amount_2); // sender change let change_utxo = transfer_w1.change_utxo.as_ref().unwrap(); - let unspents = test_list_unspents(&mut wallet_1, None, true); + let unspents = party_1.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| u.utxo.outpoint == *change_utxo) @@ -820,7 +771,7 @@ fn send_extra_success() { assert_eq!(ca_a2.asset_id, Some(asset_cfa.asset_id.clone())); assert!(ca_a2.settled); // recipient allocations - let unspents = test_list_unspents(&mut wallet_2, None, true); + let unspents = party_2.list_unspents(true); let allocations: Vec<&RgbAllocation> = unspents.iter().flat_map(|u| &u.rgb_allocations).collect(); let a_a1: Vec<&&RgbAllocation> = allocations @@ -833,18 +784,10 @@ fn send_extra_success() { // 3rd transfer, asset_cfa (extra in previous sends): wallet 1 > wallet 2 // - test_create_utxos( - &mut wallet_1, - online_1, - true, - Some(2), - None, - FEE_RATE, - Some(1), - ); + party_1.create_utxos(true, Some(2), None, FEE_RATE, Some(1)); // send - let receive_data_2 = test_blind_receive(&mut wallet_2); + let receive_data_2 = party_2.blind_receive(); println!("\n=== send 3"); let recipient_map = HashMap::from([( asset_cfa.asset_id.clone(), @@ -855,21 +798,21 @@ fn send_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_3 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_3 = party_1.send_retry(&recipient_map); assert!(!txid_3.is_empty()); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send 3, WaitingCounterparty"); + party_1.show_unspent_colorings("wallet 1 after send 3, WaitingCounterparty"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // transfer 3 checks - let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_cfa.asset_id)); + let transfers_w2 = party_2.list_transfers(Some(&asset_cfa.asset_id)); let transfer_w2 = transfers_w2.last().unwrap(); - let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_cfa.asset_id)); + let transfers_w1 = party_1.list_transfers(Some(&asset_cfa.asset_id)); let transfer_w1 = transfers_w1.last().unwrap(); // transfers data assert_eq!(transfer_w1.status, TransferStatus::Settled); @@ -890,17 +833,17 @@ fn send_extra_success() { ); assert_eq!(transfer_w2.kind, TransferKind::ReceiveBlind); // check balances - let balance_nia_w1 = test_get_asset_balance(&wallet_1, &asset_nia.asset_id); - let balance_cfa_w1 = test_get_asset_balance(&wallet_1, &asset_cfa.asset_id); + let balance_nia_w1 = party_1.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w1 = party_1.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w1.settled, supply_nia - amount_1 - amount_2); assert_eq!(balance_cfa_w1.settled, supply_cfa - amount_3); - let balance_nia_w2 = test_get_asset_balance(&wallet_2, &asset_nia.asset_id); - let balance_cfa_w2 = test_get_asset_balance(&wallet_2, &asset_cfa.asset_id); + let balance_nia_w2 = party_2.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w2 = party_2.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w2.settled, amount_1 + amount_2); assert_eq!(balance_cfa_w2.settled, amount_3); // sender change let change_utxo = transfer_w1.change_utxo.as_ref().unwrap(); - let unspents = test_list_unspents(&mut wallet_1, None, true); + let unspents = party_1.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| u.utxo.outpoint == *change_utxo) @@ -928,13 +871,13 @@ fn send_extra_success() { assert_eq!(ca_a2.asset_id, Some(asset_cfa.asset_id.clone())); assert!(ca_a2.settled); - show_unspent_colorings(&mut wallet_2, "wallet 2 after send 3, Settled"); + party_2.show_unspent_colorings("wallet 2 after send 3, Settled"); // // 4th transfer, asset_cfa (2 asset_nia extra transitions): wallet 2 > wallet 1 // - let receive_data_4 = test_blind_receive(&mut wallet_1); + let receive_data_4 = party_1.blind_receive(); println!("\n=== send 4"); let recipient_map = HashMap::from([( asset_cfa.asset_id.clone(), @@ -945,21 +888,21 @@ fn send_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_4 = test_send(&mut wallet_2, online_2, &recipient_map); + let txid_4 = party_2.send_retry(&recipient_map); assert!(!txid_4.is_empty()); - show_unspent_colorings(&mut wallet_2, "wallet 2 after send 4, WaitingCounterparty"); + party_2.show_unspent_colorings("wallet 2 after send 4, WaitingCounterparty"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); // transfer 4 checks - let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_cfa.asset_id)); + let transfers_w2 = party_2.list_transfers(Some(&asset_cfa.asset_id)); let transfer_w2 = transfers_w2.last().unwrap(); - let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_cfa.asset_id)); + let transfers_w1 = party_1.list_transfers(Some(&asset_cfa.asset_id)); let transfer_w1 = transfers_w1.last().unwrap(); // transfers data assert_eq!(transfer_w2.status, TransferStatus::Settled); @@ -980,17 +923,17 @@ fn send_extra_success() { ); assert_eq!(transfer_w1.kind, TransferKind::ReceiveBlind); // check balances - let balance_nia_w1 = test_get_asset_balance(&wallet_1, &asset_nia.asset_id); - let balance_cfa_w1 = test_get_asset_balance(&wallet_1, &asset_cfa.asset_id); + let balance_nia_w1 = party_1.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w1 = party_1.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w1.settled, supply_nia - amount_1 - amount_2); assert_eq!(balance_cfa_w1.settled, supply_cfa - amount_3 + amount_4); - let balance_nia_w2 = test_get_asset_balance(&wallet_2, &asset_nia.asset_id); - let balance_cfa_w2 = test_get_asset_balance(&wallet_2, &asset_cfa.asset_id); + let balance_nia_w2 = party_2.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w2 = party_2.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w2.settled, amount_1 + amount_2); assert_eq!(balance_cfa_w2.settled, amount_3 - amount_4); // sender change let change_utxo = transfer_w2.change_utxo.as_ref().unwrap(); - let unspents = test_list_unspents(&mut wallet_2, None, true); + let unspents = party_2.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| u.utxo.outpoint == *change_utxo) @@ -1039,7 +982,7 @@ fn send_extra_success() { // 5th transfer, asset_nia (merging 2 allocations, no change): wallet 2 > wallet 1 // - let receive_data_5 = test_blind_receive(&mut wallet_1); + let receive_data_5 = party_1.blind_receive(); println!("\n=== send 5"); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), @@ -1050,21 +993,21 @@ fn send_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_5 = test_send(&mut wallet_2, online_2, &recipient_map); + let txid_5 = party_2.send_retry(&recipient_map); assert!(!txid_5.is_empty()); - show_unspent_colorings(&mut wallet_2, "wallet 2 after send 5, WaitingCounterparty"); + party_2.show_unspent_colorings("wallet 2 after send 5, WaitingCounterparty"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); // transfer 5 checks - let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_nia.asset_id)); + let transfers_w2 = party_2.list_transfers(Some(&asset_nia.asset_id)); let transfer_w2 = transfers_w2.last().unwrap(); - let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_nia.asset_id)); + let transfers_w1 = party_1.list_transfers(Some(&asset_nia.asset_id)); let transfer_w1 = transfers_w1.last().unwrap(); // transfers data assert_eq!(transfer_w2.status, TransferStatus::Settled); @@ -1082,12 +1025,12 @@ fn send_extra_success() { ); assert_eq!(transfer_w1.kind, TransferKind::ReceiveBlind); // check balances - let balance_nia_w1 = test_get_asset_balance(&wallet_1, &asset_nia.asset_id); - let balance_cfa_w1 = test_get_asset_balance(&wallet_1, &asset_cfa.asset_id); + let balance_nia_w1 = party_1.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w1 = party_1.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w1.settled, supply_nia); assert_eq!(balance_cfa_w1.settled, supply_cfa - amount_3 + amount_4); - let balance_nia_w2 = test_get_asset_balance(&wallet_2, &asset_nia.asset_id); - let balance_cfa_w2 = test_get_asset_balance(&wallet_2, &asset_cfa.asset_id); + let balance_nia_w2 = party_2.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w2 = party_2.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w2.settled, 0); assert_eq!(balance_cfa_w2.settled, amount_3 - amount_4); @@ -1095,7 +1038,7 @@ fn send_extra_success() { // 6th transfer, asset_nia (send all, 2 allocations, no change): wallet 1 > wallet 2 // - let receive_data_6 = test_blind_receive(&mut wallet_2); + let receive_data_6 = party_2.blind_receive(); println!("\n=== send 6"); let recipient_map = HashMap::from([( asset_nia.asset_id.clone(), @@ -1106,21 +1049,21 @@ fn send_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_6 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_6 = party_1.send_retry(&recipient_map); assert!(!txid_6.is_empty()); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send 6, WaitingCounterparty"); + party_1.show_unspent_colorings("wallet 1 after send 6, WaitingCounterparty"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // transfer 6 checks - let transfers_w1 = test_list_transfers(&wallet_1, Some(&asset_nia.asset_id)); + let transfers_w1 = party_1.list_transfers(Some(&asset_nia.asset_id)); let transfer_w1 = transfers_w1.last().unwrap(); - let transfers_w2 = test_list_transfers(&wallet_2, Some(&asset_nia.asset_id)); + let transfers_w2 = party_2.list_transfers(Some(&asset_nia.asset_id)); let transfer_w2 = transfers_w2.last().unwrap(); // transfers data assert_eq!(transfer_w1.status, TransferStatus::Settled); @@ -1138,12 +1081,12 @@ fn send_extra_success() { ); assert_eq!(transfer_w2.kind, TransferKind::ReceiveBlind); // check balances - let balance_nia_w2 = test_get_asset_balance(&wallet_2, &asset_nia.asset_id); - let balance_cfa_w2 = test_get_asset_balance(&wallet_2, &asset_cfa.asset_id); + let balance_nia_w2 = party_2.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w2 = party_2.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w2.settled, supply_nia); assert_eq!(balance_cfa_w2.settled, amount_3 - amount_4); - let balance_nia_w1 = test_get_asset_balance(&wallet_1, &asset_nia.asset_id); - let balance_cfa_w1 = test_get_asset_balance(&wallet_1, &asset_cfa.asset_id); + let balance_nia_w1 = party_1.get_asset_balance(&asset_nia.asset_id); + let balance_cfa_w1 = party_1.get_asset_balance(&asset_cfa.asset_id); assert_eq!(balance_nia_w1.settled, 0); assert_eq!(balance_cfa_w1.settled, supply_cfa - amount_3 + amount_4); } @@ -1160,26 +1103,21 @@ fn send_received_success() { let amount_2b: u64 = 4; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); // issue - let asset_nia = test_issue_asset_nia(&mut wallet_1, online_1, None); - let asset_cfa = test_issue_asset_cfa( - &mut wallet_1, - online_1, - Some(&[AMOUNT * 2]), - Some(FILE_STR.to_string()), - ); + let asset_nia = party_1.issue_asset_nia(None); + let asset_cfa = party_1.issue_asset_cfa(Some(&[AMOUNT * 2]), Some(FILE_STR.to_string())); // // 1st transfer: wallet 1 > wallet 2 // // send - let receive_data_a20 = test_blind_receive(&mut wallet_2); - let receive_data_a25 = test_blind_receive(&mut wallet_2); + let receive_data_a20 = party_2.blind_receive(); + let receive_data_a25 = party_2.blind_receive(); let recipient_map = HashMap::from([ ( asset_nia.asset_id.clone(), @@ -1200,30 +1138,30 @@ fn send_received_success() { }], ), ]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_1 = party_1.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // transfer 1 checks - let (transfers_w1, _, _) = get_test_transfers_sender(&wallet_1, &txid_1); + let (transfers_w1, _, _) = party_1.get_test_transfers_sender(&txid_1); let transfers_for_asset_nia = transfers_w1.get(&asset_nia.asset_id).unwrap(); let transfers_for_asset_cfa = transfers_w1.get(&asset_cfa.asset_id).unwrap(); assert_eq!(transfers_for_asset_nia.len(), 1); assert_eq!(transfers_for_asset_cfa.len(), 1); let transfer_w1a = transfers_for_asset_nia.first().unwrap(); let transfer_w1b = transfers_for_asset_cfa.first().unwrap(); - let transfer_w2a = get_test_transfer_recipient(&wallet_2, &receive_data_a20.recipient_id); - let transfer_w2b = get_test_transfer_recipient(&wallet_2, &receive_data_a25.recipient_id); - let (transfer_data_w1a, _) = get_test_transfer_data(&wallet_1, transfer_w1a); - let (transfer_data_w1b, _) = get_test_transfer_data(&wallet_1, transfer_w1b); - let (transfer_data_w2a, _) = get_test_transfer_data(&wallet_2, &transfer_w2a); - let (transfer_data_w2b, _) = get_test_transfer_data(&wallet_2, &transfer_w2b); + let transfer_w2a = party_2.get_test_transfer_recipient(&receive_data_a20.recipient_id); + let transfer_w2b = party_2.get_test_transfer_recipient(&receive_data_a25.recipient_id); + let (transfer_data_w1a, _) = party_1.get_test_transfer_data(transfer_w1a); + let (transfer_data_w1b, _) = party_1.get_test_transfer_data(transfer_w1b); + let (transfer_data_w2a, _) = party_2.get_test_transfer_data(&transfer_w2a); + let (transfer_data_w2b, _) = party_2.get_test_transfer_data(&transfer_w2b); assert_eq!( transfer_w1a.requested_assignment, Some(Assignment::Fungible(amount_1a)) @@ -1245,7 +1183,7 @@ fn send_received_success() { assert_eq!(transfer_data_w2a.status, TransferStatus::Settled); assert_eq!(transfer_data_w2b.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet_1, None, true); + let unspents = party_1.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w1a.change_utxo) @@ -1274,8 +1212,8 @@ fn send_received_success() { // // send - let receive_data_b20 = test_blind_receive(&mut wallet_3); - let receive_data_b25 = test_blind_receive(&mut wallet_3); + let receive_data_b20 = party_3.blind_receive(); + let receive_data_b25 = party_3.blind_receive(); let recipient_map = HashMap::from([ ( asset_nia.asset_id.clone(), @@ -1296,30 +1234,30 @@ fn send_received_success() { }], ), ]); - let txid_2 = test_send(&mut wallet_2, online_2, &recipient_map); + let txid_2 = party_2.send_retry(&recipient_map); assert!(!txid_2.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); // transfer 2 checks - let (transfers_w2, _, _) = get_test_transfers_sender(&wallet_2, &txid_2); + let (transfers_w2, _, _) = party_2.get_test_transfers_sender(&txid_2); let transfers_for_asset_nia = transfers_w2.get(&asset_nia.asset_id).unwrap(); let transfers_for_asset_cfa = transfers_w2.get(&asset_cfa.asset_id).unwrap(); assert_eq!(transfers_for_asset_nia.len(), 1); assert_eq!(transfers_for_asset_cfa.len(), 1); let transfer_w2a = transfers_for_asset_nia.first().unwrap(); let transfer_w2b = transfers_for_asset_cfa.first().unwrap(); - let transfer_w3a = get_test_transfer_recipient(&wallet_3, &receive_data_b20.recipient_id); - let transfer_w3b = get_test_transfer_recipient(&wallet_3, &receive_data_b25.recipient_id); - let (transfer_data_w2a, _) = get_test_transfer_data(&wallet_2, transfer_w2a); - let (transfer_data_w2b, _) = get_test_transfer_data(&wallet_2, transfer_w2b); - let (transfer_data_w3a, _) = get_test_transfer_data(&wallet_3, &transfer_w3a); - let (transfer_data_w3b, _) = get_test_transfer_data(&wallet_3, &transfer_w3b); + let transfer_w3a = party_3.get_test_transfer_recipient(&receive_data_b20.recipient_id); + let transfer_w3b = party_3.get_test_transfer_recipient(&receive_data_b25.recipient_id); + let (transfer_data_w2a, _) = party_2.get_test_transfer_data(transfer_w2a); + let (transfer_data_w2b, _) = party_2.get_test_transfer_data(transfer_w2b); + let (transfer_data_w3a, _) = party_3.get_test_transfer_data(&transfer_w3a); + let (transfer_data_w3b, _) = party_3.get_test_transfer_data(&transfer_w3b); assert_eq!( transfer_w2a.requested_assignment, Some(Assignment::Fungible(amount_2a)) @@ -1341,7 +1279,7 @@ fn send_received_success() { assert_eq!(transfer_data_w3a.status, TransferStatus::Settled); assert_eq!(transfer_data_w3b.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet_2, None, true); + let unspents = party_2.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w2a.change_utxo) @@ -1366,11 +1304,7 @@ fn send_received_success() { ); // check CFA asset has the correct media after being received - let cfa_assets = wallet_3 - .list_assets(vec![AssetSchema::Cfa]) - .unwrap() - .cfa - .unwrap(); + let cfa_assets = party_3.list_assets(&[AssetSchema::Cfa]).cfa.unwrap(); assert_eq!(cfa_assets.len(), 1); let recv_asset = cfa_assets.first().unwrap(); let dst_path = recv_asset.media.as_ref().unwrap().file_path.clone(); @@ -1392,34 +1326,20 @@ fn send_received_uda_success() { let image_str = ["tests", "qrcode.png"].join(MAIN_SEPARATOR_STR); // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); // issue - let asset = test_issue_asset_uda( - &mut wallet_1, - online_1, - Some(DETAILS), - Some(FILE_STR), - vec![&image_str, FILE_STR], - ); - let txn = wallet_1.database().begin_transaction().unwrap(); - assert!( - txn.get_asset(asset.asset_id.clone()) - .unwrap() - .unwrap() - .media_idx - .is_none() - ); - txn.commit().unwrap(); + let asset = party_1.issue_asset_uda(Some(DETAILS), Some(FILE_STR), vec![&image_str, FILE_STR]); + assert!(party_1.db_asset(&asset.asset_id).media_idx.is_none()); // // 1st transfer: wallet 1 > wallet 2 // // send - let receive_data_1 = test_blind_receive(&mut wallet_2); + let receive_data_1 = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -1429,21 +1349,21 @@ fn send_received_uda_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_1 = party_1.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); // transfer 1 checks - let (transfer_w1, _, _) = get_test_transfer_sender(&wallet_1, &txid_1); - let transfer_w2 = get_test_transfer_recipient(&wallet_2, &receive_data_1.recipient_id); - let (transfer_data_w1, _) = get_test_transfer_data(&wallet_1, &transfer_w1); - let (transfer_data_w2, _) = get_test_transfer_data(&wallet_2, &transfer_w2); + let (transfer_w1, _, _) = party_1.get_test_transfer_sender(&txid_1); + let transfer_w2 = party_2.get_test_transfer_recipient(&receive_data_1.recipient_id); + let (transfer_data_w1, _) = party_1.get_test_transfer_data(&transfer_w1); + let (transfer_data_w2, _) = party_2.get_test_transfer_data(&transfer_w2); assert_eq!(transfer_data_w1.assignments, vec![]); assert_eq!(transfer_data_w2.assignments, vec![Assignment::NonFungible]); assert_eq!(transfer_data_w1.status, TransferStatus::Settled); @@ -1454,7 +1374,7 @@ fn send_received_uda_success() { // // send - let receive_data_2 = test_witness_receive(&mut wallet_3); + let receive_data_2 = party_3.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -1467,41 +1387,29 @@ fn send_received_uda_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_2, online_2, &recipient_map); + let txid_2 = party_2.send_retry(&recipient_map); assert!(!txid_2.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_3, online_3, None, None); - let txn = wallet_3.database().begin_transaction().unwrap(); - assert!( - txn.get_asset(asset.asset_id.clone()) - .unwrap() - .unwrap() - .media_idx - .is_none() - ); - txn.commit().unwrap(); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); + party_3.wait_for_refresh(None); + assert!(party_3.db_asset(&asset.asset_id).media_idx.is_none()); + party_2.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(Some(&asset.asset_id)); // transfer 2 checks - let transfer_w3 = get_test_transfer_recipient(&wallet_3, &receive_data_2.recipient_id); - let (transfer_w2, _, _) = get_test_transfer_sender(&wallet_2, &txid_2); - let (transfer_data_w3, _) = get_test_transfer_data(&wallet_3, &transfer_w3); - let (transfer_data_w2, _) = get_test_transfer_data(&wallet_2, &transfer_w2); + let transfer_w3 = party_3.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (transfer_w2, _, _) = party_2.get_test_transfer_sender(&txid_2); + let (transfer_data_w3, _) = party_3.get_test_transfer_data(&transfer_w3); + let (transfer_data_w2, _) = party_2.get_test_transfer_data(&transfer_w2); assert_eq!(transfer_data_w3.assignments, vec![Assignment::NonFungible]); assert_eq!(transfer_data_w2.assignments, vec![]); assert_eq!(transfer_data_w3.status, TransferStatus::Settled); assert_eq!(transfer_data_w2.status, TransferStatus::Settled); // check asset has been received correctly - let uda_assets = wallet_3 - .list_assets(vec![AssetSchema::Uda]) - .unwrap() - .uda - .unwrap(); + let uda_assets = party_3.list_assets(&[AssetSchema::Uda]).uda.unwrap(); assert_eq!(uda_assets.len(), 1); let recv_asset = uda_assets.first().unwrap(); assert_eq!(recv_asset.asset_id, asset.asset_id); @@ -1560,19 +1468,19 @@ fn send_received_cfa_success() { let amount_2: u64 = 7; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); // issue - let asset = test_issue_asset_cfa(&mut wallet_1, online_1, None, Some(FILE_STR.to_string())); + let asset = party_1.issue_asset_cfa(None, Some(FILE_STR.to_string())); // // 1st transfer: wallet 1 > wallet 2 // // send - let receive_data_1 = test_blind_receive(&mut wallet_2); + let receive_data_1 = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -1582,21 +1490,21 @@ fn send_received_cfa_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map); + let txid_1 = party_1.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); // transfer 1 checks - let (transfer_w1, _, _) = get_test_transfer_sender(&wallet_1, &txid_1); - let transfer_w2 = get_test_transfer_recipient(&wallet_2, &receive_data_1.recipient_id); - let (transfer_data_w1, _) = get_test_transfer_data(&wallet_1, &transfer_w1); - let (transfer_data_w2, _) = get_test_transfer_data(&wallet_2, &transfer_w2); + let (transfer_w1, _, _) = party_1.get_test_transfer_sender(&txid_1); + let transfer_w2 = party_2.get_test_transfer_recipient(&receive_data_1.recipient_id); + let (transfer_data_w1, _) = party_1.get_test_transfer_data(&transfer_w1); + let (transfer_data_w2, _) = party_2.get_test_transfer_data(&transfer_w2); assert_eq!( transfer_data_w1.assignments, vec![Assignment::Fungible(AMOUNT - amount_1)] @@ -1608,7 +1516,7 @@ fn send_received_cfa_success() { assert_eq!(transfer_data_w1.status, TransferStatus::Settled); assert_eq!(transfer_data_w2.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet_1, None, true); + let unspents = party_1.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w1.change_utxo) @@ -1625,7 +1533,7 @@ fn send_received_cfa_success() { // // send - let receive_data_2 = test_blind_receive(&mut wallet_3); + let receive_data_2 = party_3.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -1635,21 +1543,21 @@ fn send_received_cfa_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_2, online_2, &recipient_map); + let txid_2 = party_2.send_retry(&recipient_map); assert!(!txid_2.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(Some(&asset.asset_id)); // transfer 2 checks - let transfer_w3 = get_test_transfer_recipient(&wallet_3, &receive_data_2.recipient_id); - let (transfer_w2, _, _) = get_test_transfer_sender(&wallet_2, &txid_2); - let (transfer_data_w3, _) = get_test_transfer_data(&wallet_3, &transfer_w3); - let (transfer_data_w2, _) = get_test_transfer_data(&wallet_2, &transfer_w2); + let transfer_w3 = party_3.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (transfer_w2, _, _) = party_2.get_test_transfer_sender(&txid_2); + let (transfer_data_w3, _) = party_3.get_test_transfer_data(&transfer_w3); + let (transfer_data_w2, _) = party_2.get_test_transfer_data(&transfer_w2); assert_eq!( transfer_data_w3.assignments, vec![Assignment::Fungible(amount_2)] @@ -1661,7 +1569,7 @@ fn send_received_cfa_success() { assert_eq!(transfer_data_w3.status, TransferStatus::Settled); assert_eq!(transfer_data_w2.status, TransferStatus::Settled); - let unspents = test_list_unspents(&mut wallet_2, None, true); + let unspents = party_2.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_w2.change_utxo) @@ -1673,11 +1581,7 @@ fn send_received_cfa_success() { Assignment::Fungible(amount_1 - amount_2) ); // check asset has been received correctly - let cfa_assets = wallet_3 - .list_assets(vec![AssetSchema::Cfa]) - .unwrap() - .cfa - .unwrap(); + let cfa_assets = party_3.list_assets(&[AssetSchema::Cfa]).cfa.unwrap(); assert_eq!(cfa_assets.len(), 1); let recv_asset = cfa_assets.first().unwrap(); assert_eq!(recv_asset.asset_id, asset.asset_id); @@ -1716,15 +1620,15 @@ fn receive_multiple_same_asset_success() { let amount_2: u64 = 33; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); - let receive_data_2 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); + let receive_data_2 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -1742,16 +1646,16 @@ fn receive_multiple_same_asset_success() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); + let rcv_transfer_1 = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); let (rcv_transfer_data_1, rcv_asset_transfer_1) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_1); + rcv_party.get_test_transfer_data(&rcv_transfer_1); let (rcv_transfer_data_2, rcv_asset_transfer_2) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); - let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid); + rcv_party.get_test_transfer_data(&rcv_transfer_2); + let (transfers, asset_transfers, _) = party.get_test_transfers_sender(&txid); assert_eq!(asset_transfers.len(), 1); assert_eq!(transfers.len(), 1); let asset_transfer = asset_transfers.first().unwrap(); @@ -1765,8 +1669,8 @@ fn receive_multiple_same_asset_success() { .iter() .find(|t| t.recipient_id == Some(receive_data_2.recipient_id.clone())) .unwrap(); - let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1); - let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2); + let (transfer_data_1, _) = party.get_test_transfer_data(transfer_1); + let (transfer_data_2, _) = party.get_test_transfer_data(transfer_2); // ack is None assert_eq!(rcv_transfer_1.ack, None); @@ -1857,16 +1761,16 @@ fn receive_multiple_same_asset_success() { // transfers progress to status WaitingConfirmations after a refresh std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); + let rcv_transfer_1 = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); let (rcv_transfer_data_1, rcv_asset_transfer_1) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_1); + rcv_party.get_test_transfer_data(&rcv_transfer_1); let (rcv_transfer_data_2, rcv_asset_transfer_2) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); - let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid); + rcv_party.get_test_transfer_data(&rcv_transfer_2); + let (transfers, _, _) = party.get_test_transfers_sender(&txid); assert_eq!(transfers.len(), 1); let transfers_for_asset = transfers.get(&asset.asset_id).unwrap(); assert_eq!(transfers_for_asset.len(), 2); @@ -1878,8 +1782,8 @@ fn receive_multiple_same_asset_success() { .iter() .find(|t| t.recipient_id == Some(receive_data_2.recipient_id.clone())) .unwrap(); - let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1); - let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2); + let (transfer_data_1, _) = party.get_test_transfer_data(transfer_1); + let (transfer_data_2, _) = party.get_test_transfer_data(transfer_2); assert_eq!( rcv_transfer_data_1.status, @@ -1919,14 +1823,14 @@ fn receive_multiple_same_asset_success() { // transfers progress to status Settled after tx mining + refresh mine(false); std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - - let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); - let (rcv_transfer_data_1, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_1); - let (rcv_transfer_data_2, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); - let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + + let rcv_transfer_1 = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (rcv_transfer_data_1, _) = rcv_party.get_test_transfer_data(&rcv_transfer_1); + let (rcv_transfer_data_2, _) = rcv_party.get_test_transfer_data(&rcv_transfer_2); + let (transfers, _, _) = party.get_test_transfers_sender(&txid); assert_eq!(transfers.len(), 1); let transfers_for_asset = transfers.get(&asset.asset_id).unwrap(); assert_eq!(transfers_for_asset.len(), 2); @@ -1938,8 +1842,8 @@ fn receive_multiple_same_asset_success() { .iter() .find(|t| t.recipient_id == Some(receive_data_2.recipient_id.clone())) .unwrap(); - let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1); - let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2); + let (transfer_data_1, _) = party.get_test_transfer_data(transfer_1); + let (transfer_data_2, _) = party.get_test_transfer_data(transfer_2); assert_eq!(rcv_transfer_data_1.status, TransferStatus::Settled); assert_eq!(rcv_transfer_data_2.status, TransferStatus::Settled); @@ -1952,7 +1856,7 @@ fn receive_multiple_same_asset_success() { assert!(transfer_data_2.updated_at > updated_at_1); // change is unspent once transfer is Settled - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_1.change_utxo); @@ -1969,12 +1873,13 @@ fn receive_multiple_different_assets_success() { let amount_2: u64 = 33; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset_1 = test_issue_asset_nia(&mut wallet, online, None); - let asset_2 = wallet + let asset_1 = party.issue_asset_nia(None); + let asset_2 = party + .wallet .issue_asset_cfa( s!("NAME2"), Some(DETAILS.to_string()), @@ -1985,8 +1890,8 @@ fn receive_multiple_different_assets_success() { .unwrap(); // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); - let receive_data_2 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); + let receive_data_2 = rcv_party.blind_receive(); let recipient_map = HashMap::from([ ( asset_1.asset_id.clone(), @@ -2007,16 +1912,16 @@ fn receive_multiple_different_assets_success() { }], ), ]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); + let rcv_transfer_1 = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); let (rcv_transfer_data_1, rcv_asset_transfer_1) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_1); + rcv_party.get_test_transfer_data(&rcv_transfer_1); let (rcv_transfer_data_2, rcv_asset_transfer_2) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); - let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid); + rcv_party.get_test_transfer_data(&rcv_transfer_2); + let (transfers, asset_transfers, _) = party.get_test_transfers_sender(&txid); assert_eq!(asset_transfers.len(), 2); assert_eq!(transfers.len(), 2); let asset_transfer_1 = asset_transfers @@ -2033,8 +1938,8 @@ fn receive_multiple_different_assets_success() { assert_eq!(transfers_for_asset_2.len(), 1); let transfer_1 = transfers_for_asset_1.first().unwrap(); let transfer_2 = transfers_for_asset_2.first().unwrap(); - let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1); - let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2); + let (transfer_data_1, _) = party.get_test_transfer_data(transfer_1); + let (transfer_data_2, _) = party.get_test_transfer_data(transfer_2); // ack is None assert_eq!(rcv_transfer_1.ack, None); @@ -2127,16 +2032,16 @@ fn receive_multiple_different_assets_success() { // transfers progress to status WaitingConfirmations after a refresh std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); - let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); + let rcv_transfer_1 = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); let (rcv_transfer_data_1, rcv_asset_transfer_1) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_1); + rcv_party.get_test_transfer_data(&rcv_transfer_1); let (rcv_transfer_data_2, rcv_asset_transfer_2) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); - let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid); + rcv_party.get_test_transfer_data(&rcv_transfer_2); + let (transfers, _, _) = party.get_test_transfers_sender(&txid); assert_eq!(transfers.len(), 2); let transfers_for_asset_1 = transfers.get(&asset_1.asset_id).unwrap(); let transfers_for_asset_2 = transfers.get(&asset_2.asset_id).unwrap(); @@ -2144,8 +2049,8 @@ fn receive_multiple_different_assets_success() { assert_eq!(transfers_for_asset_2.len(), 1); let transfer_1 = transfers_for_asset_1.first().unwrap(); let transfer_2 = transfers_for_asset_2.first().unwrap(); - let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1); - let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2); + let (transfer_data_1, _) = party.get_test_transfer_data(transfer_1); + let (transfer_data_2, _) = party.get_test_transfer_data(transfer_2); assert_eq!( rcv_transfer_data_1.status, @@ -2189,7 +2094,7 @@ fn receive_multiple_different_assets_success() { assert!(updated_at_2 > transfer_data_2.created_at); // assets have been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let nia_assets = rcv_assets.nia.unwrap(); let cfa_assets = rcv_assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 1); @@ -2225,14 +2130,14 @@ fn receive_multiple_different_assets_success() { // transfers progress to status Settled after tx mining + refresh std::thread::sleep(Duration::from_millis(1000)); // make sure updated_at will be at least +1s mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); - - let rcv_transfer_1 = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let rcv_transfer_2 = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); - let (rcv_transfer_data_1, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_1); - let (rcv_transfer_data_2, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer_2); - let (transfers, _, _) = get_test_transfers_sender(&wallet, &txid); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); + + let rcv_transfer_1 = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let rcv_transfer_2 = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (rcv_transfer_data_1, _) = rcv_party.get_test_transfer_data(&rcv_transfer_1); + let (rcv_transfer_data_2, _) = rcv_party.get_test_transfer_data(&rcv_transfer_2); + let (transfers, _, _) = party.get_test_transfers_sender(&txid); assert_eq!(transfers.len(), 2); let transfers_for_asset_1 = transfers.get(&asset_1.asset_id).unwrap(); let transfers_for_asset_2 = transfers.get(&asset_2.asset_id).unwrap(); @@ -2240,8 +2145,8 @@ fn receive_multiple_different_assets_success() { assert_eq!(transfers_for_asset_2.len(), 1); let transfer_1 = transfers_for_asset_1.first().unwrap(); let transfer_2 = transfers_for_asset_2.first().unwrap(); - let (transfer_data_1, _) = get_test_transfer_data(&wallet, transfer_1); - let (transfer_data_2, _) = get_test_transfer_data(&wallet, transfer_2); + let (transfer_data_1, _) = party.get_test_transfer_data(transfer_1); + let (transfer_data_2, _) = party.get_test_transfer_data(transfer_2); assert_eq!(rcv_transfer_data_1.status, TransferStatus::Settled); assert_eq!(rcv_transfer_data_2.status, TransferStatus::Settled); @@ -2254,7 +2159,7 @@ fn receive_multiple_different_assets_success() { assert!(transfer_data_2.updated_at > updated_at_1); // change is unspent once transfer is Settled - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data_1.change_utxo); @@ -2273,29 +2178,29 @@ fn batch_donation_success() { let amount_b2 = 22; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet_1, rcv_online_1) = get_funded_wallet!(); - let (mut rcv_wallet_2, rcv_online_2) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party_1 = get_funded_party!(); + let mut rcv_party_2 = get_funded_party!(); // issue - let asset_a = test_issue_asset_nia(&mut wallet, online, None); - let asset_b = test_issue_asset_nia(&mut wallet, online, None); - let _asset_c = test_issue_asset_nia(&mut wallet, online, None); + let asset_a = party.issue_asset_nia(None); + let asset_b = party.issue_asset_nia(None); + let _asset_c = party.issue_asset_nia(None); - show_unspent_colorings(&mut wallet, "after issuances"); + party.show_unspent_colorings("after issuances"); // check each assets is allocated to a different UTXO - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let unspents_with_rgb_allocations = unspents .into_iter() .filter(|u| !u.rgb_allocations.is_empty()); assert_eq!(unspents_with_rgb_allocations.count(), 3); // blind - let receive_data_a1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_a2 = test_blind_receive(&mut rcv_wallet_2); - let receive_data_b1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_b2 = test_blind_receive(&mut rcv_wallet_2); + let receive_data_a1 = rcv_party_1.blind_receive(); + let receive_data_a2 = rcv_party_2.blind_receive(); + let receive_data_b1 = rcv_party_1.blind_receive(); + let receive_data_b2 = rcv_party_2.blind_receive(); // send multiple assets to multiple recipients let recipient_map = HashMap::from([ @@ -2334,9 +2239,10 @@ fn batch_donation_success() { ], ), ]); - let txid = wallet + let txid = party + .wallet .send( - online, + party.online, recipient_map, true, FEE_RATE, @@ -2347,13 +2253,13 @@ fn batch_donation_success() { .txid; assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after send"); + party.show_unspent_colorings("after send"); // check change UTXO has all the expected allocations - let transfers_a = test_list_transfers(&wallet, Some(&asset_a.asset_id)); + let transfers_a = party.list_transfers(Some(&asset_a.asset_id)); let transfer_a = transfers_a.last().unwrap(); let change_utxo = transfer_a.change_utxo.as_ref().unwrap(); - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let change_unspent = unspents .into_iter() .find(|u| u.utxo.outpoint == *change_utxo) @@ -2377,21 +2283,21 @@ fn batch_donation_success() { // take receiver transfers from WaitingCounterparty to Settled // (send_batch doesn't wait for recipient ACKs and proceeds to broadcast) - wait_for_refresh(&mut rcv_wallet_1, rcv_online_1, None, None); - wait_for_refresh(&mut rcv_wallet_2, rcv_online_2, None, None); - test_list_transfers(&rcv_wallet_1, Some(&asset_a.asset_id)); - test_list_transfers(&rcv_wallet_1, Some(&asset_b.asset_id)); - test_list_transfers(&rcv_wallet_2, Some(&asset_a.asset_id)); - test_list_transfers(&rcv_wallet_2, Some(&asset_b.asset_id)); + rcv_party_1.wait_for_refresh(None); + rcv_party_2.wait_for_refresh(None); + rcv_party_1.list_transfers(Some(&asset_a.asset_id)); + rcv_party_1.list_transfers(Some(&asset_b.asset_id)); + rcv_party_2.list_transfers(Some(&asset_a.asset_id)); + rcv_party_2.list_transfers(Some(&asset_b.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet_1, rcv_online_1, None, None); - wait_for_refresh(&mut rcv_wallet_2, rcv_online_2, None, None); - test_list_transfers(&rcv_wallet_1, Some(&asset_a.asset_id)); - test_list_transfers(&rcv_wallet_1, Some(&asset_b.asset_id)); - test_list_transfers(&rcv_wallet_2, Some(&asset_a.asset_id)); - test_list_transfers(&rcv_wallet_2, Some(&asset_b.asset_id)); - - show_unspent_colorings(&mut wallet, "after send, settled"); + rcv_party_1.wait_for_refresh(None); + rcv_party_2.wait_for_refresh(None); + rcv_party_1.list_transfers(Some(&asset_a.asset_id)); + rcv_party_1.list_transfers(Some(&asset_b.asset_id)); + rcv_party_2.list_transfers(Some(&asset_a.asset_id)); + rcv_party_2.list_transfers(Some(&asset_b.asset_id)); + + party.show_unspent_colorings("after send, settled"); } #[cfg(feature = "electrum")] @@ -2403,22 +2309,15 @@ fn reuse_failed_blinded_success() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue asset - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // 1st transfer - let receive_data = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + 60) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data = + rcv_party.blind_receive_asset_expiry(None, Some((now().unix_timestamp() + 60) as u64)); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -2428,18 +2327,18 @@ fn reuse_failed_blinded_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); assert!(!send_result.txid.is_empty()); // try to send again and check the asset is not spendable - let result = test_send_result(&mut wallet, online, &recipient_map); + let result = party.send_result(&recipient_map); assert_matches!(result, Err(Error::InsufficientAssignments { asset_id: t, available: a }) if t == asset.asset_id && a == AssignmentsCollection::default()); // fail transfer so asset allocation can be spent again - test_fail_transfers_single(&mut wallet, online, send_result.batch_transfer_idx); + party.fail_transfers_single(send_result.batch_transfer_idx); // 2nd transfer using the same blinded UTXO - let result = test_send_result(&mut wallet, online, &recipient_map); + let result = party.send_result(&recipient_map); assert!(matches!(result, Err(Error::RecipientIDAlreadyUsed))); } @@ -2452,16 +2351,16 @@ fn ack() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet_1, rcv_online_1) = get_funded_wallet!(); - let (mut rcv_wallet_2, rcv_online_2) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party_1 = get_funded_party!(); + let mut rcv_party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send with donation set to false - let receive_data_1 = test_blind_receive(&mut rcv_wallet_1); - let receive_data_2 = test_blind_receive(&mut rcv_wallet_2); + let receive_data_1 = rcv_party_1.blind_receive(); + let receive_data_2 = rcv_party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -2479,54 +2378,38 @@ fn ack() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // all transfers are in WaitingCounterparty status - assert!(check_test_transfer_status_recipient( - &rcv_wallet_1, + assert!(rcv_party_1.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_2, + assert!(rcv_party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::WaitingCounterparty - )); + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::WaitingCounterparty)); // ack from recipient 1 > its transfer status changes to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet_1, rcv_online_1, None, None); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_1, + rcv_party_1.wait_for_refresh(None); + assert!(rcv_party_1.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::WaitingConfirmations )); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::WaitingCounterparty - )); + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::WaitingCounterparty)); // ack from recipient 2 > its transfer status changes to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet_2, rcv_online_2, None, None); - assert!(check_test_transfer_status_recipient( - &rcv_wallet_2, + rcv_party_2.wait_for_refresh(None); + assert!(rcv_party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingConfirmations )); // now sender can broadcast and move on to WaitingConfirmations - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::WaitingConfirmations - )); + party.wait_for_refresh(Some(&asset.asset_id)); + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::WaitingConfirmations)); } #[cfg(feature = "electrum")] @@ -2538,14 +2421,14 @@ fn nack() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send with donation set to false - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -2555,20 +2438,15 @@ fn nack() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // transfers are in WaitingCounterparty status - assert!(check_test_transfer_status_recipient( - &rcv_wallet, + assert!(rcv_party.check_test_transfer_status_recipient( &receive_data.recipient_id, TransferStatus::WaitingCounterparty )); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::WaitingCounterparty - )); + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::WaitingCounterparty)); // manually NACK the transfer (consignment is valid so refreshing receiver would yield an ACK) let proxy_client = get_proxy_client(None); @@ -2577,12 +2455,8 @@ fn nack() { .unwrap(); // refreshing sender transfer now has it fail - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - assert!(check_test_transfer_status_sender( - &wallet, - &txid, - TransferStatus::Failed - )); + party.wait_for_refresh(Some(&asset.asset_id)); + assert!(party.check_test_transfer_status_sender(&txid, TransferStatus::Failed)); } #[cfg(feature = "electrum")] @@ -2595,13 +2469,13 @@ fn no_change_on_pending_send() { let amount_2: u64 = 32; // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); - test_create_utxos(&mut wallet, online, true, Some(3), None, FEE_RATE, None); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); + party.create_utxos(true, Some(3), None, FEE_RATE, None); // issue 1 + get its UTXO - let asset_1 = test_issue_asset_nia(&mut wallet, online, None); - let unspents = test_list_unspents(&mut wallet, None, false); + let asset_1 = party.issue_asset_nia(None); + let unspents = party.list_unspents(false); let unspent_1 = unspents .iter() .find(|u| { @@ -2611,11 +2485,11 @@ fn no_change_on_pending_send() { }) .unwrap(); // issue 2 - let asset_2 = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT * 2])); + let asset_2 = party.issue_asset_nia(Some(&[AMOUNT * 2])); - show_unspent_colorings(&mut wallet, "before 1st send"); + party.show_unspent_colorings("before 1st send"); // send asset_1 - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -2625,12 +2499,12 @@ fn no_change_on_pending_send() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet, online, &recipient_map); + let txid_1 = party.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // send asset_2 (send_1 in WaitingCounterparty) - show_unspent_colorings(&mut wallet, "before 2nd send"); - let receive_data = test_blind_receive(&mut rcv_wallet); + party.show_unspent_colorings("before 2nd send"); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_2.asset_id.clone(), vec![Recipient { @@ -2640,22 +2514,22 @@ fn no_change_on_pending_send() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let send_result = test_send_result(&mut wallet, online, &recipient_map).unwrap(); + let send_result = party.send_result(&recipient_map).unwrap(); let txid_2 = send_result.txid; assert!(!txid_2.is_empty()); // check change was not allocated on issue 1 UTXO (pending Input coloring) assert!(!unspent_1.rgb_allocations.iter().any(|a| !a.settled)); // fail send asset_2 - test_fail_transfers_single(&mut wallet, online, send_result.batch_transfer_idx); + party.fail_transfers_single(send_result.batch_transfer_idx); // progress send_1 to WaitingConfirmations - show_unspent_colorings(&mut wallet, "before refresh"); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset_1.asset_id), None); + party.show_unspent_colorings("before refresh"); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset_1.asset_id)); // send asset_2 (send_1 in WaitingConfirmations) - show_unspent_colorings(&mut wallet, "before 3rd send"); - let receive_data = test_blind_receive(&mut rcv_wallet); + party.show_unspent_colorings("before 3rd send"); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_2.asset_id, vec![Recipient { @@ -2665,9 +2539,9 @@ fn no_change_on_pending_send() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_3 = test_send(&mut wallet, online, &recipient_map); + let txid_3 = party.send_retry(&recipient_map); assert!(!txid_3.is_empty()); - show_unspent_colorings(&mut wallet, "after 3rd send"); + party.show_unspent_colorings("after 3rd send"); // check change was not allocated on issue 1 UTXO (pending Input coloring) assert!(!unspent_1.rgb_allocations.iter().any(|a| !a.settled)); } @@ -2679,30 +2553,23 @@ fn fail() { initialize(); // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue asset - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // blind - let receive_data = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + 60) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data = + rcv_party.blind_receive_asset_expiry(None, Some((now().unix_timestamp() + 60) as u64)); // invalid recipient map: empty let recipient_map = HashMap::new(); - let result = test_send_begin_result(&mut wallet, online, &recipient_map).unwrap_err(); + let result = party.send_begin_result(&recipient_map).unwrap_err(); assert!(matches!(result, Error::InvalidRecipientMap)); // invalid recipient map: no recipients let recipient_map = HashMap::from([(asset.asset_id.clone(), vec![])]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map).unwrap_err(); + let result = party.send_begin_result(&recipient_map).unwrap_err(); assert!(matches!(result, Error::InvalidRecipientMap)); // invalid input (asset id) @@ -2715,7 +2582,7 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::AssetNotFound { asset_id: _ }))); // insufficient assets (amount too big) @@ -2728,7 +2595,7 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); let collection = AssignmentsCollection { fungible: AMOUNT, ..Default::default() @@ -2746,7 +2613,7 @@ fn fail() { transport_endpoints, }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); let msg = s!("must provide at least a transport endpoint"); assert!(matches!( result, @@ -2764,7 +2631,7 @@ fn fail() { transport_endpoints, }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!( result, Err(Error::InvalidTransportEndpoint { details: _ }) @@ -2781,7 +2648,7 @@ fn fail() { transport_endpoints, }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!( result, Err(Error::InvalidTransportEndpoint { details: _ }) @@ -2801,7 +2668,7 @@ fn fail() { transport_endpoints, }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); let msg = s!("no valid transport endpoints"); assert!(matches!( result, @@ -2824,7 +2691,7 @@ fn fail() { transport_endpoints, }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); let msg = s!("library supports at max 3 transport endpoints"); assert!(matches!( result, @@ -2841,8 +2708,8 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = wallet.send_begin( - online, + let result = party.wallet.send_begin( + party.online, recipient_map.clone(), false, 0, @@ -2853,8 +2720,8 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW)); // fee overflow - let result = wallet.send_begin( - online, + let result = party.wallet.send_begin( + party.online, recipient_map.clone(), false, u64::MAX, @@ -2882,7 +2749,7 @@ fn fail() { }, ], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::RecipientIDDuplicated))); // amount 0 @@ -2895,11 +2762,11 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::InvalidAmountZero))); // blinded with witness data - let receive_data_blinded = test_blind_receive(&mut rcv_wallet); + let receive_data_blinded = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -2912,12 +2779,12 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); let details = "cannot provide witness data for a blinded recipient"; assert!(matches!(result, Err(Error::InvalidRecipientData { details: m }) if m == details)); // witness with no witness data - let receive_data_witness = test_witness_receive(&mut rcv_wallet); + let receive_data_witness = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -2927,7 +2794,7 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); let details = "missing witness data for a witness recipient"; assert!(matches!(result, Err(Error::InvalidRecipientData { details: m }) if m == details)); @@ -2944,13 +2811,13 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::OutputBelowDustLimit))); // unsupported layer 1 println!("setting MOCK_CHAIN_NET"); MOCK_CHAIN_NET.replace(Some(ChainNet::LiquidTestnet)); - let receive_data_liquid = test_witness_receive(&mut rcv_wallet); + let receive_data_liquid = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -2963,20 +2830,12 @@ fn fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::InvalidRecipientNetwork))); // transport endpoints: no valid endpoints let transport_endpoints = vec![format!("rpc://{PROXY_HOST_MOD_API}")]; - let receive_data_te = rcv_wallet - .blind_receive( - None, - Assignment::Any, - None, - transport_endpoints.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data_te = rcv_party.blind_receive_with_endpoints(None, transport_endpoints.clone()); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -2986,7 +2845,7 @@ fn fail() { transport_endpoints, }], )]); - let result = test_send_result(&mut wallet, online, &recipient_map); + let result = party.send_result(&recipient_map); assert!(matches!(result, Err(Error::NoValidTransportEndpoint))); } @@ -3000,27 +2859,19 @@ fn pending_incoming_transfer_fail() { let amount_2: u64 = 33; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_noutxo_wallet!(); - test_create_utxos( - &mut rcv_wallet, - rcv_online, - false, - Some(1), - None, - FEE_RATE, - None, - ); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_noutxo_party!(); + rcv_party.create_utxos(false, Some(1), None, FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // // 1st transfer // // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3030,29 +2881,29 @@ fn pending_incoming_transfer_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet, online, &recipient_map); + let txid_1 = party.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - show_unspent_colorings(&mut wallet, "sender after 1st send, settled"); - show_unspent_colorings(&mut rcv_wallet, "receiver after 1st send, settled"); + party.show_unspent_colorings("sender after 1st send, settled"); + rcv_party.show_unspent_colorings("receiver after 1st send, settled"); // // 2nd transfer // // add a blind to the same UTXO - let _receive_data_2 = test_blind_receive(&mut rcv_wallet); - show_unspent_colorings(&mut rcv_wallet, "receiver after 2nd blind"); + let _receive_data_2 = rcv_party.blind_receive(); + rcv_party.show_unspent_colorings("receiver after 2nd blind"); // send from receiving wallet, 1st receive Settled, 2nd one still pending - let receive_data = test_blind_receive(&mut wallet); + let receive_data = party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3062,20 +2913,17 @@ fn pending_incoming_transfer_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - show_unspent_colorings(&mut wallet, "sender after 2nd send, WaitingCounterparty"); - show_unspent_colorings( - &mut rcv_wallet, - "receiver after 2nd send, WaitingCounterparty", - ); // check input allocation is blocked by pending receive - let result = test_send_result(&mut rcv_wallet, rcv_online, &recipient_map); + party.show_unspent_colorings("sender after 2nd send, WaitingCounterparty"); + rcv_party.show_unspent_colorings("receiver after 2nd send, WaitingCounterparty"); + let result = rcv_party.send_result(&recipient_map); assert_matches!(result, Err(Error::InsufficientAssignments { asset_id: t, available: a }) if t == asset.asset_id && a == AssignmentsCollection::default()); // refresh on both wallets (no transfer status changes) - assert!(!test_refresh_all(&mut rcv_wallet, rcv_online)); - assert!(!test_refresh_asset(&mut wallet, online, &asset.asset_id)); // check input allocation is still blocked by pending receive - let result = test_send_result(&mut rcv_wallet, rcv_online, &recipient_map); + assert!(!rcv_party.refresh_all()); + assert!(!party.refresh_asset(&asset.asset_id)); + let result = rcv_party.send_result(&recipient_map); assert_matches!(result, Err(Error::InsufficientAssignments { asset_id: t, available: a }) if t == asset.asset_id && a == AssignmentsCollection::default()); } @@ -3088,14 +2936,14 @@ fn pending_outgoing_transfer_fail() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // issue asset - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // 1st send - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3108,15 +2956,15 @@ fn pending_outgoing_transfer_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "sender after 1st send"); + party.show_unspent_colorings("sender after 1st send"); // check change UTXO has exists = false and unspents list it - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); - let unspents = test_list_unspents(&mut wallet, Some(online), false); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); + let unspents = party.list_unspents_with_sync(false); let change_unspent = unspents .iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo) @@ -3140,7 +2988,7 @@ fn pending_outgoing_transfer_fail() { assert_eq!(unspents.iter().filter(|u| !u.utxo.colorable).count(), 1); // 2nd send (1st still pending) - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3154,14 +3002,14 @@ fn pending_outgoing_transfer_fail() { }], )]); // check input allocation is blocked by pending send - let result = test_send_result(&mut wallet, online, &recipient_map); + let result = party.send_result(&recipient_map); assert_matches!(result, Err(Error::InsufficientAssignments { asset_id: t, available: a }) if t == asset.asset_id && a == AssignmentsCollection::default()); // take transfer from WaitingCounterparty to WaitingConfirmations - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); // check input allocation is still blocked by pending send - let result = test_send_result(&mut wallet, online, &recipient_map); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); + let result = party.send_result(&recipient_map); assert_matches!(result, Err(Error::InsufficientAssignments { asset_id: t, available: a }) if t == asset.asset_id && a == AssignmentsCollection::default()); } @@ -3174,19 +3022,19 @@ fn pending_transfer_input_fail() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); + party.create_utxos(false, Some(1), None, FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // blind with sender wallet to create a pending transfer - let _receive_data = test_blind_receive(&mut wallet); - show_unspent_colorings(&mut wallet, "sender after blind"); + let _receive_data = party.blind_receive(); + party.show_unspent_colorings("sender after blind"); // send and check it fails as the issuance UTXO is "blocked" by the pending receive operation - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3196,7 +3044,7 @@ fn pending_transfer_input_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_result(&mut wallet, online, &recipient_map); + let result = party.send_result(&recipient_map); assert_matches!(result, Err(Error::InsufficientAssignments { asset_id: t, available: a }) if t == asset.asset_id && a == AssignmentsCollection::default()); } @@ -3209,22 +3057,15 @@ fn already_used_fail() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue asset to 3 UTXOs - let asset = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT, AMOUNT * 2, AMOUNT * 3])); + let asset = party.issue_asset_nia(Some(&[AMOUNT, AMOUNT * 2, AMOUNT * 3])); // 1st transfer - let receive_data = rcv_wallet - .blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + 60) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap(); + let receive_data = + rcv_party.blind_receive_asset_expiry(None, Some((now().unix_timestamp() + 60) as u64)); let recipient_map = HashMap::from([( asset.asset_id, vec![Recipient { @@ -3234,11 +3075,11 @@ fn already_used_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // 2nd transfer using the same blinded UTXO - let result = test_send_result(&mut wallet, online, &recipient_map); + let result = party.send_result(&recipient_map); assert!(matches!(result, Err(Error::RecipientIDAlreadyUsed))); } @@ -3249,20 +3090,20 @@ fn cfa_extra_success() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // create a single UTXO to issue assets on the same UTXO - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); + party.create_utxos(true, Some(1), None, FEE_RATE, None); // issue NIA - let asset_nia = test_issue_asset_nia(&mut wallet, online, None); + let asset_nia = party.issue_asset_nia(None); // issue CFA let amount = 42; - let _asset_cfa = test_issue_asset_cfa(&mut wallet, online, Some(&[amount]), None); + let _asset_cfa = party.issue_asset_cfa(Some(&[amount]), None); - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); // send NIA let recipient_map = HashMap::from([( @@ -3274,17 +3115,17 @@ fn cfa_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid); + let (transfers, asset_transfers, _) = party.get_test_transfers_sender(&txid); assert_eq!(asset_transfers.len(), 2); assert_eq!(transfers.len(), 2); let asset_transfer_1 = &asset_transfers[0]; assert!(asset_transfer_1.user_driven); let asset_transfer_2 = &asset_transfers[1]; assert!(!asset_transfer_2.user_driven); - let extra_colorings = get_test_colorings(&wallet, asset_transfer_2.idx); + let extra_colorings = party.db_colorings_filtered(asset_transfer_2.idx); let extra_coloring_input = &extra_colorings[0]; let extra_coloring_change = &extra_colorings[1]; assert_eq!(extra_coloring_input.r#type, ColoringType::Input); @@ -3306,19 +3147,19 @@ fn uda_extra_success() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // create a single UTXO to issue assets on the same UTXO - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); + party.create_utxos(true, Some(1), None, FEE_RATE, None); // issue NIA - let asset_nia = test_issue_asset_nia(&mut wallet, online, None); + let asset_nia = party.issue_asset_nia(None); // issue UDA - let _asset_uda = test_issue_asset_uda(&mut wallet, online, None, None, vec![]); + let _asset_uda = party.issue_asset_uda(None, None, vec![]); - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); // send NIA let recipient_map = HashMap::from([( @@ -3330,17 +3171,17 @@ fn uda_extra_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let (transfers, asset_transfers, _) = get_test_transfers_sender(&wallet, &txid); + let (transfers, asset_transfers, _) = party.get_test_transfers_sender(&txid); assert_eq!(asset_transfers.len(), 2); assert_eq!(transfers.len(), 2); let asset_transfer_1 = &asset_transfers[0]; assert!(asset_transfer_1.user_driven); let asset_transfer_2 = &asset_transfers[1]; assert!(!asset_transfer_2.user_driven); - let extra_colorings = get_test_colorings(&wallet, asset_transfer_2.idx); + let extra_colorings = party.db_colorings_filtered(asset_transfer_2.idx); let extra_coloring_input = &extra_colorings[0]; let extra_coloring_change = &extra_colorings[1]; assert_eq!(extra_coloring_input.r#type, ColoringType::Input); @@ -3356,31 +3197,31 @@ fn psbt_rgb_consumer_success() { initialize(); // create wallet with funds and no UTXOs - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // create 1 UTXO println!("utxo 1"); - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); - show_unspent_colorings(&mut wallet, "after create utxos 1"); + party.create_utxos(true, Some(1), None, FEE_RATE, None); + party.show_unspent_colorings("after create utxos 1"); // issue a NIA asset println!("issue 1"); - let asset_nia_a = test_issue_asset_nia(&mut wallet, online, None); - show_unspent_colorings(&mut wallet, "after issue 1"); + let asset_nia_a = party.issue_asset_nia(None); + party.show_unspent_colorings("after issue 1"); // issue a 2nd NIA asset on the same UTXO println!("issue 2"); - let asset_nia_b = test_issue_asset_nia(&mut wallet, online, None); - show_unspent_colorings(&mut wallet, "after issue 2"); + let asset_nia_b = party.issue_asset_nia(None); + party.show_unspent_colorings("after issue 2"); // create 1 more UTXO for change, up_to false or AllocationsAlreadyAvailable is returned println!("utxo 2"); - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); + party.create_utxos(false, Some(1), None, FEE_RATE, None); // try to send the 1st asset println!("send_begin 1"); - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_nia_a.asset_id.clone(), vec![Recipient { @@ -3390,14 +3231,14 @@ fn psbt_rgb_consumer_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map).unwrap(); + let result = party.send_begin_result(&recipient_map).unwrap(); assert!(!result.psbt.is_empty()); - show_unspent_colorings(&mut wallet, "after send 1"); - test_fail_transfers_single(&mut wallet, online, result.batch_transfer_idx.unwrap()); + party.show_unspent_colorings("after send 1"); + party.fail_transfers_single(result.batch_transfer_idx.unwrap()); // try to send the 2nd asset println!("send_begin 2"); - let receive_data_2 = test_blind_receive(&mut rcv_wallet); + let receive_data_2 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_nia_b.asset_id.clone(), vec![Recipient { @@ -3407,15 +3248,15 @@ fn psbt_rgb_consumer_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map).unwrap(); + let result = party.send_begin_result(&recipient_map).unwrap(); assert!(!result.psbt.is_empty()); - show_unspent_colorings(&mut wallet, "after send 2"); - test_fail_transfers_single(&mut wallet, online, result.batch_transfer_idx.unwrap()); + party.show_unspent_colorings("after send 2"); + party.fail_transfers_single(result.batch_transfer_idx.unwrap()); // try to send the 1st asset to a recipient and the 2nd to different one println!("send_begin 3"); - let receive_data_3a = test_blind_receive(&mut rcv_wallet); - let receive_data_3b = test_blind_receive(&mut rcv_wallet); + let receive_data_3a = rcv_party.blind_receive(); + let receive_data_3b = rcv_party.blind_receive(); let recipient_map = HashMap::from([ ( asset_nia_a.asset_id, @@ -3436,9 +3277,9 @@ fn psbt_rgb_consumer_success() { }], ), ]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map).unwrap(); + let result = party.send_begin_result(&recipient_map).unwrap(); assert!(!result.psbt.is_empty()); - show_unspent_colorings(&mut wallet, "after send 3"); + party.show_unspent_colorings("after send 3"); } #[cfg(feature = "electrum")] @@ -3448,33 +3289,20 @@ fn insufficient_bitcoins() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // create 1 UTXO with not enough bitcoins for a send and send the rest - test_create_utxos( - &mut wallet, - online, - false, - Some(1), - Some(TINY_BTC_AMOUNT), - FEE_RATE, - None, - ); - test_send_btc( - &mut wallet, - online, - &test_get_address(&mut rcv_wallet), - 99_999_000, - ); + party.create_utxos(false, Some(1), Some(TINY_BTC_AMOUNT), FEE_RATE, None); + party.send_btc(&rcv_party.get_address(), 99_999_000); // issue an NIA asset - let asset_nia_a = test_issue_asset_nia(&mut wallet, online, None); + let asset_nia_a = party.issue_asset_nia(None); // send with no colorable UTXOs available as additional bitcoin inputs and no other funds - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 1); - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_nia_a.asset_id, vec![Recipient { @@ -3484,30 +3312,17 @@ fn insufficient_bitcoins() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // create 1 UTXO for change (add funds, create UTXO, send the rest) - fund_wallet(test_get_address(&mut wallet)); - test_create_utxos( - &mut wallet, - online, - false, - Some(1), - Some(TINY_BTC_AMOUNT), - FEE_RATE, - None, - ); - test_send_btc( - &mut wallet, - online, - &test_get_address(&mut rcv_wallet), - 99_999_000, - ); + fund_wallet(party.get_address()); + party.create_utxos(false, Some(1), Some(TINY_BTC_AMOUNT), FEE_RATE, None); + party.send_btc(&rcv_party.get_address(), 99_999_000); // send works with no colorable UTXOs available as additional bitcoin inputs - wait_for_unspents(&mut wallet, None, false, 2); - let txid = test_send(&mut wallet, online, &recipient_map); + party.wait_for_unspents(false, 2); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); } @@ -3518,27 +3333,19 @@ fn insufficient_allocations_fail() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // create 1 UTXO with not enough bitcoins for a send - test_create_utxos( - &mut wallet, - online, - false, - Some(1), - Some(TINY_BTC_AMOUNT), - FEE_RATE, - None, - ); + party.create_utxos(false, Some(1), Some(TINY_BTC_AMOUNT), FEE_RATE, None); // issue an NIA asset - let asset_nia_a = test_issue_asset_nia(&mut wallet, online, None); + let asset_nia_a = party.issue_asset_nia(None); // send with no colorable UTXOs available as change - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 2); - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_nia_a.asset_id, vec![Recipient { @@ -3548,17 +3355,17 @@ fn insufficient_allocations_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // create 1 more UTXO for change, up_to false or AllocationsAlreadyAvailable is returned println!("utxo 2"); - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); + party.create_utxos(false, Some(1), None, FEE_RATE, None); // send works with no colorable UTXOs available as additional bitcoin inputs - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); assert_eq!(unspents.len(), 3); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); } @@ -3569,28 +3376,20 @@ fn insufficient_allocations_success() { initialize(); // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // create 1 UTXO with not enough bitcoins for a send - test_create_utxos( - &mut wallet, - online, - false, - Some(1), - Some(TINY_BTC_AMOUNT), - FEE_RATE, - None, - ); + party.create_utxos(false, Some(1), Some(TINY_BTC_AMOUNT), FEE_RATE, None); // issue an NIA asset on the unspendable UTXO - let asset_nia_a = test_issue_asset_nia(&mut wallet, online, None); + let asset_nia_a = party.issue_asset_nia(None); // create 2 more UTXOs, 1 for change + 1 as additional bitcoin input - test_create_utxos(&mut wallet, online, false, Some(2), None, FEE_RATE, None); + party.create_utxos(false, Some(2), None, FEE_RATE, None); // send with 1 colorable UTXOs available as additional bitcoin input - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset_nia_a.asset_id, vec![Recipient { @@ -3600,7 +3399,7 @@ fn insufficient_allocations_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map).unwrap(); + let result = party.send_begin_result(&recipient_map).unwrap(); assert!(!result.psbt.is_empty()); } @@ -3614,14 +3413,14 @@ fn send_to_oneself() { let amount_2: u64 = 33; // wallets - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data_1 = test_blind_receive(&mut wallet); - let receive_data_2 = test_witness_receive(&mut wallet); + let receive_data_1 = party.blind_receive(); + let receive_data_2 = party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id, vec![ @@ -3642,15 +3441,15 @@ fn send_to_oneself() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // transfers progress to status Settled after refreshes - wait_for_refresh(&mut wallet, online, None, Some(&[2, 3])); + party.wait_for_refresh_raw(None, Some(&[2, 3])); mine(false); - wait_for_refresh(&mut wallet, online, None, None); + party.wait_for_refresh(None); - let batch_transfers = get_test_batch_transfers(&wallet, &txid); + let batch_transfers = party.db_batch_transfers_filtered(&txid); assert_eq!(batch_transfers.len(), 3); assert!( batch_transfers @@ -3659,7 +3458,7 @@ fn send_to_oneself() { ); // check balance is unchanged - let nia_assets = test_list_assets(&wallet, &[AssetSchema::Nia]).nia.unwrap(); + let nia_assets = party.list_assets(&[AssetSchema::Nia]).nia.unwrap(); let asset = nia_assets.first().unwrap(); assert_eq!( asset.balance, @@ -3670,7 +3469,7 @@ fn send_to_oneself() { } ); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 5); assert_eq!( transfers @@ -3712,18 +3511,18 @@ fn send_received_back_success() { let amount_2: u64 = 33; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // // 1st transfer: from issuer to recipient // // send - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3733,21 +3532,21 @@ fn send_received_back_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet, online, &recipient_map); + let txid_1 = party.send_retry(&recipient_map); assert!(!txid_1.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // transfer 1 checks - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_1); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_1); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); assert_eq!( @@ -3759,7 +3558,7 @@ fn send_received_back_success() { vec![Assignment::Fungible(AMOUNT - amount_1)] ); - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo) @@ -3776,7 +3575,7 @@ fn send_received_back_success() { // // send - let receive_data_2 = test_blind_receive(&mut wallet); + let receive_data_2 = party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -3786,21 +3585,21 @@ fn send_received_back_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut rcv_wallet, rcv_online, &recipient_map); + let txid_2 = rcv_party.send_retry(&recipient_map); assert!(!txid_2.is_empty()); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut wallet, online, None, None); - wait_for_refresh(&mut rcv_wallet, rcv_online, Some(&asset.asset_id), None); + party.wait_for_refresh(None); + rcv_party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut wallet, online, None, None); - wait_for_refresh(&mut rcv_wallet, rcv_online, Some(&asset.asset_id), None); + party.wait_for_refresh(None); + rcv_party.wait_for_refresh(Some(&asset.asset_id)); // transfer 2 checks - let rcv_transfer = get_test_transfer_recipient(&wallet, &receive_data_2.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&rcv_wallet, &txid_2); - let (transfer_data, _) = get_test_transfer_data(&rcv_wallet, &transfer); + let rcv_transfer = party.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (rcv_transfer_data, _) = party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = rcv_party.get_test_transfer_sender(&txid_2); + let (transfer_data, _) = rcv_party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); assert_eq!( @@ -3812,7 +3611,7 @@ fn send_received_back_success() { vec![Assignment::Fungible(amount_2)] ); - let unspents = test_list_unspents(&mut rcv_wallet, None, true); + let unspents = rcv_party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo) @@ -3828,38 +3627,38 @@ fn send_received_back_success() { // 3rd transfer: from issuer to recipient once again (spend what was received back) // - show_unspent_colorings(&mut wallet, "wallet before 3rd transfer"); - show_unspent_colorings(&mut rcv_wallet, "rcv_wallet before 3rd transfer"); // send - let receive_data_3 = test_blind_receive(&mut rcv_wallet); + party.show_unspent_colorings("wallet before 3rd transfer"); + rcv_party.show_unspent_colorings("rcv_wallet before 3rd transfer"); + let receive_data_3 = rcv_party.blind_receive(); let change_3 = 5; - let amount_3 = test_get_asset_balance(&wallet, &asset.asset_id).spendable - change_3; + let amount_3 = party.get_asset_balance(&asset.asset_id).spendable - change_3; let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { - assignment: Assignment::Fungible(amount_3), // make sure to spend received transfer allocation + assignment: Assignment::Fungible(amount_3), recipient_id: receive_data_3.recipient_id.clone(), witness_data: None, transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_3 = test_send(&mut wallet, online, &recipient_map); + let txid_3 = party.send_retry(&recipient_map); assert!(!txid_3.is_empty()); - show_unspent_colorings(&mut wallet, "wallet after 3rd transfer"); - show_unspent_colorings(&mut rcv_wallet, "rcv_wallet after 3rd transfer"); + party.show_unspent_colorings("wallet after 3rd transfer"); + rcv_party.show_unspent_colorings("rcv_wallet after 3rd transfer"); // take transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // transfer 3 checks - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_3.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_3); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_3.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_3); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); assert_eq!( @@ -3871,7 +3670,7 @@ fn send_received_back_success() { vec![Assignment::Fungible(change_3)] ); - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo) @@ -3893,16 +3692,16 @@ fn witness_success() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data = test_witness_receive(&mut rcv_wallet); - let receive_data_2 = test_witness_receive(&mut rcv_wallet); - let receive_data_3 = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); + let receive_data_2 = rcv_party.witness_receive(); + let receive_data_3 = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -3935,22 +3734,21 @@ fn witness_success() { }, ], )]); - test_create_utxos(&mut wallet, online, false, None, None, FEE_RATE, None); - let txid = test_send(&mut wallet, online, &recipient_map); + party.create_utxos(false, None, None, FEE_RATE, None); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet, &rcv_transfer); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let batch_transfers = get_test_batch_transfers(&wallet, &txid); + rcv_party.wait_for_refresh(None); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, rcv_asset_transfer) = rcv_party.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(Some(&asset.asset_id)); + let batch_transfers = party.db_batch_transfers_filtered(&txid); let batch_transfer = batch_transfers.first().unwrap(); - let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx); - let transfers = get_test_transfers(&wallet, asset_transfer.idx); + let asset_transfer = party.get_test_asset_transfer(batch_transfer.idx); + let transfers = party.db_transfers_filtered(asset_transfer.idx); for transfer in transfers { - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations); // ack is now true on the sender side assert_eq!(transfer.ack, Some(true)); @@ -3969,7 +3767,7 @@ fn witness_success() { assert_eq!(rcv_asset_transfer.asset_id, Some(asset.asset_id.clone())); // asset has been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let nia_assets = rcv_assets.nia.unwrap(); let cfa_assets = rcv_assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 1); @@ -3990,20 +3788,20 @@ fn witness_success() { // transfers progress to status Settled after tx mining + refresh mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let batch_transfers = get_test_batch_transfers(&wallet, &txid); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let batch_transfers = party.db_batch_transfers_filtered(&txid); let batch_transfer = batch_transfers.first().unwrap(); - let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx); - let transfers: Vec = get_test_transfers(&wallet, asset_transfer.idx).collect(); + let asset_transfer = party.get_test_asset_transfer(batch_transfer.idx); + let transfers: Vec = party.db_transfers_filtered(asset_transfer.idx); for transfer in transfers { - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(transfer_data.status, TransferStatus::Settled); // change is unspent once transfer is Settled - let unspents = test_list_unspents(&mut wallet, None, true); + let unspents = party.list_unspents(true); let change_unspent = unspents .into_iter() .find(|u| Some(u.utxo.outpoint.clone()) == transfer_data.change_utxo); @@ -4011,7 +3809,7 @@ fn witness_success() { } assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); - let balances = test_get_btc_balance(&mut rcv_wallet, rcv_online); + let balances = rcv_party.get_btc_balance_with_sync(); assert!(matches!( balances.colored, Balance { @@ -4035,19 +3833,19 @@ fn witness_multiple_assets_success() { let btc_amount_2b = 1400; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset_1 = test_issue_asset_nia(&mut wallet, online, None); - let asset_2 = test_issue_asset_nia(&mut wallet, online, None); + let asset_1 = party.issue_asset_nia(None); + let asset_2 = party.issue_asset_nia(None); // send 1: check a transfer of multiple assets with multiple recepients works as expected println!("\nsend 1"); - let receive_data_1a = test_witness_receive(&mut rcv_wallet); - let receive_data_1b = test_witness_receive(&mut rcv_wallet); - let receive_data_2a = test_witness_receive(&mut rcv_wallet); - let receive_data_2b = test_witness_receive(&mut rcv_wallet); + let receive_data_1a = rcv_party.witness_receive(); + let receive_data_1b = rcv_party.witness_receive(); + let receive_data_2a = rcv_party.witness_receive(); + let receive_data_2b = rcv_party.witness_receive(); let recipient_map = HashMap::from([ ( asset_1.asset_id.clone(), @@ -4096,23 +3894,23 @@ fn witness_multiple_assets_success() { ], ), ]); - test_create_utxos(&mut wallet, online, false, None, None, FEE_RATE, None); - let txid = test_send(&mut wallet, online, &recipient_map); + party.create_utxos(false, None, None, FEE_RATE, None); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); - // check receiver transfers - let rcv_xfer_1a = get_test_transfer_recipient(&rcv_wallet, &receive_data_1a.recipient_id); - let rcv_xfer_1b = get_test_transfer_recipient(&rcv_wallet, &receive_data_1b.recipient_id); - let rcv_xfer_2a = get_test_transfer_recipient(&rcv_wallet, &receive_data_2a.recipient_id); - let rcv_xfer_2b = get_test_transfer_recipient(&rcv_wallet, &receive_data_2b.recipient_id); - let (rcv_xfer_data_1a, rcv_asset_xfer_1a) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_1a); - let (rcv_xfer_data_1b, rcv_asset_xfer_1b) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_1b); - let (rcv_xfer_data_2a, rcv_asset_xfer_2a) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_2a); - let (rcv_xfer_data_2b, rcv_asset_xfer_2b) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_2b); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); + + let rcv_xfer_1a = rcv_party.get_test_transfer_recipient(&receive_data_1a.recipient_id); + let rcv_xfer_1b = rcv_party.get_test_transfer_recipient(&receive_data_1b.recipient_id); + let rcv_xfer_2a = rcv_party.get_test_transfer_recipient(&receive_data_2a.recipient_id); + let rcv_xfer_2b = rcv_party.get_test_transfer_recipient(&receive_data_2b.recipient_id); + let (rcv_xfer_data_1a, rcv_asset_xfer_1a) = rcv_party.get_test_transfer_data(&rcv_xfer_1a); + let (rcv_xfer_data_1b, rcv_asset_xfer_1b) = rcv_party.get_test_transfer_data(&rcv_xfer_1b); + let (rcv_xfer_data_2a, rcv_asset_xfer_2a) = rcv_party.get_test_transfer_data(&rcv_xfer_2a); + let (rcv_xfer_data_2b, rcv_asset_xfer_2b) = rcv_party.get_test_transfer_data(&rcv_xfer_2b); assert_eq!(rcv_xfer_data_1a.kind, TransferKind::ReceiveWitness); assert_eq!(rcv_xfer_data_1b.kind, TransferKind::ReceiveWitness); assert_eq!(rcv_xfer_data_2a.kind, TransferKind::ReceiveWitness); @@ -4154,7 +3952,7 @@ fn witness_multiple_assets_success() { assert_eq!(rcv_asset_xfer_2a.asset_id, Some(asset_2.asset_id.clone())); assert_eq!(rcv_asset_xfer_2b.asset_id, Some(asset_2.asset_id.clone())); // asset has been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let nia_assets = rcv_assets.nia.unwrap(); let cfa_assets = rcv_assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 2); @@ -4181,7 +3979,7 @@ fn witness_multiple_assets_success() { ); // transfer vout + BTC amount match tx outputs #[allow(unreachable_patterns)] - let tx_details = match rcv_wallet.indexer() { + let tx_details = match rcv_party.wallet.indexer() { Indexer::Electrum(client) => client .inner .raw_call( @@ -4218,37 +4016,37 @@ fn witness_multiple_assets_success() { } // check sender transfers - let batch_transfers = get_test_batch_transfers(&wallet, &txid); + let batch_transfers = party.db_batch_transfers_filtered(&txid); assert_eq!(batch_transfers.len(), 1); let batch_transfer = batch_transfers.first().unwrap(); - let asset_transfers = get_test_asset_transfers(&wallet, batch_transfer.idx); + let asset_transfers = party.db_asset_transfers_filtered(batch_transfer.idx); assert_eq!(asset_transfers.len(), 2); - let transfers_1 = get_test_transfers(&wallet, asset_transfers.first().unwrap().idx); - let transfers_2 = get_test_transfers(&wallet, asset_transfers.last().unwrap().idx); - transfers_1.chain(transfers_2).for_each(|t| { - let (transfer_data, _) = get_test_transfer_data(&wallet, &t); + let transfers_1 = party.db_transfers_filtered(asset_transfers.first().unwrap().idx); + let transfers_2 = party.db_transfers_filtered(asset_transfers.last().unwrap().idx); + transfers_1.into_iter().chain(transfers_2).for_each(|t| { + let (transfer_data, _) = party.get_test_transfer_data(&t); assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations); }); // transfers progress to status Settled after tx mining + refresh mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); - // check receiver transfers - let rcv_xfer_1a = get_test_transfer_recipient(&rcv_wallet, &receive_data_1a.recipient_id); - let rcv_xfer_1b = get_test_transfer_recipient(&rcv_wallet, &receive_data_1b.recipient_id); - let rcv_xfer_2a = get_test_transfer_recipient(&rcv_wallet, &receive_data_2a.recipient_id); - let rcv_xfer_2b = get_test_transfer_recipient(&rcv_wallet, &receive_data_2b.recipient_id); - let (rcv_xfer_data_1a, _) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_1a); - let (rcv_xfer_data_1b, _) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_1b); - let (rcv_xfer_data_2a, _) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_2a); - let (rcv_xfer_data_2b, _) = get_test_transfer_data(&rcv_wallet, &rcv_xfer_2b); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); + + let rcv_xfer_1a = rcv_party.get_test_transfer_recipient(&receive_data_1a.recipient_id); + let rcv_xfer_1b = rcv_party.get_test_transfer_recipient(&receive_data_1b.recipient_id); + let rcv_xfer_2a = rcv_party.get_test_transfer_recipient(&receive_data_2a.recipient_id); + let rcv_xfer_2b = rcv_party.get_test_transfer_recipient(&receive_data_2b.recipient_id); + let (rcv_xfer_data_1a, _) = rcv_party.get_test_transfer_data(&rcv_xfer_1a); + let (rcv_xfer_data_1b, _) = rcv_party.get_test_transfer_data(&rcv_xfer_1b); + let (rcv_xfer_data_2a, _) = rcv_party.get_test_transfer_data(&rcv_xfer_2a); + let (rcv_xfer_data_2b, _) = rcv_party.get_test_transfer_data(&rcv_xfer_2b); assert_eq!(rcv_xfer_data_1a.status, TransferStatus::Settled); assert_eq!(rcv_xfer_data_1b.status, TransferStatus::Settled); assert_eq!(rcv_xfer_data_2a.status, TransferStatus::Settled); assert_eq!(rcv_xfer_data_2b.status, TransferStatus::Settled); - let rcv_balances = test_get_btc_balance(&mut rcv_wallet, rcv_online); + let rcv_balances = rcv_party.get_btc_balance_with_sync(); assert!(matches!( rcv_balances.colored, Balance { @@ -4259,19 +4057,19 @@ fn witness_multiple_assets_success() { )); // check sender transfers - let batch_transfers = get_test_batch_transfers(&wallet, &txid); + let batch_transfers = party.db_batch_transfers_filtered(&txid); assert_eq!(batch_transfers.len(), 1); let batch_transfer = batch_transfers.first().unwrap(); - let asset_transfers = get_test_asset_transfers(&wallet, batch_transfer.idx); + let asset_transfers = party.db_asset_transfers_filtered(batch_transfer.idx); assert_eq!(asset_transfers.len(), 2); - let transfers_1 = get_test_transfers(&wallet, asset_transfers.first().unwrap().idx); - let transfers_2 = get_test_transfers(&wallet, asset_transfers.last().unwrap().idx); - transfers_1.chain(transfers_2).for_each(|t| { - let (transfer_data, _) = get_test_transfer_data(&wallet, &t); + let transfers_1 = party.db_transfers_filtered(asset_transfers.first().unwrap().idx); + let transfers_2 = party.db_transfers_filtered(asset_transfers.last().unwrap().idx); + transfers_1.into_iter().chain(transfers_2).for_each(|t| { + let (transfer_data, _) = party.get_test_transfer_data(&t); assert_eq!(transfer_data.status, TransferStatus::Settled); }); // asset has been received correctly - let rcv_assets = test_list_assets(&rcv_wallet, &[]); + let rcv_assets = rcv_party.list_assets(&[]); let nia_assets = rcv_assets.nia.unwrap(); let cfa_assets = rcv_assets.cfa.unwrap(); assert_eq!(nia_assets.len(), 2); @@ -4299,7 +4097,7 @@ fn witness_multiple_assets_success() { // send 2: check get_asset_balance works with a pending witness receive with no asset ID println!("\nsend 2"); - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -4312,17 +4110,17 @@ fn witness_multiple_assets_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // check receiver transfer - let rcv_xfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_xfer_data, rcv_asset_xfer) = get_test_transfer_data(&rcv_wallet, &rcv_xfer); + let rcv_xfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_xfer_data, rcv_asset_xfer) = rcv_party.get_test_transfer_data(&rcv_xfer); assert_eq!(rcv_xfer_data.status, TransferStatus::WaitingCounterparty); assert_eq!(rcv_xfer.requested_assignment, Some(Assignment::Any)); assert_eq!(rcv_asset_xfer.asset_id, None); // check asset balance: pending witness transfer not counted (no asset ID) - let asset_1_balance = test_get_asset_balance(&rcv_wallet, &asset_1.asset_id); + let asset_1_balance = rcv_party.get_asset_balance(&asset_1.asset_id); assert_eq!( asset_1_balance, Balance { @@ -4333,12 +4131,12 @@ fn witness_multiple_assets_success() { ); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // check receiver transfer - let rcv_xfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_xfer_data, rcv_asset_xfer) = get_test_transfer_data(&rcv_wallet, &rcv_xfer); + let rcv_xfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_xfer_data, rcv_asset_xfer) = rcv_party.get_test_transfer_data(&rcv_xfer); assert_eq!(rcv_xfer_data.status, TransferStatus::WaitingConfirmations); assert_eq!( rcv_xfer_data.assignments, @@ -4346,7 +4144,7 @@ fn witness_multiple_assets_success() { ); assert_eq!(rcv_asset_xfer.asset_id, Some(asset_1.asset_id.clone())); // check asset balance: pending witness transfer counted (future) - let asset_1_balance = test_get_asset_balance(&rcv_wallet, &asset_1.asset_id); + let asset_1_balance = rcv_party.get_asset_balance(&asset_1.asset_id); assert_eq!( asset_1_balance, Balance { @@ -4358,15 +4156,15 @@ fn witness_multiple_assets_success() { // transfers progress to status Settled after tx mining + refresh mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // check receiver transfer - let rcv_xfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_xfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_xfer); + let rcv_xfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_xfer_data, _) = rcv_party.get_test_transfer_data(&rcv_xfer); assert_eq!(rcv_xfer_data.status, TransferStatus::Settled); // check asset balance: pending witness transfer counted (settled + spendable as well) - let asset_1_balance = test_get_asset_balance(&rcv_wallet, &asset_1.asset_id); + let asset_1_balance = rcv_party.get_asset_balance(&asset_1.asset_id); assert_eq!( asset_1_balance, Balance { @@ -4386,16 +4184,16 @@ fn witness_multiple_inputs_success() { let amount: u64 = 66; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // send println!("send 1"); - let receive_data_1a = test_witness_receive(&mut wallet_2); - let receive_data_1b = test_witness_receive(&mut wallet_2); + let receive_data_1a = party_2.witness_receive(); + let receive_data_1b = party_2.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -4419,18 +4217,18 @@ fn witness_multiple_inputs_success() { }, ], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfers - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); println!("send 2"); - let receive_data_2 = test_witness_receive(&mut wallet_1); + let receive_data_2 = party_1.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -4443,18 +4241,18 @@ fn witness_multiple_inputs_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfers - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(Some(&asset.asset_id)); println!("send 3"); - let receive_data_3 = test_witness_receive(&mut wallet_2); + let receive_data_3 = party_2.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -4467,21 +4265,21 @@ fn witness_multiple_inputs_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfers - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); - // check transfers have settled - let rcv_transfer = get_test_transfer_recipient(&wallet_2, &receive_data_3.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_2, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_1, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet_1, &transfer); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); + + let rcv_transfer = party_2.get_test_transfer_recipient(&receive_data_3.recipient_id); + let (rcv_transfer_data, _) = party_2.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_1.get_test_transfer_sender(&txid); + let (transfer_data, _) = party_1.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); } @@ -4495,16 +4293,16 @@ fn witness_fail_wrong_vout() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet_1, rcv_online_1) = get_funded_wallet!(); - let (mut rcv_wallet_2, rcv_online_2) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party_1 = get_funded_party!(); + let mut rcv_party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data_1 = test_witness_receive(&mut rcv_wallet_1); - let receive_data_2 = test_witness_receive(&mut rcv_wallet_2); + let receive_data_1 = rcv_party_1.witness_receive(); + let receive_data_2 = rcv_party_2.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -4530,22 +4328,22 @@ fn witness_fail_wrong_vout() { )]); println!("setting MOCK_VOUT"); MOCK_VOUT.replace(Some(2)); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // transfers progress to status Failed after a refresh - wait_for_refresh(&mut rcv_wallet_2, rcv_online_2, None, None); - wait_for_refresh(&mut rcv_wallet_1, rcv_online_1, None, None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet_1, &receive_data_1.recipient_id); + rcv_party_2.wait_for_refresh(None); + rcv_party_1.wait_for_refresh(None); + let rcv_transfer = rcv_party_1.get_test_transfer_recipient(&receive_data_1.recipient_id); let (rcv_transfer_data, _rcv_asset_transfer) = - get_test_transfer_data(&rcv_wallet_1, &rcv_transfer); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); - let batch_transfers = get_test_batch_transfers(&wallet, &txid); + rcv_party_1.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(Some(&asset.asset_id)); + let batch_transfers = party.db_batch_transfers_filtered(&txid); let batch_transfer = batch_transfers.first().unwrap(); - let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx); - let transfers = get_test_transfers(&wallet, asset_transfer.idx); + let asset_transfer = party.get_test_asset_transfer(batch_transfer.idx); + let transfers = party.db_transfers_filtered(asset_transfer.idx); for transfer in transfers { - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(transfer_data.status, TransferStatus::Failed); } assert_eq!(rcv_transfer_data.kind, TransferKind::ReceiveWitness); @@ -4554,10 +4352,8 @@ fn witness_fail_wrong_vout() { #[cfg(any(feature = "electrum", feature = "esplora"))] fn min_confirmations_common( - wallet: &mut Wallet, - online: Online, - rcv_wallet: &mut Wallet, - rcv_online: Online, + party: &mut SinglesigParty, + rcv_party: &mut SinglesigParty, esplora: bool, ) { let amount: u64 = 66; @@ -4567,14 +4363,15 @@ fn min_confirmations_common( let min_confirmations = 2; // issue - let asset = test_issue_asset_nia(wallet, online, None); + let asset = party.issue_asset_nia(None); // avoid bitcoind sync issues let _guard = stop_mining_when_alone(); force_mine_no_resume_when_alone(esplora); // send - let receive_data = rcv_wallet + let receive_data = rcv_party + .wallet .blind_receive( None, Assignment::Any, @@ -4592,9 +4389,10 @@ fn min_confirmations_common( transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = wallet + let txid = party + .wallet .send( - online, + party.online, recipient_map, false, FEE_RATE, @@ -4605,12 +4403,12 @@ fn min_confirmations_common( .txid; assert!(!txid.is_empty()); - let rcv_transfer = get_test_transfer_recipient(rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (_, rcv_batch_transfer) = get_test_transfer_related(rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); - let (_, batch_transfer) = get_test_transfer_related(wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (_, rcv_batch_transfer) = rcv_party.get_test_transfer_related(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); + let (_, batch_transfer) = party.get_test_transfer_related(&transfer); assert_eq!(rcv_batch_transfer.min_confirmations, min_confirmations); assert_eq!(batch_transfer.min_confirmations, min_confirmations); assert_eq!( @@ -4620,11 +4418,11 @@ fn min_confirmations_common( assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(rcv_wallet, rcv_online, None, None); - wait_for_refresh(wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations @@ -4633,11 +4431,11 @@ fn min_confirmations_common( // transfers remain in status WaitingConfirmations after a block is mined force_mine_no_resume_when_alone(esplora); - assert!(!test_refresh_all(rcv_wallet, rcv_online)); - assert!(!test_refresh_asset(wallet, online, &asset.asset_id)); + assert!(!rcv_party.refresh_all()); + assert!(!party.refresh_asset(&asset.asset_id)); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations @@ -4646,11 +4444,11 @@ fn min_confirmations_common( // transfers progress to status Settled after a second block is mined force_mine_no_resume_when_alone(esplora); - wait_for_refresh(rcv_wallet, rcv_online, None, None); - wait_for_refresh(wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); @@ -4659,7 +4457,8 @@ fn min_confirmations_common( let min_confirmations = 0; // send - let receive_data = rcv_wallet + let receive_data = rcv_party + .wallet .blind_receive( None, Assignment::Any, @@ -4677,9 +4476,10 @@ fn min_confirmations_common( transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = wallet + let txid = party + .wallet .send( - online, + party.online, recipient_map, false, FEE_RATE, @@ -4690,12 +4490,12 @@ fn min_confirmations_common( .txid; assert!(!txid.is_empty()); - let rcv_transfer = get_test_transfer_recipient(rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (_, rcv_batch_transfer) = get_test_transfer_related(rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); - let (_, batch_transfer) = get_test_transfer_related(wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (_, rcv_batch_transfer) = rcv_party.get_test_transfer_related(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); + let (_, batch_transfer) = party.get_test_transfer_related(&transfer); assert_eq!(rcv_batch_transfer.min_confirmations, min_confirmations); assert_eq!(batch_transfer.min_confirmations, min_confirmations); assert_eq!( @@ -4705,11 +4505,11 @@ fn min_confirmations_common( assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(rcv_wallet, rcv_online, None, None); - wait_for_refresh(wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations @@ -4717,16 +4517,16 @@ fn min_confirmations_common( assert_eq!(transfer_data.status, TransferStatus::WaitingConfirmations); // transfers progress to status Settled before a block is mined - wait_for_refresh(rcv_wallet, rcv_online, None, None); - wait_for_refresh(wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let (rcv_transfer_data, _) = get_test_transfer_data(rcv_wallet, &rcv_transfer); - let (transfer_data, _) = get_test_transfer_data(wallet, &transfer); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // spend received allocations - let receive_data = test_blind_receive(wallet); + let receive_data = party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -4736,21 +4536,21 @@ fn min_confirmations_common( transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(rcv_wallet, rcv_online, &recipient_map); + let txid = rcv_party.send_retry(&recipient_map); assert!(!txid.is_empty()); force_mine_no_resume_when_alone(esplora); - wait_for_refresh(wallet, online, None, None); - wait_for_refresh(rcv_wallet, rcv_online, Some(&asset.asset_id), None); + party.wait_for_refresh(None); + rcv_party.wait_for_refresh(Some(&asset.asset_id)); drop(_guard); mine(esplora); - wait_for_refresh(wallet, online, None, None); - wait_for_refresh(rcv_wallet, rcv_online, Some(&asset.asset_id), None); + party.wait_for_refresh(None); + rcv_party.wait_for_refresh(Some(&asset.asset_id)); - let rcv_transfer = get_test_transfer_recipient(wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(rcv_wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(rcv_wallet, &transfer); + let rcv_transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = rcv_party.get_test_transfer_sender(&txid); + let (transfer_data, _) = rcv_party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); } @@ -4762,10 +4562,10 @@ fn min_confirmations_electrum() { initialize(); // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); - min_confirmations_common(&mut wallet, online, &mut rcv_wallet, rcv_online, false); + min_confirmations_common(&mut party, &mut rcv_party, false); } #[cfg(feature = "esplora")] @@ -4775,10 +4575,10 @@ fn min_confirmations_esplora() { initialize(); // wallets - let (mut wallet, online) = get_funded_wallet!(ESPLORA_URL.to_string()); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(ESPLORA_URL.to_string()); + let mut party = get_funded_party!(ESPLORA_URL.to_string()); + let mut rcv_party = get_funded_party!(ESPLORA_URL.to_string()); - min_confirmations_common(&mut wallet, online, &mut rcv_wallet, rcv_online, true); + min_confirmations_common(&mut party, &mut rcv_party, true); } #[cfg(feature = "electrum")] @@ -4791,27 +4591,19 @@ fn spend_double_receive() { let amount_2 = 200; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); // create bigger UTXOs for wallet_2 so a single one can support a witness transfer - let (mut wallet_2, online_2) = get_funded_noutxo_wallet!(); - test_create_utxos( - &mut wallet_2, - online_2, - false, - None, - Some(5000), - FEE_RATE, - None, - ); + let mut party_1 = get_funded_party!(); + let mut party_3 = get_funded_party!(); + let mut party_2 = get_funded_noutxo_party!(); + party_2.create_utxos(false, None, Some(5000), FEE_RATE, None); // issue println!("issue"); - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // send a first time 1->2 (blind) println!("send blind 1->2"); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -4821,9 +4613,10 @@ fn spend_double_receive() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = wallet_1 + let txid_1 = party_1 + .wallet .send( - online_1, + party_1.online, recipient_map, true, FEE_RATE, @@ -4835,20 +4628,20 @@ fn spend_double_receive() { assert!(!txid_1.is_empty()); // settle transfer mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); // check transfer status - let rcv_transfer = get_test_transfer_recipient(&wallet_2, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_2, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_1, &txid_1); - let (transfer_data, _) = get_test_transfer_data(&wallet_1, &transfer); + party_2.wait_for_refresh(None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); + let rcv_transfer = party_2.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_2.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_1.get_test_transfer_sender(&txid_1); + let (transfer_data, _) = party_1.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // send a second time 1->2 (witness, so the 2 allocations can't be on the same UTXO) println!("send witness 1->2"); - let receive_data = test_witness_receive(&mut wallet_2); + let receive_data = party_2.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -4861,9 +4654,10 @@ fn spend_double_receive() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = wallet_1 + let txid_2 = party_1 + .wallet .send( - online_1, + party_1.online, recipient_map, true, FEE_RATE, @@ -4875,19 +4669,19 @@ fn spend_double_receive() { assert!(!txid_2.is_empty()); // settle transfer mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); // check transfer status - let rcv_transfer = get_test_transfer_recipient(&wallet_2, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_2, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_1, &txid_2); - let (transfer_data, _) = get_test_transfer_data(&wallet_1, &transfer); + party_2.wait_for_refresh(None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); + let rcv_transfer = party_2.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_2.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_1.get_test_transfer_sender(&txid_2); + let (transfer_data, _) = party_1.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // check wallet_2 has the 2 expected allocations - let unspents = test_list_unspents(&mut wallet_2, None, true); + let unspents = party_2.list_unspents(true); let asset_unspents: Vec<&Unspent> = unspents .iter() .filter(|u| { @@ -4924,11 +4718,11 @@ fn spend_double_receive() { // send 2->3, manually selecting the 1st allocation (blind, amount_1) only println!("send witness 2->3"); - let receive_data = test_witness_receive(&mut wallet_3); + let receive_data = party_3.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { - assignment: Assignment::Fungible(amount_1), // amount of the 1st received allocation + assignment: Assignment::Fungible(amount_1), recipient_id: receive_data.recipient_id.clone(), witness_data: Some(WitnessData { amount_sat: 1000, @@ -4938,19 +4732,15 @@ fn spend_double_receive() { }], )]); // manually set the input unspents to the UTXO of the 1st allocation - let txn = wallet_2.database().begin_transaction().unwrap(); - let db_data = txn.get_db_data(false).unwrap(); - let utxos = txn.get_unspent_txos(db_data.txos.clone()).unwrap(); - let mut input_unspents = txn - .get_rgb_allocations( - utxos, - Some(db_data.colorings.clone()), - Some(db_data.batch_transfers.clone()), - Some(db_data.asset_transfers.clone()), - Some(db_data.transfers.clone()), - ) - .unwrap(); - txn.commit().unwrap(); + let db_data = party_2.db_data(false); + let utxos = party_2.db_unspent_txos(db_data.txos.clone()); + let mut input_unspents = party_2.db_rgb_allocations( + utxos, + Some(db_data.colorings.clone()), + Some(db_data.batch_transfers.clone()), + Some(db_data.asset_transfers.clone()), + Some(db_data.transfers.clone()), + ); input_unspents.retain(|u| { !u.rgb_allocations.is_empty() && u.rgb_allocations.iter().all(|a| { @@ -4965,26 +4755,26 @@ fn spend_double_receive() { println!("setting MOCK_INPUT_UNSPENTS"); MOCK_INPUT_UNSPENTS.with_borrow_mut(|v| v.push(input_unspents.first().unwrap().clone())); // send (will use the manually-selected input unspent) - let txid_3 = test_send(&mut wallet_2, online_2, &recipient_map); + let txid_3 = party_2.send_retry(&recipient_map); assert!(!txid_3.is_empty()); // settle transfer - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, Some(&asset.asset_id), None); // check transfer status - let rcv_transfer = get_test_transfer_recipient(&wallet_3, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet_3, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet_2, &txid_3); - let (transfer_data, _) = get_test_transfer_data(&wallet_2, &transfer); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(Some(&asset.asset_id)); + let rcv_transfer = party_3.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = party_3.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party_2.get_test_transfer_sender(&txid_3); + let (transfer_data, _) = party_2.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); // check final balances - let balance_1 = test_get_asset_balance(&wallet_1, &asset.asset_id); - let balance_2 = test_get_asset_balance(&wallet_2, &asset.asset_id); - let balance_3 = test_get_asset_balance(&wallet_3, &asset.asset_id); + let balance_1 = party_1.get_asset_balance(&asset.asset_id); + let balance_2 = party_2.get_asset_balance(&asset.asset_id); + let balance_3 = party_3.get_asset_balance(&asset.asset_id); assert_eq!( balance_1, Balance { @@ -5021,15 +4811,15 @@ fn input_sorting() { let amount: u64 = 120; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue (allocations not sorted) - let asset = test_issue_asset_nia(&mut wallet, online, Some(&amounts)); + let asset = party.issue_asset_nia(Some(&amounts)); // send, spending the 111 and 222 allocations println!("\nsend 1"); - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5039,17 +4829,17 @@ fn input_sorting() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfers - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // check the intended UTXOs have been used - let unspents = list_test_unspents(&mut wallet, "after send"); + let unspents = party.list_unspents(false); let allocations: Vec<&RgbAllocation> = unspents.iter().flat_map(|e| &e.rgb_allocations).collect(); let mut cur_amounts: Vec = allocations @@ -5079,14 +4869,14 @@ fn spend_witness_receive_utxo() { let amount: u64 = 66; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_noutxo_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_noutxo_party!(); // issue - let asset_a = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset_a = party_1.issue_asset_nia(None); // send - let receive_data_1 = test_witness_receive(&mut wallet_2); + let receive_data_1 = party_2.witness_receive(); let recipient_map_1 = HashMap::from([( asset_a.asset_id.clone(), vec![Recipient { @@ -5099,16 +4889,16 @@ fn spend_witness_receive_utxo() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map_1); + let txid_1 = party_1.send_retry(&recipient_map_1); assert!(!txid_1.is_empty()); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut wallet_2, online_2, None, None); - let transfer_1_recv = get_test_transfer_recipient(&wallet_2, &receive_data_1.recipient_id); - let (transfer_1_recv_data, _) = get_test_transfer_data(&wallet_2, &transfer_1_recv); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset_a.asset_id), None); - let (transfer_1_send, _, _) = get_test_transfer_sender(&wallet_1, &txid_1); - let (transfer_1_send_data, _) = get_test_transfer_data(&wallet_1, &transfer_1_send); + party_2.wait_for_refresh(None); + let transfer_1_recv = party_2.get_test_transfer_recipient(&receive_data_1.recipient_id); + let (transfer_1_recv_data, _) = party_2.get_test_transfer_data(&transfer_1_recv); + party_1.wait_for_refresh(Some(&asset_a.asset_id)); + let (transfer_1_send, _, _) = party_1.get_test_transfer_sender(&txid_1); + let (transfer_1_send_data, _) = party_1.get_test_transfer_data(&transfer_1_send); assert_eq!( transfer_1_recv_data.status, TransferStatus::WaitingConfirmations @@ -5120,16 +4910,18 @@ fn spend_witness_receive_utxo() { // mine and refresh the sender wallet only (receiver transfer still WaitingConfirmations) mine(false); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset_a.asset_id), None); + party_1.wait_for_refresh(Some(&asset_a.asset_id)); // sync DB TXOs for the receiver wallet - test_create_utxos_begin_result(&mut wallet_2, online_2, false, None, None, FEE_RATE).unwrap(); + party_2 + .create_utxos_begin_result(false, None, None, FEE_RATE) + .unwrap(); // make sure the witness receive UTXO is available - assert!(test_list_unspents(&mut wallet_2, Some(online_2), false).len() > 1); + assert!(party_2.list_unspents_with_sync(false).len() > 1); // try to issue an asset on the pending witness receive UTXO > should fail - let result = test_issue_asset_nia_result(&mut wallet_2, online_2, Some(&[AMOUNT])); + let result = party_2.issue_asset_nia_result(Some(&[AMOUNT])); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } @@ -5142,15 +4934,15 @@ fn rgb_change_on_btc_change() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_funded_party!(); // issue - test_create_utxos(&mut wallet, online, false, Some(1), None, FEE_RATE, None); - let asset = test_issue_asset_nia(&mut wallet, online, None); + party.create_utxos(false, Some(1), None, FEE_RATE, None); + let asset = party.issue_asset_nia(None); // send with no available colorable UTXOs (need to allocate change to BTC change UTXO) - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5160,13 +4952,13 @@ fn rgb_change_on_btc_change() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // RGB change has been allocated to the same UTXO as the BTC change (exists = false) - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); - let unspents = test_list_unspents(&mut wallet, None, false); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); + let unspents = party.list_unspents(false); assert_eq!( unspents .iter() @@ -5187,12 +4979,12 @@ fn rgb_change_on_btc_change() { assert_eq!(allocation.assignment, Assignment::Fungible(AMOUNT - amount)); // transfers progress to status WaitingConfirmations after a refresh - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - wait_for_refresh(&mut wallet, online, None, None); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + rcv_party.wait_for_refresh(None); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + party.wait_for_refresh(None); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!( rcv_transfer_data.status, @@ -5202,13 +4994,13 @@ fn rgb_change_on_btc_change() { // transfers progress to status Settled after tx mining + refresh mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); assert_eq!(transfer_data.status, TransferStatus::Settled); } @@ -5222,18 +5014,18 @@ fn no_inexistent_utxos() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let (mut rcv_wallet, _) = get_empty_wallet!(); + let mut party = get_funded_noutxo_party!(); + let mut rcv_party = get_empty_party!(); // create 1 UTXO let size = Some(UTXO_SIZE * 2); - test_create_utxos(&mut wallet, online, true, Some(1), size, FEE_RATE, None); + party.create_utxos(true, Some(1), size, FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT])); + let asset = party.issue_asset_nia(Some(&[AMOUNT])); // send - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5246,34 +5038,34 @@ fn no_inexistent_utxos() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after send (WaitingCounterparty)"); + party.show_unspent_colorings("after send (WaitingCounterparty)"); // 1 UTXO being spent, 1 UTXO with exists = false // trying to get an UTXO for a blind receive should fail - let result = test_blind_receive_result(&mut wallet); + let result = party.blind_receive_result(); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // trying to issue an asset should fail - let result = test_issue_asset_nia_result(&mut wallet, online, None); + let result = party.issue_asset_nia_result(None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); - let result = test_issue_asset_cfa_result(&mut wallet, online, None, None); + let result = party.issue_asset_cfa_result(None, None); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); - let result = test_issue_asset_uda_result(&mut wallet, online, None, None, vec![]); + let result = party.issue_asset_uda_result(None, None, vec![]); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); // trying to create 1 UTXO with up_to = true should create 1 - test_create_utxos(&mut wallet, online, true, Some(1), None, FEE_RATE, None); + party.create_utxos(true, Some(1), None, FEE_RATE, None); // 1 UTXO being spent, 1 UTXO with exists = false, 1 new UTXO // issuing an asset should now succeed - let asset_2 = test_issue_asset_nia(&mut wallet, online, Some(&[AMOUNT * 2])); + let asset_2 = party.issue_asset_nia(Some(&[AMOUNT * 2])); - show_unspent_colorings(&mut wallet, "after 2nd issue"); + party.show_unspent_colorings("after 2nd issue"); // 1 UTXO being spent, 1 UTXO with exists = false, 1 UTXO with an allocated asset // trying to send more BTC than what's available in the UTXO being spent should fail - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_2.asset_id.clone(), vec![Recipient { @@ -5286,7 +5078,7 @@ fn no_inexistent_utxos() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_begin_result(&mut wallet, online, &recipient_map); + let result = party.send_begin_result(&recipient_map); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } @@ -5301,18 +5093,18 @@ fn min_fee_rate() { let fee_rate = 1; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // prepare transfer data let recipient_map = HashMap::from([( asset.asset_id.clone(), (1..=5) .map(|_| { - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); Recipient { assignment: Assignment::Fungible(amount), recipient_id: receive_data.recipient_id, @@ -5327,9 +5119,10 @@ fn min_fee_rate() { )]); // check fee amount is the expected one - let res = wallet + let res = party + .wallet .send_begin( - online, + party.online, recipient_map.clone(), false, fee_rate, @@ -5343,10 +5136,11 @@ fn min_fee_rate() { assert_eq!(fee, 510); // actual send - test_fail_transfers_single(&mut wallet, online, res.batch_transfer_idx.unwrap()); - let txid = wallet + party.fail_transfers_single(res.batch_transfer_idx.unwrap()); + let txid = party + .wallet .send( - online, + party.online, recipient_map.clone(), false, fee_rate, @@ -5358,18 +5152,16 @@ fn min_fee_rate() { assert!(!txid.is_empty()); // ACK transfer - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); // broadcast tx - assert!(test_refresh_asset(&mut wallet, online, &asset.asset_id)); + rcv_party.wait_for_refresh(None); + assert!(party.refresh_asset(&asset.asset_id)); } #[cfg(any(feature = "electrum", feature = "esplora"))] fn max_fee_exceeded_common( asset_id: &str, - wallet: &mut Wallet, - online: Online, - rcv_wallet: &mut Wallet, - rcv_online: Online, + party: &mut SinglesigParty, + rcv_party: &mut SinglesigParty, transfer_idx: i32, ) { let fee_rate = 20000; @@ -5377,19 +5169,11 @@ fn max_fee_exceeded_common( let amount_sat: u64 = 698; // get a lot of funds - (0..9).for_each(|_| fund_wallet(test_get_address(wallet))); - test_create_utxos( - wallet, - online, - false, - Some(20), - Some(u32::MAX / 100), - FEE_RATE, - None, - ); + (0..9).for_each(|_| fund_wallet(party.get_address())); + party.create_utxos(false, Some(20), Some(u32::MAX / 100), FEE_RATE, None); // prepare transfer data - let receive_data = test_witness_receive(rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset_id.to_string(), vec![Recipient { @@ -5404,9 +5188,10 @@ fn max_fee_exceeded_common( )]); // send - let send_result = wallet + let send_result = party + .wallet .send( - online, + party.online, recipient_map.clone(), false, fee_rate, @@ -5417,9 +5202,9 @@ fn max_fee_exceeded_common( assert!(!send_result.txid.is_empty()); // ACK transfer - wait_for_refresh(rcv_wallet, rcv_online, None, None); // broadcast tx - let result = test_refresh_result(wallet, online, None, &[]).unwrap(); + rcv_party.wait_for_refresh(None); + let result = party.refresh_result(None, &[]).unwrap(); assert_eq!( result, HashMap::from([( @@ -5432,8 +5217,8 @@ fn max_fee_exceeded_common( } )]) ); - test_fail_transfers_single(wallet, online, send_result.batch_transfer_idx); - let result = test_refresh_result(wallet, online, None, &[]).unwrap(); + party.fail_transfers_single(send_result.batch_transfer_idx); + let result = party.refresh_result(None, &[]).unwrap(); assert_eq!(result, HashMap::new()); } @@ -5443,19 +5228,12 @@ fn max_fee_exceeded_common( fn max_fee_exceeded_electrum() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); - max_fee_exceeded_common( - &asset.asset_id, - &mut wallet, - online, - &mut rcv_wallet, - rcv_online, - 2, - ); + max_fee_exceeded_common(&asset.asset_id, &mut party, &mut rcv_party, 2); } #[cfg(feature = "esplora")] @@ -5464,28 +5242,19 @@ fn max_fee_exceeded_electrum() { fn max_fee_exceeded_esplora() { initialize(); - let (mut wallet, online) = get_funded_wallet!(ESPLORA_URL.to_string()); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(ESPLORA_URL.to_string()); + let mut party = get_funded_party!(ESPLORA_URL.to_string()); + let mut rcv_party = get_empty_party!(ESPLORA_URL.to_string()); - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); - max_fee_exceeded_common( - &asset.asset_id, - &mut wallet, - online, - &mut rcv_wallet, - rcv_online, - 2, - ); + max_fee_exceeded_common(&asset.asset_id, &mut party, &mut rcv_party, 2); } #[cfg(any(feature = "electrum", feature = "esplora"))] fn min_relay_fee_common( asset_id: &str, - wallet: &mut Wallet, - online: Online, - rcv_wallet: &mut Wallet, - rcv_online: Online, + party: &mut SinglesigParty, + rcv_party: &mut SinglesigParty, transfer_idx: i32, ) { let fee_rate = 0; @@ -5497,7 +5266,7 @@ fn min_relay_fee_common( asset_id.to_string(), (1..=5) .map(|_| { - let receive_data = test_witness_receive(rcv_wallet); + let receive_data = rcv_party.witness_receive(); Recipient { assignment: Assignment::Fungible(amount), recipient_id: receive_data.recipient_id, @@ -5514,9 +5283,10 @@ fn min_relay_fee_common( // check fee amount is the expected one println!("setting MOCK_CHECK_FEE_RATE"); MOCK_CHECK_FEE_RATE.replace(vec![true, true]); - let res = wallet + let res = party + .wallet .send_begin( - online, + party.online, recipient_map.clone(), false, fee_rate, @@ -5528,14 +5298,15 @@ fn min_relay_fee_common( let psbt = Psbt::from_str(&res.psbt).unwrap(); let fee = psbt.fee().unwrap().to_sat(); assert_eq!(fee, 0); - test_fail_transfers_single(wallet, online, res.batch_transfer_idx.unwrap()); + party.fail_transfers_single(res.batch_transfer_idx.unwrap()); // actual send println!("setting MOCK_CHECK_FEE_RATE"); MOCK_CHECK_FEE_RATE.replace(vec![true, true]); - let send_result = wallet + let send_result = party + .wallet .send( - online, + party.online, recipient_map.clone(), false, fee_rate, @@ -5546,9 +5317,9 @@ fn min_relay_fee_common( assert!(!send_result.txid.is_empty()); // ACK transfer - wait_for_refresh(rcv_wallet, rcv_online, None, None); // broadcast tx - let result = test_refresh_result(wallet, online, None, &[]).unwrap(); + rcv_party.wait_for_refresh(None); + let result = party.refresh_result(None, &[]).unwrap(); assert_eq!( result, HashMap::from([( @@ -5561,8 +5332,8 @@ fn min_relay_fee_common( } )]) ); - test_fail_transfers_single(wallet, online, send_result.batch_transfer_idx); - let result = test_refresh_result(wallet, online, None, &[]).unwrap(); + party.fail_transfers_single(send_result.batch_transfer_idx); + let result = party.refresh_result(None, &[]).unwrap(); assert_eq!(result, HashMap::new()); } @@ -5572,19 +5343,12 @@ fn min_relay_fee_common( fn min_relay_fee_electrum() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); - min_relay_fee_common( - &asset.asset_id, - &mut wallet, - online, - &mut rcv_wallet, - rcv_online, - 3, - ); + min_relay_fee_common(&asset.asset_id, &mut party, &mut rcv_party, 3); } #[cfg(feature = "esplora")] @@ -5593,19 +5357,12 @@ fn min_relay_fee_electrum() { fn min_relay_fee_esplora() { initialize(); - let (mut wallet, online) = get_funded_wallet!(ESPLORA_URL.to_string()); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(ESPLORA_URL.to_string()); + let mut party = get_funded_party!(ESPLORA_URL.to_string()); + let mut rcv_party = get_empty_party!(ESPLORA_URL.to_string()); - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); - min_relay_fee_common( - &asset.asset_id, - &mut wallet, - online, - &mut rcv_wallet, - rcv_online, - 3, - ); + min_relay_fee_common(&asset.asset_id, &mut party, &mut rcv_party, 3); } #[cfg(feature = "electrum")] @@ -5615,11 +5372,11 @@ fn script_buf_to_from_recipient_id() { initialize(); // wallets - let (mut wallet, _online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // get a script bug from an address (witness receive) - let address_str = test_get_address(&mut wallet); - let script_buf = wallet.get_script_pubkey(&address_str).unwrap(); + let address_str = party.get_address(); + let script_buf = party.wallet.get_script_pubkey(&address_str).unwrap(); // recipient ID from script buf let recipient_id = recipient_id_from_script_buf(script_buf.clone(), BitcoinNetwork::Regtest); @@ -5632,7 +5389,7 @@ fn script_buf_to_from_recipient_id() { assert_eq!(script_from_recipient.unwrap(), script_buf); // script buf from recipient ID None (blinded) - let receive_data = test_blind_receive(&mut wallet); + let receive_data = party.blind_receive(); let script_from_recipient = script_buf_from_recipient_id(receive_data.recipient_id).unwrap(); assert!(script_from_recipient.is_none()); @@ -5650,18 +5407,18 @@ fn skip_sync() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue (2 allocations, 1 per send) let issue_amounts = [100, 200]; - let asset = test_issue_asset_nia(&mut wallet, online, Some(&issue_amounts)); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let asset = party.issue_asset_nia(Some(&issue_amounts)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 1); assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance); // send (blinded) skipping sync - let receive_data_1 = test_blind_receive(&mut rcv_wallet); + let receive_data_1 = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5671,9 +5428,10 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = wallet + let txid_1 = party + .wallet .send( - online, + party.online, recipient_map.clone(), false, FEE_RATE, @@ -5684,10 +5442,10 @@ fn skip_sync() { .txid; assert!(!txid_1.is_empty()); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_1.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_1); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_1.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_1); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); // amount let change = issue_amounts[0] - amount; @@ -5708,7 +5466,7 @@ fn skip_sync() { assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); // send (witness) skipping sync - let receive_data_2 = test_witness_receive(&mut rcv_wallet); + let receive_data_2 = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5721,9 +5479,10 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = wallet + let txid_2 = party + .wallet .send( - online, + party.online, recipient_map.clone(), false, FEE_RATE, @@ -5734,10 +5493,10 @@ fn skip_sync() { .txid; assert!(!txid_2.is_empty()); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data_2.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_2); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data_2.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_2); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); // amount assert_eq!( @@ -5757,24 +5516,16 @@ fn skip_sync() { assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); // settle transfers - wait_for_refresh(&mut rcv_wallet, rcv_online, None, Some(&[1, 2])); - wait_for_refresh(&mut wallet, online, None, Some(&[2, 3])); + rcv_party.wait_for_refresh_raw(None, Some(&[1, 2])); + party.wait_for_refresh_raw(None, Some(&[2, 3])); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, Some(&[1, 2])); - wait_for_refresh(&mut wallet, online, None, Some(&[2, 3])); - assert!(check_test_transfer_status_sender( - &wallet, - &txid_1, - TransferStatus::Settled - )); - assert!(check_test_transfer_status_sender( - &wallet, - &txid_2, - TransferStatus::Settled - )); + rcv_party.wait_for_refresh_raw(None, Some(&[1, 2])); + party.wait_for_refresh_raw(None, Some(&[2, 3])); + assert!(party.check_test_transfer_status_sender(&txid_1, TransferStatus::Settled)); + assert!(party.check_test_transfer_status_sender(&txid_2, TransferStatus::Settled)); // send to oneself (witness) skipping sync - let receive_data_3 = test_witness_receive(&mut wallet); + let receive_data_3 = party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5787,9 +5538,10 @@ fn skip_sync() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_3 = wallet + let txid_3 = party + .wallet .send( - online, + party.online, recipient_map.clone(), false, FEE_RATE, @@ -5801,10 +5553,10 @@ fn skip_sync() { assert!(!txid_3.is_empty()); // transfers are in WaitingCounterparty - let rcv_transfer = get_test_transfer_recipient(&wallet, &receive_data_3.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet, &rcv_transfer); - let (transfer, _, _) = get_test_transfer_sender(&wallet, &txid_3); - let (transfer_data, _) = get_test_transfer_data(&wallet, &transfer); + let rcv_transfer = party.get_test_transfer_recipient(&receive_data_3.recipient_id); + let (rcv_transfer_data, _) = party.get_test_transfer_data(&rcv_transfer); + let (transfer, _, _) = party.get_test_transfer_sender(&txid_3); + let (transfer_data, _) = party.get_test_transfer_data(&transfer); assert_eq!(rcv_transfer.requested_assignment, Some(Assignment::Any)); assert_eq!( transfer.requested_assignment, @@ -5817,18 +5569,21 @@ fn skip_sync() { assert_eq!(transfer_data.status, TransferStatus::WaitingCounterparty); // refresh skipping sync - wallet.refresh(online, None, vec![], true).unwrap(); + party + .wallet + .refresh(party.online, None, vec![], true) + .unwrap(); // transfers are now in WaitingConfirmations - let rcv_transfer = get_test_transfer_recipient(&wallet, &receive_data_3.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet, &rcv_transfer); - let batch_transfers = get_test_batch_transfers(&wallet, &txid_3); + let rcv_transfer = party.get_test_transfer_recipient(&receive_data_3.recipient_id); + let (rcv_transfer_data, _) = party.get_test_transfer_data(&rcv_transfer); + let batch_transfers = party.db_batch_transfers_filtered(&txid_3); let batch_transfer = batch_transfers.iter().find(|t| t.idx == 5).unwrap(); - let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx); - let transfers: Vec = get_test_transfers(&wallet, asset_transfer.idx).collect(); + let asset_transfer = party.get_test_asset_transfer(batch_transfer.idx); + let transfers: Vec = party.db_transfers_filtered(asset_transfer.idx); assert_eq!(transfers.len(), 1); let transfer = transfers.first().unwrap(); - let (transfer_data, _) = get_test_transfer_data(&wallet, transfer); + let (transfer_data, _) = party.get_test_transfer_data(transfer); assert_eq!( rcv_transfer_data.assignments, vec![Assignment::Fungible(amount)] @@ -5845,35 +5600,42 @@ fn skip_sync() { // mine and refresh skipping sync > cannot refresh ReceiveWitness transfer as a sync is needed mine(false); - wallet.refresh(online, None, vec![], true).unwrap(); - show_unspent_colorings(&mut wallet, "after refresh 2"); + party + .wallet + .refresh(party.online, None, vec![], true) + .unwrap(); + party.show_unspent_colorings("after refresh 2"); // Send transfer is now settled - let batch_transfers = get_test_batch_transfers(&wallet, &txid_3); + let batch_transfers = party.db_batch_transfers_filtered(&txid_3); let batch_transfer = batch_transfers.iter().find(|t| t.idx == 5).unwrap(); - let asset_transfer = get_test_asset_transfer(&wallet, batch_transfer.idx); - let transfers: Vec = get_test_transfers(&wallet, asset_transfer.idx).collect(); + let asset_transfer = party.get_test_asset_transfer(batch_transfer.idx); + let transfers: Vec = party.db_transfers_filtered(asset_transfer.idx); let transfer = transfers.first().unwrap(); - let (transfer_data, _) = get_test_transfer_data(&wallet, transfer); + let (transfer_data, _) = party.get_test_transfer_data(transfer); assert_eq!(transfer_data.status, TransferStatus::Settled); // sync and refresh again (still skipping sync) > ReceiveWitness transfer now refreshes + new UTXO appears - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, }, ) .unwrap(); - wallet.refresh(online, None, vec![], true).unwrap(); - show_unspent_colorings(&mut wallet, "after refresh 3"); + party + .wallet + .refresh(party.online, None, vec![], true) + .unwrap(); + party.show_unspent_colorings("after refresh 3"); // ReceiveWitness transfer is now settled as well - let rcv_transfer = get_test_transfer_recipient(&wallet, &receive_data_3.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&wallet, &rcv_transfer); - assert_eq!(rcv_transfer_data.status, TransferStatus::Settled,); + let rcv_transfer = party.get_test_transfer_recipient(&receive_data_3.recipient_id); + let (rcv_transfer_data, _) = party.get_test_transfer_data(&rcv_transfer); + assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); } #[cfg(feature = "electrum")] @@ -5886,25 +5648,25 @@ fn ifa_success() { let amount_inflation: u64 = 42; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party!(); // issue - let asset = test_issue_asset_ifa(&mut wallet, online, None, None, None); - show_unspent_colorings(&mut wallet, "after issuance"); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let asset = party.issue_asset_ifa(None, None, None); + party.show_unspent_colorings("after issuance"); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 1); assert!(transfers.iter().any(|t| t.kind == TransferKind::Issuance)); // issuance checks - let unspents = test_list_unspents(&mut wallet, None, false); + let unspents = party.list_unspents(false); let mut allocations = unspents.iter().flat_map(|u| &u.rgb_allocations); assert!(allocations.any(|a| a.assignment == Assignment::Fungible(AMOUNT))); assert!(allocations.any(|a| a.assignment == Assignment::InflationRight(AMOUNT_INFLATION))); // send - let receive_data_fungible = test_blind_receive(&mut rcv_wallet); - let receive_data_inflation = test_blind_receive(&mut rcv_wallet); + let receive_data_fungible = rcv_party.blind_receive(); + let receive_data_inflation = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -5922,28 +5684,27 @@ fn ifa_success() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after send"); + party.show_unspent_colorings("after send"); // transfers progress to status Settled after refreshing - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); // transfer checks - let recv_fungible = - get_test_transfer_recipient(&rcv_wallet, &receive_data_fungible.recipient_id); - let (recv_fungible_data, _) = get_test_transfer_data(&rcv_wallet, &recv_fungible); + let recv_fungible = rcv_party.get_test_transfer_recipient(&receive_data_fungible.recipient_id); + let (recv_fungible_data, _) = rcv_party.get_test_transfer_data(&recv_fungible); assert_eq!(recv_fungible_data.status, TransferStatus::Settled); let recv_inflation = - get_test_transfer_recipient(&rcv_wallet, &receive_data_fungible.recipient_id); - let (recv_inflation_data, _) = get_test_transfer_data(&rcv_wallet, &recv_inflation); + rcv_party.get_test_transfer_recipient(&receive_data_inflation.recipient_id); + let (recv_inflation_data, _) = rcv_party.get_test_transfer_data(&recv_inflation); assert_eq!(recv_inflation_data.status, TransferStatus::Settled); - let transfers = test_list_transfers(&wallet, Some(&asset.asset_id)); + let transfers = party.list_transfers(Some(&asset.asset_id)); assert_eq!(transfers.len(), 3); let mut sends = transfers.iter().filter(|t| t.kind == TransferKind::Send); assert_eq!(sends.clone().count(), 2); @@ -5961,13 +5722,13 @@ fn ifa_success() { assert!(send_inflation.change_utxo.is_some()); // send all assets to another UTXO - show_unspent_colorings(&mut wallet, "before asset move"); + party.show_unspent_colorings("before asset move"); let Balance { settled: _, future: _, spendable: asset_total, - } = test_get_asset_balance(&wallet, &asset.asset_id); - let receive_data = test_blind_receive(&mut wallet); + } = party.get_asset_balance(&asset.asset_id); + let receive_data = party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -5977,26 +5738,26 @@ fn ifa_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle the transfers - show_unspent_colorings(&mut wallet, "after asset send to oneself"); - wait_for_refresh(&mut wallet, online, None, None); - show_unspent_colorings(&mut wallet, "after asset send to oneself + refresh 1"); + party.show_unspent_colorings("after asset send to oneself"); + party.wait_for_refresh(None); + party.show_unspent_colorings("after asset send to oneself + refresh 1"); mine(false); - wait_for_refresh(&mut wallet, online, None, None); + party.wait_for_refresh(None); // send InflationRight only - show_unspent_colorings(&mut wallet, "before InflationRights move"); // settle the transfers - let unspents = test_list_unspents(&mut wallet, Some(online), true); + party.show_unspent_colorings("before InflationRights move"); + let unspents = party.list_unspents_with_sync(true); let inflation_right_amount = unspents .iter() .flat_map(|u| u.rgb_allocations.clone()) .filter(|a| matches!(a.assignment, Assignment::InflationRight(_))) .map(|a| a.assignment.inflation_amount()) .sum::(); - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6006,32 +5767,32 @@ fn ifa_success() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - show_unspent_colorings(&mut wallet, "after InflationRights move"); // check asset allocations are still spendable (not selected as input) - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + party.show_unspent_colorings("after InflationRights move"); + let balance = party.get_asset_balance(&asset.asset_id); let expected_balance = Balance { settled: asset_total, future: asset_total, spendable: asset_total, }; assert_eq!(balance, expected_balance); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, None, None); - show_unspent_colorings(&mut wallet, "after InflationRights move + refresh"); // check final balances - let balance = test_get_asset_balance(&wallet, &asset.asset_id); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(None); + party.show_unspent_colorings("after InflationRights move + refresh"); + let balance = party.get_asset_balance(&asset.asset_id); let expected_balance = Balance { settled: asset_total, future: asset_total, spendable: asset_total, }; assert_eq!(balance, expected_balance); - let unspents = test_list_unspents(&mut wallet, Some(online), true); + let unspents = party.list_unspents_with_sync(true); let inflation_right_amount = unspents .iter() .flat_map(|u| u.rgb_allocations.clone()) @@ -6069,22 +5830,20 @@ fn ifa_reject_list() { #[cfg(feature = "electrum")] fn test_reject_list_scenario_1() { - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); let list_name = "reject1.list"; write_opouts_to_reject_list(list_name, &[]); - let asset = test_issue_asset_ifa( - &mut wallet_1, - online_1, + let asset = party_1.issue_asset_ifa( Some(&[100, 100]), Some(&[50]), Some(format!("http://localhost:8140/lists/{list_name}")), ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let amt = 60; let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), @@ -6095,20 +5854,20 @@ fn test_reject_list_scenario_1() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map_1); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let txid = party_1.send_retry(&recipient_map_1); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // add to the reject list the newly received allocation - let opouts = extract_opouts_from_transfer(&wallet_2, &asset.asset_id, &txid); + let opouts = party_2.extract_opouts_from_transfer(&asset.asset_id, &txid); assert_eq!(opouts.len(), 1); write_opouts_to_reject_list(list_name, &[opouts[0].to_string()]); // fail to send from the rejected allocation - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let mut recipient_map_2 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6118,7 +5877,7 @@ fn test_reject_list_scenario_1() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_result(&mut wallet_2, online_2, &recipient_map_2); + let result = party_2.send_result(&recipient_map_2); assert_matches!( result, Err(Error::InsufficientAssignments { asset_id: ref t, .. }) if t == &asset.asset_id @@ -6127,16 +5886,17 @@ fn test_reject_list_scenario_1() { // skip build dag check to see that receiver would refuse println!("setting MOCK_SKIP_BUILD_DAG"); MOCK_SKIP_BUILD_DAG.replace(Some(())); - let _txid = test_send(&mut wallet_2, online_2, &recipient_map_2); - test_refresh_all(&mut wallet_3, online_3); - assert!(check_test_transfer_status_recipient( - &wallet_3, - &receive_data.recipient_id, - TransferStatus::Failed - )); + let _txid = party_2.send_retry(&recipient_map_2); + party_3.refresh_all(); + assert!( + party_3.check_test_transfer_status_recipient( + &receive_data.recipient_id, + TransferStatus::Failed + ) + ); // send more assets - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map_3 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6146,45 +5906,43 @@ fn test_reject_list_scenario_1() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_1, online_1, &recipient_map_3); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let _txid = party_1.send_retry(&recipient_map_3); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // now the previously failed send works since enough allowed allocations - let receive_data = test_blind_receive(&mut wallet_3); // avoid RecipientIDAlreadyUsed + let receive_data = party_3.blind_receive(); // avoid RecipientIDAlreadyUsed recipient_map_2 .entry(asset.asset_id) .and_modify(|r| r[0].recipient_id = receive_data.recipient_id.clone()); - let _txid = test_send(&mut wallet_2, online_2, &recipient_map_2); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + let _txid = party_2.send_retry(&recipient_map_2); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + party_2.wait_for_refresh(None); + party_3.wait_for_refresh(None); } #[cfg(feature = "electrum")] fn test_reject_list_scenario_2() { - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); - let (mut wallet_4, online_4) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); + let mut party_4 = get_funded_party!(); let list_name = "reject2.list"; write_opouts_to_reject_list(list_name, &[]); - let asset = test_issue_asset_ifa( - &mut wallet_1, - online_1, + let asset = party_1.issue_asset_ifa( Some(&[200]), Some(&[50]), Some(format!("http://localhost:8140/lists/{list_name}")), ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6194,14 +5952,14 @@ fn test_reject_list_scenario_2() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map_1); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let txid = party_1.send_retry(&recipient_map_1); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let amt = 60; let recipient_map_2 = HashMap::from([( asset.asset_id.clone(), @@ -6212,20 +5970,20 @@ fn test_reject_list_scenario_2() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_2, online_2, &recipient_map_2); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + let _txid = party_2.send_retry(&recipient_map_2); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); // add to the reject list the opout from the first transfer (ancestor of the 2nd) - let opouts = extract_opouts_from_transfer(&wallet_2, &asset.asset_id, &txid); + let opouts = party_2.extract_opouts_from_transfer(&asset.asset_id, &txid); assert_eq!(opouts.len(), 1); write_opouts_to_reject_list(list_name, &[opouts[0].to_string()]); // fail to send from the allocation with a rejected ancestor - let receive_data = test_blind_receive(&mut wallet_4); + let receive_data = party_4.blind_receive(); let mut recipient_map_3 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6235,7 +5993,7 @@ fn test_reject_list_scenario_2() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let result = test_send_result(&mut wallet_3, online_3, &recipient_map_3); + let result = party_3.send_result(&recipient_map_3); assert_matches!( result, Err(Error::InsufficientAssignments { asset_id: ref t, .. }) if t == &asset.asset_id @@ -6244,16 +6002,17 @@ fn test_reject_list_scenario_2() { // skip build dag check to see that receiver would refuse println!("setting MOCK_SKIP_BUILD_DAG"); MOCK_SKIP_BUILD_DAG.replace(Some(())); - let _txid = test_send(&mut wallet_3, online_3, &recipient_map_3); - test_refresh_all(&mut wallet_4, online_4); - assert!(check_test_transfer_status_recipient( - &wallet_4, - &receive_data.recipient_id, - TransferStatus::Failed - )); + let _txid = party_3.send_retry(&recipient_map_3); + party_4.refresh_all(); + assert!( + party_4.check_test_transfer_status_recipient( + &receive_data.recipient_id, + TransferStatus::Failed + ) + ); // send more assets - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map_4 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6263,44 +6022,42 @@ fn test_reject_list_scenario_2() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_1, online_1, &recipient_map_4); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let _txid = party_1.send_retry(&recipient_map_4); + party_3.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_3.wait_for_refresh(None); + party_1.wait_for_refresh(None); // now the previously failed send works since enough allowed allocations - let receive_data = test_blind_receive(&mut wallet_4); // avoid RecipientIDAlreadyUsed + let receive_data = party_4.blind_receive(); // avoid RecipientIDAlreadyUsed recipient_map_3 .entry(asset.asset_id) .and_modify(|r| r[0].recipient_id = receive_data.recipient_id.clone()); - let _txid = test_send(&mut wallet_3, online_3, &recipient_map_3); - wait_for_refresh(&mut wallet_4, online_4, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + let _txid = party_3.send_retry(&recipient_map_3); + party_4.wait_for_refresh(None); + party_3.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_4, online_4, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + party_4.wait_for_refresh(None); + party_3.wait_for_refresh(None); } #[cfg(feature = "electrum")] fn test_reject_list_scenario_3() { - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); let list_name = "reject3.list"; write_opouts_to_reject_list(list_name, &[]); - let asset = test_issue_asset_ifa( - &mut wallet_1, - online_1, + let asset = party_1.issue_asset_ifa( Some(&[100]), Some(&[50]), Some(format!("http://localhost:8140/lists/{list_name}")), ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let amt = 60; let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), @@ -6311,22 +6068,22 @@ fn test_reject_list_scenario_3() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map_1); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let txid = party_1.send_retry(&recipient_map_1); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // add to the reject list the newly received allocation // both in rejected and allowed mode - let opouts = extract_opouts_from_transfer(&wallet_2, &asset.asset_id, &txid); + let opouts = party_2.extract_opouts_from_transfer(&asset.asset_id, &txid); assert_eq!(opouts.len(), 1); let opout_str = opouts[0].to_string(); write_opouts_to_reject_list(list_name, &[opout_str.clone(), format!("!{opout_str}")]); // send the newly received allocation (succeeds because the opout has been allowed) - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map_2 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6336,34 +6093,32 @@ fn test_reject_list_scenario_3() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_2, online_2, &recipient_map_2); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + let _txid = party_2.send_retry(&recipient_map_2); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + party_2.wait_for_refresh(None); + party_3.wait_for_refresh(None); } #[cfg(feature = "electrum")] fn test_reject_list_scenario_4() { - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); - let (mut wallet_4, online_4) = get_funded_wallet!(); - let (mut wallet_5, online_5) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); + let mut party_4 = get_funded_party!(); + let mut party_5 = get_funded_party!(); let list_name = "reject4.list"; write_opouts_to_reject_list(list_name, &[]); - let asset = test_issue_asset_ifa( - &mut wallet_1, - online_1, + let asset = party_1.issue_asset_ifa( Some(&[100]), Some(&[50]), Some(format!("http://localhost:8140/lists/{list_name}")), ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6373,14 +6128,14 @@ fn test_reject_list_scenario_4() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map_1); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let txid_1 = party_1.send_retry(&recipient_map_1); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map_2 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6390,14 +6145,14 @@ fn test_reject_list_scenario_4() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_2, online_2, &recipient_map_2); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + let txid_2 = party_2.send_retry(&recipient_map_2); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_3.wait_for_refresh(None); + party_2.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_4); + let receive_data = party_4.blind_receive(); let recipient_map_3 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6407,18 +6162,18 @@ fn test_reject_list_scenario_4() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_3, online_3, &recipient_map_3); - wait_for_refresh(&mut wallet_4, online_4, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + let _txid = party_3.send_retry(&recipient_map_3); + party_4.wait_for_refresh(None); + party_3.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_4, online_4, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + party_4.wait_for_refresh(None); + party_3.wait_for_refresh(None); // add to the reject list the opout from first the first transfer and // allow the one from the second transfer (child of the first one) - let opouts_1 = extract_opouts_from_transfer(&wallet_2, &asset.asset_id, &txid_1); + let opouts_1 = party_2.extract_opouts_from_transfer(&asset.asset_id, &txid_1); assert_eq!(opouts_1.len(), 1); - let opouts_2 = extract_opouts_from_transfer(&wallet_3, &asset.asset_id, &txid_2); + let opouts_2 = party_3.extract_opouts_from_transfer(&asset.asset_id, &txid_2); assert_eq!(opouts_2.len(), 1); write_opouts_to_reject_list( list_name, @@ -6426,7 +6181,7 @@ fn test_reject_list_scenario_4() { ); // send the newly received allocation (succeeds because the more recent ancestor is allowed) - let receive_data = test_blind_receive(&mut wallet_5); + let receive_data = party_5.blind_receive(); let recipient_map_3 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6436,33 +6191,31 @@ fn test_reject_list_scenario_4() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_4, online_4, &recipient_map_3); - wait_for_refresh(&mut wallet_5, online_5, None, None); - wait_for_refresh(&mut wallet_4, online_4, None, None); + let _txid = party_4.send_retry(&recipient_map_3); + party_5.wait_for_refresh(None); + party_4.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_4, online_4, None, None); - wait_for_refresh(&mut wallet_5, online_5, None, None); + party_4.wait_for_refresh(None); + party_5.wait_for_refresh(None); } #[cfg(feature = "electrum")] fn test_reject_list_scenario_5() { - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); - let (mut wallet_3, online_3) = get_funded_wallet!(); - let (mut wallet_4, online_4) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); + let mut party_3 = get_funded_party!(); + let mut party_4 = get_funded_party!(); let list_name = "reject5.list"; write_opouts_to_reject_list(list_name, &[]); - let asset = test_issue_asset_ifa( - &mut wallet_1, - online_1, + let asset = party_1.issue_asset_ifa( Some(&[150]), Some(&[100]), Some(format!("http://localhost:8140/lists/{list_name}")), ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6472,14 +6225,14 @@ fn test_reject_list_scenario_5() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map_1); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let txid = party_1.send_retry(&recipient_map_1); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); - let receive_data = test_blind_receive(&mut wallet_3); + let receive_data = party_3.blind_receive(); let recipient_map_2 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6489,22 +6242,22 @@ fn test_reject_list_scenario_5() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_1, online_1, &recipient_map_2); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + let _txid = party_1.send_retry(&recipient_map_2); + party_3.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_3.wait_for_refresh(None); + party_1.wait_for_refresh(None); // add to the reject list the allocation of the first transfer (sibling of the one we are about // to spend) - let opouts = extract_opouts_from_transfer(&wallet_2, &asset.asset_id, &txid); + let opouts = party_2.extract_opouts_from_transfer(&asset.asset_id, &txid); assert_eq!(opouts.len(), 1); write_opouts_to_reject_list(list_name, &[opouts[0].to_string()]); // send the newly received allocation (succeeds because the rejected allocation is in the DAG // but not in the opout ancestry chain) - let receive_data = test_blind_receive(&mut wallet_4); + let receive_data = party_4.blind_receive(); let recipient_map_3 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6514,12 +6267,12 @@ fn test_reject_list_scenario_5() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let _txid = test_send(&mut wallet_3, online_3, &recipient_map_3); - wait_for_refresh(&mut wallet_4, online_4, None, None); - wait_for_refresh(&mut wallet_3, online_3, None, None); + let _txid = party_3.send_retry(&recipient_map_3); + party_4.wait_for_refresh(None); + party_3.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_3, online_3, None, None); - wait_for_refresh(&mut wallet_4, online_4, None, None); + party_3.wait_for_refresh(None); + party_4.wait_for_refresh(None); } #[cfg(feature = "electrum")] @@ -6531,16 +6284,17 @@ fn pending_witness_ma1_blind_receive_fail() { let amount: u64 = 66; // sender wallet - let (mut wallet, online) = get_funded_wallet!(); // recipient wallet + let mut party = get_funded_party!(); let mut rcv_wallet = get_test_wallet(true, Some(1)); // MAX_ALLOCATIONS_PER_UTXO = 1 let rcv_online = rcv_wallet.go_online(test_go_online_options(None)).unwrap(); + let mut rcv_party = party!(rcv_wallet, rcv_online); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // send - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6553,9 +6307,10 @@ fn pending_witness_ma1_blind_receive_fail() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let OperationResult { txid, .. } = wallet + let OperationResult { txid, .. } = party + .wallet .send( - online, + party.online, recipient_map.clone(), true, // donation, so TX gets broadcast right away FEE_RATE, @@ -6566,9 +6321,10 @@ fn pending_witness_ma1_blind_receive_fail() { assert!(!txid.is_empty()); // sync recipient wallet (no refresh) to see the new UTXO but not the new allocation - rcv_wallet + rcv_party + .wallet .sync( - rcv_online, + rcv_party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -6577,7 +6333,7 @@ fn pending_witness_ma1_blind_receive_fail() { .unwrap(); // make sure the recipient wallet sees 1 colorable UTXO with no RGB allocations - let unspents = test_list_unspents(&mut rcv_wallet, None, false); + let unspents = rcv_party.list_unspents(false); assert_eq!(unspents.len(), 1); assert!( unspents @@ -6586,7 +6342,7 @@ fn pending_witness_ma1_blind_receive_fail() { ); // try to blind the new UTXO: it should error as it already has the max allocation number - let result = test_blind_receive_result(&mut rcv_wallet); + let result = rcv_party.blind_receive_result(); assert!(matches!(result, Err(Error::InsufficientAllocationSlots))); } @@ -6599,11 +6355,11 @@ fn pending_witness_txo() { let amount: u64 = 66; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // // normal @@ -6611,7 +6367,7 @@ fn pending_witness_txo() { // send let _guard = stop_mining(); - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6624,27 +6380,26 @@ fn pending_witness_txo() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingCounterparty ); // check the recipient doesn't see the TXO yet + has one pending witness script - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txos = txn.iter_txos().unwrap(); + let rcv_txos = rcv_party.db_txos(); assert!(!rcv_txos.iter().any(|t| t.txid == txid)); - let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); - txn.commit().unwrap(); + let rcv_pending_witness_scripts = rcv_party.db_pending_witness_scripts(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // sync recipient wallet - rcv_wallet + rcv_party + .wallet .sync( - rcv_online, + rcv_party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -6653,25 +6408,22 @@ fn pending_witness_txo() { .unwrap(); // check the recipient doesn't see the TXO yet + has one pending witness - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txos = txn.iter_txos().unwrap(); + let rcv_txos = rcv_party.db_txos(); assert!(!rcv_txos.iter().any(|t| t.txid == txid)); - let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); - txn.commit().unwrap(); + let rcv_pending_witness_scripts = rcv_party.db_pending_witness_scripts(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // refresh the recipient to move the transfer to WaitingConfirmations - test_refresh_all(&mut rcv_wallet, rcv_online); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); + rcv_party.refresh_all(); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations ); // check the recipient now sees the TXO yet as inexistent + pending witness - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txos = txn.iter_txos().unwrap(); + let rcv_txos = rcv_party.db_txos(); let rcv_witness_txos: Vec = rcv_txos.into_iter().filter(|t| t.txid == txid).collect(); assert_eq!(rcv_witness_txos.len(), 1); @@ -6684,17 +6436,17 @@ fn pending_witness_txo() { }; // check the recipient still has the pending witness script - let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); - txn.commit().unwrap(); + let rcv_pending_witness_scripts = rcv_party.db_pending_witness_scripts(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // refresh the sender to move the transfer to WaitingConfirmations (broadcast) - test_refresh_all(&mut wallet, online); + party.refresh_all(); // sync recipient wallet - rcv_wallet + rcv_party + .wallet .sync( - rcv_online, + rcv_party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -6703,29 +6455,25 @@ fn pending_witness_txo() { .unwrap(); // check the recipient TXO now exists and is still pending witness - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); + let rcv_txo = rcv_party.db_txo(&rcv_outpoint).unwrap(); assert!(rcv_txo.exists); assert!(rcv_txo.pending_witness); // check the recipient pending witness script has been deleted - let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); - txn.commit().unwrap(); + let rcv_pending_witness_scripts = rcv_party.db_pending_witness_scripts(); assert!(rcv_pending_witness_scripts.is_empty()); // mine + refresh the recipient to move the transfer to Settled drop(_guard); mine(false); - test_refresh_all(&mut rcv_wallet, rcv_online); - test_refresh_all(&mut wallet, online); // so that change is spendable - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); + rcv_party.refresh_all(); + party.refresh_all(); // so that change is spendable + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); // check the recipient TXO still exists and is no more pending witness - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); - txn.commit().unwrap(); + let rcv_txo = rcv_party.db_txo(&rcv_outpoint).unwrap(); assert!(rcv_txo.exists); assert!(!rcv_txo.pending_witness); @@ -6734,11 +6482,11 @@ fn pending_witness_txo() { // // new recipient wallet - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut rcv_party = get_empty_party!(); // send (donation) let _guard = stop_mining(); - let receive_data = test_witness_receive(&mut rcv_wallet); + let receive_data = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6751,9 +6499,10 @@ fn pending_witness_txo() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let OperationResult { txid, .. } = wallet + let OperationResult { txid, .. } = party + .wallet .send( - online, + party.online, recipient_map.clone(), true, FEE_RATE, @@ -6762,25 +6511,24 @@ fn pending_witness_txo() { ) .unwrap(); assert!(!txid.is_empty()); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingCounterparty ); // check the recipient doesn't see the TXO yet + has one pending witness script - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txos = txn.iter_txos().unwrap(); + let rcv_txos = rcv_party.db_txos(); assert!(!rcv_txos.iter().any(|t| t.txid == txid)); - let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); - txn.commit().unwrap(); + let rcv_pending_witness_scripts = rcv_party.db_pending_witness_scripts(); assert_eq!(rcv_pending_witness_scripts.len(), 1); // sync recipient wallet - rcv_wallet + rcv_party + .wallet .sync( - rcv_online, + rcv_party.online, SyncOptions { keychain: SyncKeychain::Colored, strategy: SyncStrategy::FastSync, @@ -6789,10 +6537,8 @@ fn pending_witness_txo() { .unwrap(); // check the recipient now sees the TXO, as existent + pending witness - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txos = txn.iter_txos().unwrap(); - let rcv_witness_txos: Vec = - rcv_txos.into_iter().filter(|t| t.txid == txid).collect(); + let rcv_txos = rcv_party.db_txos(); + let rcv_witness_txos: Vec<_> = rcv_txos.into_iter().filter(|t| t.txid == txid).collect(); assert_eq!(rcv_witness_txos.len(), 1); let rcv_txo = rcv_witness_txos.first().unwrap(); assert!(rcv_txo.exists); @@ -6803,39 +6549,34 @@ fn pending_witness_txo() { }; // check pending witness script has been deleted - let rcv_pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); - txn.commit().unwrap(); + let rcv_pending_witness_scripts = rcv_party.db_pending_witness_scripts(); assert!(rcv_pending_witness_scripts.is_empty()); // refresh to move the transfer to WaitingConfirmations - test_refresh_all(&mut rcv_wallet, rcv_online); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); + rcv_party.refresh_all(); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); assert_eq!( rcv_transfer_data.status, TransferStatus::WaitingConfirmations ); // check the TXO is still existent + pending witness - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); - txn.commit().unwrap(); + let rcv_txo = rcv_party.db_txo(&rcv_outpoint).unwrap(); assert!(rcv_txo.exists); assert!(rcv_txo.pending_witness); // refresh + mine to move the transfer to Settled - test_refresh_all(&mut wallet, online); + party.refresh_all(); drop(_guard); mine(false); - test_refresh_all(&mut rcv_wallet, rcv_online); - let rcv_transfer = get_test_transfer_recipient(&rcv_wallet, &receive_data.recipient_id); - let (rcv_transfer_data, _) = get_test_transfer_data(&rcv_wallet, &rcv_transfer); + rcv_party.refresh_all(); + let rcv_transfer = rcv_party.get_test_transfer_recipient(&receive_data.recipient_id); + let (rcv_transfer_data, _) = rcv_party.get_test_transfer_data(&rcv_transfer); assert_eq!(rcv_transfer_data.status, TransferStatus::Settled); // check the TXO is still existent but not pending witness anymore - let txn = rcv_wallet.database().begin_transaction().unwrap(); - let rcv_txo = txn.get_txo(&rcv_outpoint).unwrap().unwrap(); - txn.commit().unwrap(); + let rcv_txo = rcv_party.db_txo(&rcv_outpoint).unwrap(); assert!(rcv_txo.exists); assert!(!rcv_txo.pending_witness); } @@ -6849,30 +6590,23 @@ fn blinded_change_failed_xfer() { let amount: u64 = 66; // wallets - let (mut wallet_1, online_1) = get_funded_noutxo_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_noutxo_party!(); + let mut party_2 = get_funded_party!(); // create 2 small UTXOs on wallet 1: 1 for issuance, 1 for change - test_create_utxos( - &mut wallet_1, - online_1, - true, - Some(2), - Some(487), - FEE_RATE, - None, - ); + party_1.create_utxos(true, Some(2), Some(487), FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // send 1: 1 > 2 (no broadcast, fail instead) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 1"); + party_1.show_unspent_colorings("wallet 1: pre send 1"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = wallet_2 + let receive_data = party_2 + .wallet .blind_receive( None, Assignment::Any, @@ -6892,28 +6626,20 @@ fn blinded_change_failed_xfer() { )]); // fail transfer on recipient side std::thread::sleep(Duration::from_secs(2)); - assert!( - wallet_2 - .fail_transfers(online_2, Some(1), false, false) - .unwrap() - ); // send - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + assert!(party_2.fail_transfers(Some(1), false, false).unwrap()); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // fail transfer on sender side - assert!( - wallet_1 - .fail_transfers(online_1, Some(2), false, false) - .unwrap() - ); + assert!(party_1.fail_transfers(Some(2), false, false).unwrap()); // send 2: 1 > 2 (complete) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 2"); + party_1.show_unspent_colorings("wallet 1: pre send 2"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6923,33 +6649,25 @@ fn blinded_change_failed_xfer() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // create another small UTXO on wallet 1 for blinded change - test_create_utxos( - &mut wallet_1, - online_1, - false, - Some(1), - Some(487), - FEE_RATE, - None, - ); + party_1.create_utxos(false, Some(1), Some(487), FEE_RATE, None); // send 3: 1 > 2 (spend the change) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 3"); + party_1.show_unspent_colorings("wallet 1: pre send 3"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6959,22 +6677,22 @@ fn blinded_change_failed_xfer() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // send 4: 2 > 1 (spend the received allocation) - show_unspent_colorings(&mut wallet_2, "wallet 2: pre send 4"); + party_2.show_unspent_colorings("wallet 2: pre send 4"); println!( "balance 2: {:?}", - test_get_asset_balance(&wallet_2, &asset.asset_id) + party_2.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_1); + let receive_data = party_1.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -6984,24 +6702,24 @@ fn blinded_change_failed_xfer() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); - show_unspent_colorings(&mut wallet_1, "wallet 1: final"); + party_1.show_unspent_colorings("wallet 1: final"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - show_unspent_colorings(&mut wallet_1, "wallet 2: final"); + party_2.show_unspent_colorings("wallet 2: final"); println!( "balance 2: {:?}", - test_get_asset_balance(&wallet_2, &asset.asset_id) + party_2.get_asset_balance(&asset.asset_id) ); } @@ -7014,30 +6732,23 @@ fn blinded_change_send_begin_only() { let amount: u64 = 66; // wallets - let (mut wallet_1, online_1) = get_funded_noutxo_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_noutxo_party!(); + let mut party_2 = get_funded_party!(); // create 2 small UTXOs on wallet 1: 1 for issuance, 1 for change - test_create_utxos( - &mut wallet_1, - online_1, - true, - Some(2), - Some(487), - FEE_RATE, - None, - ); + party_1.create_utxos(true, Some(2), Some(487), FEE_RATE, None); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // send 1: 1 > 2 (send_begin only) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 1"); + party_1.show_unspent_colorings("wallet 1: pre send 1"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = wallet_2 + let receive_data = party_2 + .wallet .blind_receive( None, Assignment::Any, @@ -7057,28 +6768,24 @@ fn blinded_change_send_begin_only() { )]); // fail transfer on recipient side std::thread::sleep(Duration::from_secs(2)); - assert!( - wallet_2 - .fail_transfers(online_2, Some(1), false, false) - .unwrap() - ); // send (send_begin only) - let result = test_send_begin_result(&mut wallet_1, online_1, &recipient_map).unwrap(); + assert!(party_2.fail_transfers(Some(1), false, false).unwrap()); + let result = party_1.send_begin_result(&recipient_map).unwrap(); assert!(!result.psbt.is_empty()); // fail the initiated transfer to free up UTXOs for the next send assert!( - wallet_1 - .fail_transfers(online_1, result.batch_transfer_idx, false, false) + party_1 + .fail_transfers(result.batch_transfer_idx, false, false) .unwrap() ); // send 2: 1 > 2 (complete) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 2"); + party_1.show_unspent_colorings("wallet 1: pre send 2"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7089,33 +6796,25 @@ fn blinded_change_send_begin_only() { }], )]); // send - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // create another small UTXO on wallet 1 for blinded change - test_create_utxos( - &mut wallet_1, - online_1, - false, - Some(1), - Some(487), - FEE_RATE, - None, - ); + party_1.create_utxos(false, Some(1), Some(487), FEE_RATE, None); // send 3: 1 > 2 (spend the change) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 3"); + party_1.show_unspent_colorings("wallet 1: pre send 3"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7125,22 +6824,22 @@ fn blinded_change_send_begin_only() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // send 4: 2 > 1 (spend the received allocation) - show_unspent_colorings(&mut wallet_2, "wallet 2: pre send 4"); + party_2.show_unspent_colorings("wallet 2: pre send 4"); println!( "balance 2: {:?}", - test_get_asset_balance(&wallet_2, &asset.asset_id) + party_2.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_1); + let receive_data = party_1.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7150,24 +6849,24 @@ fn blinded_change_send_begin_only() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); - show_unspent_colorings(&mut wallet_1, "wallet 1: final"); + party_1.show_unspent_colorings("wallet 1: final"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - show_unspent_colorings(&mut wallet_1, "wallet 2: final"); + party_2.show_unspent_colorings("wallet 2: final"); println!( "balance 2: {:?}", - test_get_asset_balance(&wallet_2, &asset.asset_id) + party_2.get_asset_balance(&asset.asset_id) ); } @@ -7180,19 +6879,20 @@ fn donation_recipient_nack() { let amount: u64 = 10; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // send 1: 1 > 2 (donation, fail from recipient side) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 1"); + party_1.show_unspent_colorings("wallet 1: pre send 1"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = wallet_2 + let receive_data = party_2 + .wallet .blind_receive( None, Assignment::Any, @@ -7212,15 +6912,12 @@ fn donation_recipient_nack() { )]); // fail transfer on recipient side std::thread::sleep(Duration::from_secs(2)); - assert!( - wallet_2 - .fail_transfers(online_2, Some(1), false, false) - .unwrap() - ); // send - let txid = wallet_1 + assert!(party_2.fail_transfers(Some(1), false, false).unwrap()); + let txid = party_1 + .wallet .send( - online_1, + party_1.online, recipient_map, true, FEE_RATE, @@ -7230,37 +6927,30 @@ fn donation_recipient_nack() { .unwrap() .txid; assert!(!txid.is_empty()); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid, - TransferStatus::WaitingConfirmations - )); // manually NACK the transfer + assert!(party_1.check_test_transfer_status_sender(&txid, TransferStatus::WaitingConfirmations)); let proxy_client = get_proxy_client(None); proxy_client .post_ack(&receive_data.recipient_id, false) .unwrap(); // settle on sender side mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid, - TransferStatus::Settled - )); - assert!(check_test_transfer_status_recipient( - &wallet_2, - &receive_data.recipient_id, - TransferStatus::Failed - )); + party_1.wait_for_refresh(None); + assert!(party_1.check_test_transfer_status_sender(&txid, TransferStatus::Settled)); + assert!( + party_2.check_test_transfer_status_recipient( + &receive_data.recipient_id, + TransferStatus::Failed + ) + ); // send 2: 1 > 2 (spend change) - show_unspent_colorings(&mut wallet_1, "wallet 1: pre send 2"); + party_1.show_unspent_colorings("wallet 1: pre send 2"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_2); + let receive_data = party_2.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7270,22 +6960,22 @@ fn donation_recipient_nack() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, None, None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(None); // send 3: 2 > 1 (spend received allocation) - show_unspent_colorings(&mut wallet_2, "wallet 2: pre send 3"); + party_2.show_unspent_colorings("wallet 2: pre send 3"); println!( "balance 2: {:?}", - test_get_asset_balance(&wallet_2, &asset.asset_id) + party_2.get_asset_balance(&asset.asset_id) ); - let receive_data = test_blind_receive(&mut wallet_1); + let receive_data = party_1.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7295,24 +6985,24 @@ fn donation_recipient_nack() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet_1, online_1, None, None); - wait_for_refresh(&mut wallet_2, online_2, None, None); + party_1.wait_for_refresh(None); + party_2.wait_for_refresh(None); - show_unspent_colorings(&mut wallet_1, "wallet 1: final"); + party_1.show_unspent_colorings("wallet 1: final"); println!( "balance 1: {:?}", - test_get_asset_balance(&wallet_1, &asset.asset_id) + party_1.get_asset_balance(&asset.asset_id) ); - show_unspent_colorings(&mut wallet_1, "wallet 2: final"); + party_2.show_unspent_colorings("wallet 2: final"); println!( "balance 2: {:?}", - test_get_asset_balance(&wallet_2, &asset.asset_id) + party_2.get_asset_balance(&asset.asset_id) ); } @@ -7325,14 +7015,14 @@ fn send_end_without_send_begin() { let amount: u64 = 10; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // send begin on wallet 1 to create PSBT - let receive_data = test_blind_receive(&mut wallet_1); + let receive_data = party_1.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7342,16 +7032,16 @@ fn send_end_without_send_begin() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let unsigned_psbt = test_send_begin_result(&mut wallet_1, online_1, &recipient_map).unwrap(); + let unsigned_psbt = party_1.send_begin_result(&recipient_map).unwrap(); - let signed_psbt = wallet_1.sign_psbt(unsigned_psbt.psbt, None).unwrap(); + let signed_psbt = party_1.wallet.sign_psbt(unsigned_psbt.psbt, None).unwrap(); let psbt_txid = Psbt::from_str(&signed_psbt) .unwrap() .extract_tx() .unwrap() .compute_txid() .to_string(); - let result = wallet_2.send_end(online_2, signed_psbt); + let result = party_2.wallet.send_end(party_2.online, signed_psbt); assert_matches!(result, Err(Error::UnknownTransfer { txid }) if txid == psbt_txid); } @@ -7359,11 +7049,13 @@ fn send_end_without_send_begin() { #[test] #[parallel] fn allocations() { - fn get_coloring_map(wallet: &Wallet, unspents: &[Unspent]) -> HashMap> { + fn get_coloring_map( + party: &SinglesigParty, + unspents: &[Unspent], + ) -> HashMap> { let mut coloring_map: HashMap> = HashMap::new(); - let txn = wallet.database().begin_transaction().unwrap(); - let db_txos = txn.iter_txos().unwrap(); - let db_colorings: Vec = txn.iter_colorings().unwrap(); + let db_txos = party.db_txos(); + let db_colorings = party.db_colorings(); for u in unspents { let outpoint = &u.utxo.outpoint; let db_txo = db_txos @@ -7376,21 +7068,18 @@ fn allocations() { .collect(); coloring_map.insert(db_txo.clone(), txo_colorings.into_iter().cloned().collect()); } - txn.commit().unwrap(); coloring_map } fn check_allocations( - wallet: &Wallet, + party: &SinglesigParty, unspents_colorable: &[Unspent], amounts_user: &[u64], amounts_auto: &[u64], pending_xfer: bool, ) { - let coloring_map = get_coloring_map(wallet, unspents_colorable); - let txn = wallet.database().begin_transaction().unwrap(); - let db_asset_transfers = txn.iter_asset_transfers().unwrap(); - txn.commit().unwrap(); + let coloring_map = get_coloring_map(party, unspents_colorable); + let db_asset_transfers = party.db_asset_transfers(); let assignments_auto: Vec<_> = amounts_auto .iter() .map(|a| Assignment::Fungible(*a)) @@ -7540,25 +7229,26 @@ fn allocations() { // wallets // - wallet 1 (standard) - let (mut wallet_1, online_1) = get_funded_wallet!(); // - wallet 2 (1 UTXO, 6 max allocations per UTXO) - let mut wallet_2 = get_test_wallet(true, Some(6)); // using 6 max allocation per UTXO - let online_2 = test_go_online(&mut wallet_2, true, None); - fund_wallet(test_get_address(&mut wallet_2)); - test_create_utxos(&mut wallet_2, online_2, true, Some(1), None, FEE_RATE, None); - // issue (allocations all on the same UTXO) - let asset_1 = test_issue_asset_nia(&mut wallet_1, online_1, None); - let asset_2 = test_issue_asset_cfa(&mut wallet_1, online_1, None, None); - show_unspent_colorings(&mut wallet_1, "wallet 1 after issuance"); + let mut party_1 = get_funded_party!(); + let mut party_2 = offline_party!(get_test_wallet(true, Some(6))); // MAX_ALLOCATIONS_PER_UTXO = 6 + let online_2 = party_2.go_online(true, None); + let mut party_2 = party!(party_2.wallet, online_2); + fund_wallet(party_2.get_address()); + party_2.create_utxos(true, Some(1), None, FEE_RATE, None); + + let asset_1 = party_1.issue_asset_nia(None); + let asset_2 = party_1.issue_asset_cfa(None, None); + party_1.show_unspent_colorings("wallet 1 after issuance"); // send to wallet 2, creating 6 allocations (4x asset 1, 2x asset 2) on the same UTXO - let receive_data_1 = test_blind_receive(&mut wallet_2); - let receive_data_2 = test_blind_receive(&mut wallet_2); - let receive_data_3 = test_blind_receive(&mut wallet_2); - let receive_data_4 = test_blind_receive(&mut wallet_2); - let receive_data_5 = test_blind_receive(&mut wallet_2); - let receive_data_6 = test_blind_receive(&mut wallet_2); + let receive_data_1 = party_2.blind_receive(); + let receive_data_2 = party_2.blind_receive(); + let receive_data_3 = party_2.blind_receive(); + let receive_data_4 = party_2.blind_receive(); + let receive_data_5 = party_2.blind_receive(); + let receive_data_6 = party_2.blind_receive(); let recipient_map = HashMap::from([ ( asset_1.asset_id.clone(), @@ -7607,28 +7297,28 @@ fn allocations() { ], ), ]); - let txid = test_send(&mut wallet_1, online_1, &recipient_map); + let txid = party_1.send_retry(&recipient_map); assert!(!txid.is_empty()); // settle transfers - test_refresh_all(&mut wallet_2, online_2); - test_refresh_all(&mut wallet_1, online_1); + party_2.refresh_all(); + party_1.refresh_all(); mine(false); - test_refresh_all(&mut wallet_2, online_2); - test_refresh_all(&mut wallet_1, online_1); - show_unspent_colorings(&mut wallet_1, "wallet 1 after setup send"); - show_unspent_colorings(&mut wallet_2, "wallet 2 after setup send"); + party_2.refresh_all(); + party_1.refresh_all(); + party_1.show_unspent_colorings("wallet 1 after setup send"); + party_2.show_unspent_colorings("wallet 2 after setup send"); // check received allocation colorings - let unspents_colorable = get_colorable_unspents(&mut wallet_2, Some(online_2), false); + let unspents_colorable = party_2.get_colorable_unspents_with_sync(false); let amounts_all = amounts_user .iter() .chain(amounts_auto.iter()) .copied() .collect::>(); - check_allocations(&wallet_2, &unspents_colorable, &amounts_all, &[], false); + check_allocations(&party_2, &unspents_colorable, &amounts_all, &[], false); // send the 2 smallest allocations from wallet 2 let _guard = stop_mining(); - let receive_data = test_blind_receive(&mut wallet_1); + let receive_data = party_1.blind_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -7638,20 +7328,20 @@ fn allocations() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // check allocation colorings // - main transition allocations have input colorings, user driven // - extra transition allocations have input + change colorings, not user driven - show_unspent_colorings(&mut wallet_2, "wallet 2 after send (WaitingCounterparty)"); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send (WaitingCounterparty)"); - let unspents_colorable = get_colorable_unspents(&mut wallet_2, Some(online_2), false); + party_2.show_unspent_colorings("wallet 2 after send (WaitingCounterparty)"); + party_1.show_unspent_colorings("wallet 1 after send (WaitingCounterparty)"); + let unspents_colorable = party_2.get_colorable_unspents_with_sync(false); print_unspents( &unspents_colorable, "wallet 2 unspents after send (WaitingCounterparty)", ); check_allocations( - &wallet_2, + &party_2, &unspents_colorable, &amounts_user, &amounts_auto, @@ -7661,18 +7351,18 @@ fn allocations() { check_unspents(&unspents_colorable, &amounts_user, &amounts_auto, true); // progress transfer to WaitingConfirmations - test_refresh_all(&mut wallet_1, online_1); - test_refresh_all(&mut wallet_2, online_2); + party_1.refresh_all(); + party_2.refresh_all(); // check allocation colorings (same as in WaitingCounterparty) - show_unspent_colorings(&mut wallet_2, "wallet 2 after send (WaitingConfirmations)"); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send (WaitingConfirmations)"); - let unspents_colorable = get_colorable_unspents(&mut wallet_2, Some(online_2), false); + party_2.show_unspent_colorings("wallet 2 after send (WaitingConfirmations)"); + party_1.show_unspent_colorings("wallet 1 after send (WaitingConfirmations)"); + let unspents_colorable = party_2.get_colorable_unspents_with_sync(false); print_unspents( &unspents_colorable, "wallet 2 unspents after send (WaitingConfirmations)", ); check_allocations( - &wallet_2, + &party_2, &unspents_colorable, &amounts_user, &amounts_auto, @@ -7684,18 +7374,18 @@ fn allocations() { // settle transfer drop(_guard); mine(false); - test_refresh_all(&mut wallet_1, online_1); - test_refresh_all(&mut wallet_2, online_2); + party_1.refresh_all(); + party_2.refresh_all(); // check allocation colorings (no input colorings, same change colorings) - show_unspent_colorings(&mut wallet_2, "wallet 2 after send (Settled)"); - show_unspent_colorings(&mut wallet_1, "wallet 1 after send (Settled)"); - let unspents_colorable = get_colorable_unspents(&mut wallet_2, Some(online_2), false); + party_2.show_unspent_colorings("wallet 2 after send (Settled)"); + party_1.show_unspent_colorings("wallet 1 after send (Settled)"); + let unspents_colorable = party_2.get_colorable_unspents_with_sync(false); print_unspents( &unspents_colorable, "wallet 2 unspents after send (Settled)", ); check_allocations( - &wallet_2, + &party_2, &unspents_colorable, &amounts_user, &amounts_auto, @@ -7705,7 +7395,7 @@ fn allocations() { check_unspents(&unspents_colorable, &amounts_user, &amounts_auto, false); // send half of the smallest remaining allocation from wallet 2 - let receive_data = test_blind_receive(&mut wallet_1); + let receive_data = party_1.blind_receive(); let recipient_map = HashMap::from([( asset_1.asset_id.clone(), vec![Recipient { @@ -7715,31 +7405,23 @@ fn allocations() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet_2, online_2, &recipient_map); + let txid = party_2.send_retry(&recipient_map); assert!(!txid.is_empty()); // check allocation colorings // - main transition allocations have input colorings, user driven // - extra transition allocations have input + change colorings, not user driven - show_unspent_colorings( - &mut wallet_2, - "wallet 2 after 2nd send (WaitingCounterparty)", - ); - show_unspent_colorings( - &mut wallet_1, - "wallet 1 after 2nd send (WaitingCounterparty)", - ); + party_2.show_unspent_colorings("wallet 2 after 2nd send (WaitingCounterparty)"); + party_1.show_unspent_colorings("wallet 1 after 2nd send (WaitingCounterparty)"); let amounts_input = [amount_3, amount_4, amount_5, amount_6]; let amounts_change = [amount_3 / 2, amount_4, amount_5, amount_6]; - let unspents_colorable = get_colorable_unspents(&mut wallet_2, Some(online_2), false); + let unspents_colorable = party_2.get_colorable_unspents_with_sync(false); print_unspents( &unspents_colorable, "wallet 2 unspents after 2nd send (WaitingCounterparty)", ); - let coloring_map = get_coloring_map(&wallet_2, &unspents_colorable); - let txn = wallet_2.database().begin_transaction().unwrap(); - let db_batch_transfers = txn.iter_batch_transfers().unwrap(); - let db_asset_transfers = txn.iter_asset_transfers().unwrap(); - txn.commit().unwrap(); + let coloring_map = get_coloring_map(&party_2, &unspents_colorable); + let db_batch_transfers = party_2.db_batch_transfers(); + let db_asset_transfers = party_2.db_asset_transfers(); // check input colorings let input_colorings: Vec<_> = coloring_map .values() @@ -7845,14 +7527,14 @@ fn p2wpkh_send_receive_nia() { let amount_witness: u64 = 26; let total = amount_blind + amount_witness; - let (mut wallet, online) = get_funded_wallet_p2wpkh(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet_p2wpkh(); + let mut party = get_funded_party_p2wpkh(); + let mut rcv_party = get_funded_party_p2wpkh(); - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // two recipients on the P2WPKH receiver: one blinded, one witness - let receive_blind = test_blind_receive(&mut rcv_wallet); - let receive_witness = test_witness_receive(&mut rcv_wallet); + let receive_blind = rcv_party.blind_receive(); + let receive_witness = rcv_party.witness_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![ @@ -7873,20 +7555,20 @@ fn p2wpkh_send_receive_nia() { }, ], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // drive transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); // settled balance on both sides - let balance_sender = test_get_asset_balance(&wallet, &asset.asset_id); + let balance_sender = party.get_asset_balance(&asset.asset_id); assert_eq!(balance_sender.settled, AMOUNT - total); - let balance_receiver = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + let balance_receiver = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!(balance_receiver.settled, total); } @@ -7900,13 +7582,13 @@ fn cross_type_p2tr_to_p2wpkh() { let amount: u64 = 66; let amount_back: u64 = 10; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, rcv_online) = get_funded_wallet_p2wpkh(); + let mut party = get_funded_party!(); + let mut rcv_party = get_funded_party_p2wpkh(); - let asset = test_issue_asset_nia(&mut wallet, online, None); + let asset = party.issue_asset_nia(None); // P2TR → P2WPKH - let receive_data = test_blind_receive(&mut rcv_wallet); + let receive_data = rcv_party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7916,23 +7598,23 @@ fn cross_type_p2tr_to_p2wpkh() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid = test_send(&mut wallet, online, &recipient_map); + let txid = party.send_retry(&recipient_map); assert!(!txid.is_empty()); // drive transfers from WaitingCounterparty to Settled - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); mine(false); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); - wait_for_refresh(&mut wallet, online, Some(&asset.asset_id), None); + rcv_party.wait_for_refresh(None); + party.wait_for_refresh(Some(&asset.asset_id)); - let balance_sender = test_get_asset_balance(&wallet, &asset.asset_id); + let balance_sender = party.get_asset_balance(&asset.asset_id); assert_eq!(balance_sender.settled, AMOUNT - amount); - let balance_receiver = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + let balance_receiver = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!(balance_receiver.settled, amount); // P2WPKH → P2TR (send some back to complete the roundtrip) - let receive_back = test_blind_receive(&mut wallet); + let receive_back = party.blind_receive(); let recipient_map_back = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7942,18 +7624,18 @@ fn cross_type_p2tr_to_p2wpkh() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_back = test_send(&mut rcv_wallet, rcv_online, &recipient_map_back); + let txid_back = rcv_party.send_retry(&recipient_map_back); assert!(!txid_back.is_empty()); - wait_for_refresh(&mut wallet, online, None, None); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); + party.wait_for_refresh(None); + rcv_party.wait_for_refresh(None); mine(false); - wait_for_refresh(&mut wallet, online, None, None); - wait_for_refresh(&mut rcv_wallet, rcv_online, None, None); + party.wait_for_refresh(None); + rcv_party.wait_for_refresh(None); - let balance_sender = test_get_asset_balance(&wallet, &asset.asset_id); + let balance_sender = party.get_asset_balance(&asset.asset_id); assert_eq!(balance_sender.settled, AMOUNT - amount + amount_back); - let balance_receiver = test_get_asset_balance(&rcv_wallet, &asset.asset_id); + let balance_receiver = rcv_party.get_asset_balance(&asset.asset_id); assert_eq!(balance_receiver.settled, amount - amount_back); } @@ -7967,14 +7649,14 @@ fn unsafe_history_waits_for_safe_height() { let amount_2: u64 = 33; // wallets - let (mut wallet_1, online_1) = get_funded_wallet!(); - let (mut wallet_2, online_2) = get_funded_wallet!(); + let mut party_1 = get_funded_party!(); + let mut party_2 = get_funded_party!(); // issue - let asset = test_issue_asset_nia(&mut wallet_1, online_1, None); + let asset = party_1.issue_asset_nia(None); // 1st transfer: wallet 1 > wallet 2 - let receive_data_1 = test_blind_receive(&mut wallet_2); + let receive_data_1 = party_2.blind_receive(); let recipient_map_1 = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -7984,28 +7666,24 @@ fn unsafe_history_waits_for_safe_height() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_1 = test_send(&mut wallet_1, online_1, &recipient_map_1); + let txid_1 = party_1.send_retry(&recipient_map_1); assert!(!txid_1.is_empty()); let _guard = stop_mining_when_alone(); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); force_mine_no_resume_when_alone(false); - wait_for_refresh(&mut wallet_2, online_2, None, None); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_2.wait_for_refresh(None); + party_1.wait_for_refresh(Some(&asset.asset_id)); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_1.recipient_id, TransferStatus::Settled )); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_1, - TransferStatus::Settled - )); + assert!(party_1.check_test_transfer_status_sender(&txid_1, TransferStatus::Settled)); // 2nd transfer: wallet 1 > wallet 2 with min_confirmations = 2 // txid_1 has only one confirmation, so transfer parks in WaitingSafeHeight - let receive_data_2 = wallet_2 + let receive_data_2 = party_2 + .wallet .blind_receive( None, Assignment::Any, @@ -8023,69 +7701,44 @@ fn unsafe_history_waits_for_safe_height() { transport_endpoints: TRANSPORT_ENDPOINTS.clone(), }], )]); - let txid_2 = test_send(&mut wallet_1, online_1, &recipient_map_2); + let txid_2 = party_1.send_retry(&recipient_map_2); assert!(!txid_2.is_empty()); // transfer parks in WaitingSafeHeight because it contains unsafe history - wait_for_refresh( - &mut wallet_2, - online_2, - None, - Some(&[receive_data_2.batch_transfer_idx]), - ); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_2.wait_for_refresh_raw(None, Some(&[receive_data_2.batch_transfer_idx])); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingSafeHeight )); // mine another block so txid_1 reaches 2 confirmations, then refresh to ACK force_mine_no_resume_when_alone(false); - wait_for_refresh( - &mut wallet_2, - online_2, - None, - Some(&[receive_data_2.batch_transfer_idx]), - ); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_2.wait_for_refresh_raw(None, Some(&[receive_data_2.batch_transfer_idx])); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingConfirmations )); // sender sees the ACK and broadcasts txid_2 - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_2, - TransferStatus::WaitingConfirmations - )); + party_1.wait_for_refresh(Some(&asset.asset_id)); + assert!( + party_1.check_test_transfer_status_sender(&txid_2, TransferStatus::WaitingConfirmations) + ); // mine, sender (min_confirmations = 1) settles, recipient (min_confirmations = 2) still in WaitingConfirmations force_mine_no_resume_when_alone(false); - wait_for_refresh(&mut wallet_1, online_1, Some(&asset.asset_id), None); - assert!(check_test_transfer_status_sender( - &wallet_1, - &txid_2, - TransferStatus::Settled - )); - assert!(!test_refresh_all(&mut wallet_2, online_2)); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_1.wait_for_refresh(Some(&asset.asset_id)); + assert!(party_1.check_test_transfer_status_sender(&txid_2, TransferStatus::Settled)); + assert!(!party_2.refresh_all()); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::WaitingConfirmations )); // mine again so txid_2 reaches 2 confirmations, recipient settles force_mine_no_resume_when_alone(false); - wait_for_refresh( - &mut wallet_2, - online_2, - None, - Some(&[receive_data_2.batch_transfer_idx]), - ); - assert!(check_test_transfer_status_recipient( - &wallet_2, + party_2.wait_for_refresh_raw(None, Some(&[receive_data_2.batch_transfer_idx])); + assert!(party_2.check_test_transfer_status_recipient( &receive_data_2.recipient_id, TransferStatus::Settled )); @@ -8097,9 +7750,9 @@ fn unsafe_history_waits_for_safe_height() { fn begin_end() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let asset = test_issue_asset_nia(&mut wallet, online, None); - let receive_data = test_blind_receive(&mut wallet); + let mut party = get_funded_party!(); + let asset = party.issue_asset_nia(None); + let receive_data = party.blind_receive(); let recipient_map = HashMap::from([( asset.asset_id.clone(), vec![Recipient { @@ -8111,12 +7764,11 @@ fn begin_end() { )]); // begin does not update backup_info with dry_run=true - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let _res = wallet + let bak_info_before = party.db_backup_info(); + let _res = party + .wallet .send_begin( - online, + party.online, recipient_map.clone(), false, FEE_RATE, @@ -8125,21 +7777,18 @@ fn begin_end() { true, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_after.last_operation_timestamp, bak_info_before.last_operation_timestamp ); // begin does update backup_info with dry_run=false - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let res = wallet + let bak_info_before = party.db_backup_info(); + let res = party + .wallet .send_begin( - online, + party.online, recipient_map, false, FEE_RATE, @@ -8148,20 +7797,14 @@ fn begin_end() { false, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let signed_psbt = wallet.sign_psbt(res.psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(res.psbt, None).unwrap(); // end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.send_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party.wallet.send_end(party.online, signed_psbt).unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); } diff --git a/src/wallet/test/send_btc.rs b/src/wallet/test/send_btc.rs index 6ba24b99..3d665979 100644 --- a/src/wallet/test/send_btc.rs +++ b/src/wallet/test/send_btc.rs @@ -9,12 +9,12 @@ fn success() { let amount: u64 = 1000; // wallets - let (mut wallet, online) = get_empty_wallet!(); - let (mut rcv_wallet, rcv_online) = get_empty_wallet!(); + let mut party = get_empty_party!(); + let mut rcv_party = get_empty_party!(); // initial balance - fund_wallet(test_get_address(&mut wallet)); - test_create_utxos_default(&mut wallet, online); + fund_wallet(party.get_address()); + party.create_utxos_default(); mine(false); let expected_balance = BtcBalance { vanilla: Balance { @@ -28,21 +28,12 @@ fn success() { spendable: 5000, }, }; - assert_eq!(test_get_btc_balance(&mut wallet, online), expected_balance); + assert_eq!(party.get_btc_balance_with_sync(), expected_balance); // balance after send - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let txid = test_send_btc( - &mut wallet, - online, - &test_get_address(&mut rcv_wallet), - amount, - ); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + let txid = party.send_btc(&rcv_party.get_address(), amount); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(!txid.is_empty()); mine(false); @@ -58,7 +49,7 @@ fn success() { spendable: 5000, }, }; - assert_eq!(test_get_btc_balance(&mut wallet, online), expected_balance); + assert_eq!(party.get_btc_balance_with_sync(), expected_balance); let expected_balance = BtcBalance { vanilla: Balance { settled: 1000, @@ -71,10 +62,7 @@ fn success() { spendable: 0, }, }; - assert_eq!( - test_get_btc_balance(&mut rcv_wallet, rcv_online), - expected_balance - ); + assert_eq!(rcv_party.get_btc_balance_with_sync(), expected_balance); } #[cfg(feature = "electrum")] @@ -86,43 +74,36 @@ fn fail() { let amount: u64 = 1000; // wallets - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); - let mut testnet_rcv_wallet = get_test_wallet_with_net( + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); + let mut testnet_rcv_party = offline_party!(get_test_wallet_with_net( true, Some(MAX_ALLOCATIONS_PER_UTXO), BitcoinNetwork::Testnet, - ); + )); // bad online let wrong_online = Online { id: 1 }; - let result = test_send_btc_result( - &mut wallet, - wrong_online, - &test_get_address(&mut rcv_wallet), - amount, - ); + let good_online = party.online; + party.online = wrong_online; + let result = party.send_btc_result(&rcv_party.get_address(), amount); + party.online = good_online; assert!(matches!(result, Err(Error::CannotChangeOnline))); // invalid address - let result = test_send_btc_result(&mut wallet, online, "invalid", amount); + let result = party.send_btc_result("invalid", amount); assert!(matches!(result, Err(Error::InvalidAddress { details: _ }))); - let result = test_send_btc_result( - &mut wallet, - online, - &test_get_address(&mut testnet_rcv_wallet), - amount, - ); + let result = party.send_btc_result(&testnet_rcv_party.get_address(), amount); assert!(matches!(result, Err(Error::InvalidAddress { details: _ }))); // invalid amount - let result = test_send_btc_result(&mut wallet, online, &test_get_address(&mut rcv_wallet), 0); + let result = party.send_btc_result(&rcv_party.get_address(), 0); assert!(matches!(result, Err(Error::OutputBelowDustLimit))); // invalid fee rate (low) - let result = wallet.send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + let result = party.wallet.send_btc_begin( + party.online, + rcv_party.get_address(), amount, 0, false, @@ -131,9 +112,9 @@ fn fail() { assert!(matches!(result, Err(Error::InvalidFeeRate { details: m }) if m == FEE_MSG_LOW)); // invalid fee rate (overflow) - let result = wallet.send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + let result = party.wallet.send_btc_begin( + party.online, + rcv_party.get_address(), amount, u64::MAX, false, @@ -151,19 +132,20 @@ fn skip_sync() { let amount: u64 = 1000; // wallets - let (mut wallet, online) = get_empty_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_empty_party!(); + let mut rcv_party = get_empty_party!(); // prepare 1 UTXO - fund_wallet(test_get_address(&mut wallet)); - let unspents = test_list_unspents(&mut wallet, Some(online), false); + fund_wallet(party.get_address()); + let unspents = party.list_unspents_with_sync(false); assert_eq!(unspents.len(), 1); // send a 1st time skipping sync (spending the only UTXO) - let txid_1 = wallet + let txid_1 = party + .wallet .send_btc( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), amount, FEE_RATE, true, @@ -172,10 +154,11 @@ fn skip_sync() { assert!(!txid_1.is_empty()); // send a 2nd time skipping sync > succeeds because the change UTXO from send 1 // is staged into BDK by broadcast_psbt's apply_unconfirmed_txs - let txid_2 = wallet + let txid_2 = party + .wallet .send_btc( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), amount, FEE_RATE, true, @@ -193,29 +176,28 @@ fn begin_reservation_interactions() { let amount: u64 = 1000; - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // no reservations and no SendBtc wallet_transactions initially - let txn = wallet.database().begin_transaction().unwrap(); - assert!(txn.iter_reserved_txos().unwrap().is_empty()); + assert!(party.db_reserved_txos().is_empty()); assert!( - txn.iter_wallet_transactions() - .unwrap() + party + .db_wallet_transactions() .iter() .all(|wt| wt.r#type != WalletTransactionType::SendBtc) ); - txn.commit().unwrap(); // capture vanilla spendable balance before reservation - let balance_before = test_get_btc_balance(&mut wallet, online); + let balance_before = party.get_btc_balance_with_sync(); assert!(balance_before.vanilla.spendable > 0); // begin with dry_run=false reserves the selected inputs - let unsigned_psbt_str = wallet + let unsigned_psbt_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), amount, FEE_RATE, false, @@ -227,16 +209,13 @@ fn begin_reservation_interactions() { assert_eq!(unsigned_psbt.unsigned_tx.input.len(), 1); // vanilla spendable balance reflects the reservation - let balance_reserved = test_get_btc_balance(&mut wallet, online); + let balance_reserved = party.get_btc_balance_with_sync(); assert!(balance_reserved.vanilla.spendable < balance_before.vanilla.spendable); // wallet_transaction(SendBtc) row for this txid exists - let txn = wallet.database().begin_transaction().unwrap(); - let (wt, reservations) = txn - .get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) - .unwrap() + let (wt, reservations) = party + .db_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) .expect("should exist after begin"); - txn.commit().unwrap(); assert_eq!(wt.r#type, WalletTransactionType::SendBtc); // one reserved_txo per PSBT input, all pointing to that wt row assert!(reservations.iter().all(|r| r.reserved_for == Some(wt.idx))); @@ -254,37 +233,35 @@ fn begin_reservation_interactions() { assert_eq!(reserved_set, input_set); // list_pending_vanilla_txs reports the in-flight reservation - let pending = wallet.list_pending_vanilla_txs().unwrap(); + let pending = party.wallet.list_pending_vanilla_txs().unwrap(); assert_eq!(pending.len(), 1); assert_eq!(pending[0].txid, psbt_txid); assert_eq!(pending[0].r#type, WalletTransactionType::SendBtc); // sign + end releases the reservations but keeps the wallet_transaction row - let signed_psbt = wallet.sign_psbt(unsigned_psbt_str, None).unwrap(); - let _end_txid = wallet.send_btc_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - assert!(txn.iter_reserved_txos().unwrap().is_empty()); - txn.commit().unwrap(); - assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt_str, None).unwrap(); + let _end_txid = party + .wallet + .send_btc_end(party.online, signed_psbt) + .unwrap(); + assert!(party.db_reserved_txos().is_empty()); + assert!(party.wallet.list_pending_vanilla_txs().unwrap().is_empty()); // after end, balance is no longer reduced by reservations (the UTXO is now spent, // and the change output is the new spendable balance) - let balance_after_end = test_get_btc_balance(&mut wallet, online); + let balance_after_end = party.get_btc_balance_with_sync(); assert!(balance_after_end.vanilla.spendable > balance_reserved.vanilla.spendable); // the wallet_transaction row is still there (so list_transactions classifies the tx) - let txn = wallet.database().begin_transaction().unwrap(); - let wts: Vec<_> = txn - .iter_wallet_transactions() - .unwrap() + let wts: Vec<_> = party + .db_wallet_transactions() .into_iter() .filter(|wt| wt.txid == psbt_txid && wt.r#type == WalletTransactionType::SendBtc) .collect(); - txn.commit().unwrap(); assert_eq!(wts.len(), 1); // list_transactions sees it as SendBtc mine(false); - let transactions = test_list_transactions(&mut wallet, Some(online)); + let transactions = party.list_transactions_with_sync(); let entry = transactions .iter() .find(|t| t.txid == psbt_txid) @@ -292,10 +269,11 @@ fn begin_reservation_interactions() { assert!(matches!(entry.transaction_type, TransactionType::SendBtc)); // dry_run=true begin does not create reservations/wallet_transaction row up-front - let unsigned_psbt_str = wallet + let unsigned_psbt_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), amount, FEE_RATE, false, @@ -306,29 +284,27 @@ fn begin_reservation_interactions() { let psbt_txid = unsigned_psbt.unsigned_tx.compute_txid().to_string(); // no reservations, no wallet_transaction row yet - let txn = wallet.database().begin_transaction().unwrap(); - assert!(txn.iter_reserved_txos().unwrap().is_empty()); + assert!(party.db_reserved_txos().is_empty()); assert!( - txn.get_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) - .unwrap() + party + .db_wallet_transaction_with_reserved_txos_by_txid(&psbt_txid) .is_none() ); - txn.commit().unwrap(); - assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); + assert!(party.wallet.list_pending_vanilla_txs().unwrap().is_empty()); // end still creates the SendBtc row after broadcast (for list_transactions) - let signed_psbt = wallet.sign_psbt(unsigned_psbt_str, None).unwrap(); - let end_txid = wallet.send_btc_end(online, signed_psbt).unwrap(); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt_str, None).unwrap(); + let end_txid = party + .wallet + .send_btc_end(party.online, signed_psbt) + .unwrap(); assert_eq!(end_txid, psbt_txid); - let txn = wallet.database().begin_transaction().unwrap(); - assert!(txn.iter_reserved_txos().unwrap().is_empty()); - let wts: Vec<_> = txn - .iter_wallet_transactions() - .unwrap() + assert!(party.db_reserved_txos().is_empty()); + let wts: Vec<_> = party + .db_wallet_transactions() .into_iter() .filter(|wt| wt.txid == psbt_txid && wt.r#type == WalletTransactionType::SendBtc) .collect(); - txn.commit().unwrap(); assert_eq!(wts.len(), 1); } @@ -341,13 +317,14 @@ fn two_concurrent_begins_pick_disjoint_inputs() { let amount: u64 = 1000; // wallet with several separate vanilla UTXOs to choose from - let (mut wallet, online) = get_empty_wallet!(); + let mut party = get_empty_party!(); for _ in 0..3 { - fund_wallet(test_get_address(&mut wallet)); + fund_wallet(party.get_address()); } - wallet + party + .wallet .sync( - online, + party.online, SyncOptions { keychain: SyncKeychain::Vanilla { lookback: INDEXER_SYNC_LOOKBACK as u32, @@ -357,12 +334,13 @@ fn two_concurrent_begins_pick_disjoint_inputs() { ) .unwrap(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut rcv_party = get_empty_party!(); - let psbt_1_str = wallet + let psbt_1_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), amount, FEE_RATE, true, @@ -377,10 +355,11 @@ fn two_concurrent_begins_pick_disjoint_inputs() { .map(|i| (i.previous_output.txid.to_string(), i.previous_output.vout)) .collect(); - let psbt_2_str = wallet + let psbt_2_str = party + .wallet .send_btc_begin( - online, - test_get_address(&mut rcv_wallet), + party.online, + rcv_party.get_address(), amount, FEE_RATE, true, @@ -400,7 +379,7 @@ fn two_concurrent_begins_pick_disjoint_inputs() { assert!(inputs_1.is_disjoint(&inputs_2)); // both reservations are live - let pending = wallet.list_pending_vanilla_txs().unwrap(); + let pending = party.wallet.list_pending_vanilla_txs().unwrap(); assert_eq!(pending.len(), 2); } @@ -410,17 +389,12 @@ fn two_concurrent_begins_pick_disjoint_inputs() { fn full_send_btc_leaves_no_pending() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let (mut rcv_wallet, _rcv_online) = get_empty_wallet!(); + let mut party = get_funded_party!(); + let mut rcv_party = get_empty_party!(); // a full send_btc (which uses dry_run=true internally) leaves no pending entry - let _ = test_send_btc( - &mut wallet, - online, - &test_get_address(&mut rcv_wallet), - 1000, - ); - assert!(wallet.list_pending_vanilla_txs().unwrap().is_empty()); + let _ = party.send_btc(&rcv_party.get_address(), 1000); + assert!(party.wallet.list_pending_vanilla_txs().unwrap().is_empty()); } #[cfg(feature = "electrum")] @@ -430,18 +404,25 @@ fn send_btc_end_twice() { initialize(); // wallet - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // prepare PSBT - let address = test_get_address(&mut wallet); - let unsigned_psbt = wallet - .send_btc_begin(online, address, 1000, FEE_RATE, false, false) + let address = party.get_address(); + let unsigned_psbt = party + .wallet + .send_btc_begin(party.online, address, 1000, FEE_RATE, false, false) .unwrap(); - let signed_psbt = wallet.sign_psbt(unsigned_psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(unsigned_psbt, None).unwrap(); // call send_btc_end twice with the same PSBT, which should work (idempotent) - wallet.send_btc_end(online, signed_psbt.clone()).unwrap(); - wallet.send_btc_end(online, signed_psbt).unwrap(); + party + .wallet + .send_btc_end(party.online, signed_psbt.clone()) + .unwrap(); + party + .wallet + .send_btc_end(party.online, signed_psbt) + .unwrap(); } #[cfg(feature = "electrum")] @@ -450,45 +431,38 @@ fn send_btc_end_twice() { fn begin_end() { initialize(); - let (mut wallet, online) = get_funded_noutxo_wallet!(); - let address = test_get_address(&mut wallet); + let mut party = get_funded_noutxo_party!(); + let address = party.get_address(); // begin does not update backup_info with dry_run=true - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let _psbt = wallet - .send_btc_begin(online, address.clone(), 1000, FEE_RATE, false, true) + let bak_info_before = party.db_backup_info(); + let _psbt = party + .wallet + .send_btc_begin(party.online, address.clone(), 1000, FEE_RATE, false, true) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert_eq!( bak_info_before.last_operation_timestamp, bak_info_after.last_operation_timestamp ); // begin does update backup_info with dry_run=false - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let psbt = wallet - .send_btc_begin(online, address, 1000, FEE_RATE, false, false) + let bak_info_before = party.db_backup_info(); + let psbt = party + .wallet + .send_btc_begin(party.online, address, 1000, FEE_RATE, false, false) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); - let signed_psbt = wallet.sign_psbt(psbt, None).unwrap(); + let signed_psbt = party.wallet.sign_psbt(psbt, None).unwrap(); // end updates backup_info - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - wallet.send_btc_end(online, signed_psbt).unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_before = party.db_backup_info(); + party + .wallet + .send_btc_end(party.online, signed_psbt) + .unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); } diff --git a/src/wallet/test/sign_psbt.rs b/src/wallet/test/sign_psbt.rs index 04c87b29..e5bc0c6b 100644 --- a/src/wallet/test/sign_psbt.rs +++ b/src/wallet/test/sign_psbt.rs @@ -5,20 +5,25 @@ use super::*; #[parallel] fn success() { initialize(); - let (mut wallet, online) = get_funded_wallet!(); - let address = test_get_address(&mut wallet); + let mut party = get_funded_party!(); + let address = party.get_address(); - let unsigned_psbt_str = wallet - .send_btc_begin(online, address, AMOUNT, FEE_RATE, false, true) + let unsigned_psbt_str = party + .wallet + .send_btc_begin(party.online, address, AMOUNT, FEE_RATE, false, true) .unwrap(); // no SignOptions - let signed_psbt = wallet.sign_psbt(unsigned_psbt_str.clone(), None).unwrap(); + let signed_psbt = party + .wallet + .sign_psbt(unsigned_psbt_str.clone(), None) + .unwrap(); assert!(Psbt::from_str(&signed_psbt).is_ok()); // with SignOptions let opts = SignOptions::default(); - let signed_psbt = wallet + let signed_psbt = party + .wallet .sign_psbt(unsigned_psbt_str.clone(), Some(opts)) .unwrap(); assert!(Psbt::from_str(&signed_psbt).is_ok()); diff --git a/src/wallet/test/sync.rs b/src/wallet/test/sync.rs index ea952a5b..f41d29aa 100644 --- a/src/wallet/test/sync.rs +++ b/src/wallet/test/sync.rs @@ -12,11 +12,14 @@ fn fail() { }; // wallets - let (mut wallet, _online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // sync input params // - check online is correct let wrong_online = Online { id: 1 }; - let result = test_sync_result(&mut wallet, wrong_online, sync_options); + let good_online = party.online; + party.online = wrong_online; + let result = party.sync_result(sync_options); + party.online = good_online; assert!(matches!(result, Err(Error::CannotChangeOnline))); } diff --git a/src/wallet/test/utils/api.rs b/src/wallet/test/utils/api.rs index b05e8d83..f52f842d 100644 --- a/src/wallet/test/utils/api.rs +++ b/src/wallet/test/utils/api.rs @@ -1,699 +1,1474 @@ use super::*; -pub(crate) fn test_blind_receive(wallet: &mut Wallet) -> ReceiveData { - test_blind_receive_result(wallet).unwrap() +// singlesig party without an online handle (for offline-only test APIs) +pub(crate) struct OfflineSinglesigParty { + pub(crate) wallet: Wallet, } -pub(crate) fn test_blind_receive_result(wallet: &mut Wallet) -> Result { - wallet.blind_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + DURATION_RCV_TRANSFER as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) +// singlesig party (allows uniform access to some functionality via SigParty trait) +pub(crate) struct SinglesigParty { + pub(crate) wallet: Wallet, + pub(crate) online: Online, } -pub(crate) fn test_witness_receive(wallet: &mut Wallet) -> ReceiveData { - wallet - .witness_receive( - None, - Assignment::Any, - Some((now().unix_timestamp() + DURATION_RCV_TRANSFER as i64) as u64), - TRANSPORT_ENDPOINTS.clone(), - MIN_CONFIRMATIONS, - ) - .unwrap() +// convenience macro to instantiate OfflineSinglesigParty +macro_rules! offline_party { + ($wallet:expr) => { + OfflineSinglesigParty { wallet: $wallet } + }; } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_burn( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - amount: u64, -) -> OperationResult { - test_burn_result(wallet, online, asset_id, amount).unwrap() +// convenience macro to instantiate SinglesigParty +macro_rules! party { + ($wallet:expr, $online:expr) => { + SinglesigParty { + wallet: $wallet, + online: $online, + } + }; } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_burn_result( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - amount: u64, -) -> Result { - wallet.burn( - online, - asset_id.to_string(), - amount, - FEE_RATE, - MIN_CONFIRMATIONS, - ) -} +// convenience trait to allow uniform access to offline functionality from all parties +pub(crate) trait OfflineSigParty { + type W: RgbWalletOpsOffline; -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_burn_begin( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - amount: u64, -) -> String { - test_burn_begin_result(wallet, online, asset_id, amount) - .unwrap() - .psbt -} + fn wlt(&self) -> &Self::W; -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_burn_begin_result( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - amount: u64, -) -> Result { - wallet.burn_begin( - online, - asset_id.to_string(), - amount, - FEE_RATE, - MIN_CONFIRMATIONS, - true, - ) -} + fn wlt_mut(&mut self) -> &mut Self::W; -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_burn_end_result( - wallet: &mut Wallet, - online: Online, - signed_psbt: &str, -) -> Result { - wallet.burn_end(online, signed_psbt.to_string()) -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn check_test_transfer_status_recipient( + &self, + recipient_id: &str, + expected_status: TransferStatus, + ) -> bool { + let transfers = self.db_transfers(); + let mut recipient_transfers = transfers + .iter() + .filter(|t| t.recipient_id.as_deref() == Some(recipient_id)); + let transfer = recipient_transfers.next().unwrap(); + assert!(recipient_transfers.next().is_none()); + let db_data = self.db_data(false); + let (asset_transfer, batch_transfer) = + transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers); + let transfer_data = self + .wlt() + .get_transfer_data( + transfer, + &asset_transfer, + &batch_transfer, + &db_data.txos, + &db_data.colorings, + ) + .unwrap(); + println!( + "receive with recipient_id {} is in status {:?}", + recipient_id, &transfer_data.status + ); + transfer_data.status == expected_status + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_create_utxos_default(wallet: &mut Wallet, online: Online) { - test_create_utxos(wallet, online, false, None, None, FEE_RATE, None); -} + fn check_test_transfer_status_sender( + &self, + txid: &str, + expected_status: TransferStatus, + ) -> bool { + let batch_transfers: Vec<_> = self + .db_batch_transfers() + .into_iter() + .filter(|b| b.txid == Some(txid.to_string())) + .collect(); + assert_eq!(batch_transfers.len(), 1); + let batch_transfer = batch_transfers.first().unwrap(); + println!( + "send with txid {} is in status {:?}", + txid, &batch_transfer.status + ); + batch_transfer.status == expected_status + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_create_utxos( - wallet: &mut Wallet, - online: Online, - up_to: bool, - num: Option, - size: Option, - fee_rate: u64, - expected: Option, -) { - let unspents = test_list_unspents(wallet, Some(online), false); - let colorable_before = unspents.iter().filter(|u| u.utxo.colorable).count(); - let expected = expected.unwrap_or(num.unwrap_or(UTXO_NUM)); - let _ = test_create_utxos_nowait(wallet, online, up_to, num, size, fee_rate); - let check = || { - let unspents = test_list_unspents(wallet, Some(online), false); - let colorable = unspents.iter().filter(|u| u.utxo.colorable).count(); - if (colorable - colorable_before) == expected as usize { - return true; - } - false - }; - if !wait_for_function(check, 10, 500) { - panic!( - "created utxo number ({}) didn't match the expected one ({expected})", - num.unwrap_or(UTXO_NUM) + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn check_test_wallet_data( + &mut self, + asset: &AssetNIA, + custom_issued_supply: Option, + transfer_num: usize, + spent_amount: u64, + ) { + println!("checking wallet data..."); + let issued_supply = match custom_issued_supply { + Some(supply) => supply, + None => AMOUNT, + }; + // asset list + let assets = self.list_assets(&[]); + let nia_assets = assets.nia.unwrap(); + let cfa_assets = assets.cfa.unwrap(); + assert_eq!(nia_assets.len(), 1); + assert_eq!(cfa_assets.len(), 0); + let nia_asset = nia_assets.first().unwrap(); + assert_eq!(nia_asset.asset_id, asset.asset_id); + // asset balance + let balance = self.get_asset_balance(&asset.asset_id); + assert_eq!( + balance, + Balance { + settled: asset.balance.settled - spent_amount, + future: asset.balance.future - spent_amount, + spendable: asset.balance.spendable - spent_amount, + } ); + // asset metadata + let metadata = self.get_asset_metadata(&asset.asset_id); + assert_eq!(metadata.asset_schema, AssetSchema::Nia); + assert_eq!(metadata.initial_supply, issued_supply); + assert_eq!(metadata.name, asset.name); + assert_eq!(metadata.precision, asset.precision); + assert_eq!(metadata.ticker.unwrap(), asset.ticker); + // transfer list + let transfers = self.list_transfers(Some(&asset.asset_id)); + assert_eq!(transfers.len(), 1 + transfer_num); + assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance); + assert_eq!(transfers.last().unwrap().kind, TransferKind::Send); + assert_eq!(transfers.last().unwrap().status, TransferStatus::Settled); + // unspent list + let unspents = self.list_unspents(false); + assert_eq!(unspents.len(), 6); } -} -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_create_utxos_nowait( - wallet: &mut Wallet, - online: Online, - up_to: bool, - num: Option, - size: Option, - fee_rate: u64, -) -> u8 { - wallet - .create_utxos(online, up_to, num, size, fee_rate, false) - .unwrap() -} + fn data_dir(&self) -> String { + self.wlt().get_wallet_data().data_dir + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_create_utxos_begin_result( - wallet: &mut Wallet, - online: Online, - up_to: bool, - num: Option, - size: Option, - fee_rate: u64, -) -> Result { - wallet.create_utxos_begin(online, up_to, num, size, fee_rate, false, true) -} + fn db_asset(&self, asset_id: &str) -> DbAsset { + let txn = self.wlt().database().begin_transaction().unwrap(); + let asset = txn.get_asset(asset_id.to_string()).unwrap().unwrap(); + txn.commit().unwrap(); + asset + } -pub(crate) fn test_delete_transfers( - wallet: &Wallet, - batch_transfer_idx: Option, - no_asset_only: bool, -) -> bool { - test_delete_transfers_result(wallet, batch_transfer_idx, no_asset_only).unwrap() -} + fn db_asset_transfers(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let asset_transfers = txn.iter_asset_transfers().unwrap(); + txn.commit().unwrap(); + asset_transfers + } -pub(crate) fn test_delete_transfers_result( - wallet: &Wallet, - batch_transfer_idx: Option, - no_asset_only: bool, -) -> Result { - wallet.delete_transfers(batch_transfer_idx, no_asset_only) -} + fn db_asset_transfers_filtered(&self, batch_transfer_idx: i32) -> Vec { + self.db_asset_transfers() + .into_iter() + .filter(|at| at.batch_transfer_idx == batch_transfer_idx) + .collect() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_drain_to_result( - wallet: &mut Wallet, - online: Online, - address: &str, -) -> Result { - wallet.drain_to(online, address.to_string(), FEE_RATE) -} + fn db_backup_info(&self) -> DbBackupInfo { + let txn = self.wlt().database().begin_transaction().unwrap(); + let bak_info = txn.get_backup_info().unwrap().unwrap(); + txn.commit().unwrap(); + bak_info + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_drain_to_begin_result( - wallet: &mut Wallet, - online: Online, - address: &str, - fee_rate: u64, -) -> Result { - wallet.drain_to_begin(online, address.to_string(), fee_rate, true) -} + fn db_backup_info_opt(&self) -> Option { + let txn = self.wlt().database().begin_transaction().unwrap(); + let bak_info = txn.get_backup_info().unwrap(); + txn.commit().unwrap(); + bak_info + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_drain_to(wallet: &mut Wallet, online: Online, address: &str) -> String { - wallet - .drain_to(online, address.to_string(), FEE_RATE) - .unwrap() -} + fn db_batch_transfers(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let batch_transfers = txn.iter_batch_transfers().unwrap(); + txn.commit().unwrap(); + batch_transfers + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_fail_transfers_all(wallet: &mut Wallet, online: Online) -> bool { - wallet.fail_transfers(online, None, false, false).unwrap() -} + fn db_batch_transfers_filtered(&self, txid: &str) -> Vec { + self.db_batch_transfers() + .into_iter() + .filter(|b| b.txid == Some(txid.to_string())) + .collect() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_fail_transfers_single( - wallet: &mut Wallet, - online: Online, - batch_transfer_idx: i32, -) -> bool { - wallet - .fail_transfers(online, Some(batch_transfer_idx), false, false) - .unwrap() -} + fn db_check_asset_exists(&self, asset_id: &str) -> Result { + let txn = self.wlt().database().begin_transaction().unwrap(); + let res = txn.check_asset_exists(asset_id.to_string()); + txn.commit().unwrap(); + res + } -pub(crate) fn test_get_address(wallet: &mut Wallet) -> String { - wallet.get_address().unwrap() -} + fn db_colorings(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let colorings = txn.iter_colorings().unwrap(); + txn.commit().unwrap(); + colorings + } -pub(crate) fn test_get_asset_balance(wallet: &impl RgbWalletOpsOffline, asset_id: &str) -> Balance { - test_get_asset_balance_result(wallet, asset_id).unwrap() -} + fn db_colorings_filtered(&self, asset_transfer_idx: i32) -> Vec { + self.db_colorings() + .into_iter() + .filter(|c| c.asset_transfer_idx == asset_transfer_idx) + .collect() + } -pub(crate) fn test_get_asset_balance_result( - wallet: &impl RgbWalletOpsOffline, - asset_id: &str, -) -> Result { - wallet.get_asset_balance(asset_id.to_string()) -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn db_data(&self, empty_transfers: bool) -> DbData { + let txn = self.wlt().database().begin_transaction().unwrap(); + let db_data = txn.get_db_data(empty_transfers).unwrap(); + txn.commit().unwrap(); + db_data + } -pub(crate) fn test_get_asset_metadata(wallet: &Wallet, asset_id: &str) -> Metadata { - test_get_asset_metadata_result(wallet, asset_id).unwrap() -} + fn db_del_transfer_transport_endpoint(&self, idx: i32) { + let txn = self.wlt().database().begin_transaction().unwrap(); + txn.del_transfer_transport_endpoint(idx).unwrap(); + txn.commit().unwrap(); + } -pub(crate) fn test_get_asset_metadata_result( - wallet: &Wallet, - asset_id: &str, -) -> Result { - wallet.get_asset_metadata(asset_id.to_string()) -} + fn db_get_or_insert_media(&self, digest: &str, mime: &str) -> i32 { + let txn = self.wlt().database().begin_transaction().unwrap(); + let media_idx = txn + .get_or_insert_media(digest.to_string(), mime.to_string()) + .unwrap(); + txn.commit().unwrap(); + media_idx + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_get_btc_balance(wallet: &mut Wallet, online: Online) -> BtcBalance { - wallet.get_btc_balance(Some(online), false).unwrap() -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn db_media(&self, media_idx: i32) -> DbMedia { + let txn = self.wlt().database().begin_transaction().unwrap(); + let media = txn.get_media(media_idx).unwrap().unwrap(); + txn.commit().unwrap(); + media + } -pub(crate) fn test_get_wallet_data(wallet: &Wallet) -> WalletData { - wallet.get_wallet_data() -} + fn db_medias(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let medias = txn.iter_media().unwrap(); + txn.commit().unwrap(); + medias + } -pub(crate) fn test_get_wallet_dir(wallet: &impl RgbWalletOpsOffline) -> PathBuf { - wallet.get_wallet_dir() -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn db_pending_witness_scripts(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let pending_witness_scripts = txn.iter_pending_witness_scripts().unwrap(); + txn.commit().unwrap(); + pending_witness_scripts + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_go_online_options(indexer_url: Option<&str>) -> OnlineOptions { - OnlineOptions { - indexer_url: indexer_url.unwrap_or(ELECTRUM_URL).to_string(), - skip_consistency_check: true, - vanilla_sync_lookback: INDEXER_SYNC_LOOKBACK as u32, + fn db_reserved_txos(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let reserved_txos = txn.iter_reserved_txos().unwrap(); + txn.commit().unwrap(); + reserved_txos } -} -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_go_online( - wallet: &mut Wallet, - skip_consistency_check: bool, - indexer_url: Option<&str>, -) -> Online { - test_go_online_result(wallet, skip_consistency_check, indexer_url).unwrap() -} + fn db_rgb_allocations( + &self, + utxos: Vec, + colorings: Option>, + batch_transfers: Option>, + asset_transfers: Option>, + transfers: Option>, + ) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let rgb_allocations = txn + .get_rgb_allocations( + utxos, + colorings, + batch_transfers, + asset_transfers, + transfers, + ) + .unwrap(); + txn.commit().unwrap(); + rgb_allocations + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_go_online_result( - wallet: &mut Wallet, - skip_consistency_check: bool, - indexer_url: Option<&str>, -) -> Result { - let mut online_options = test_go_online_options(indexer_url); - online_options.skip_consistency_check = skip_consistency_check; - wallet.go_online(online_options) -} + fn db_token_medias(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let token_medias = txn.iter_token_medias().unwrap(); + txn.commit().unwrap(); + token_medias + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_inflate( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - inflation_amounts: &[u64], -) -> OperationResult { - test_inflate_result(wallet, online, asset_id, inflation_amounts).unwrap() -} + fn db_tokens(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let tokens = txn.iter_tokens().unwrap(); + txn.commit().unwrap(); + tokens + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_inflate_result( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - inflation_amounts: &[u64], -) -> Result { - wallet.inflate( - online, - asset_id.to_string(), - inflation_amounts.to_vec(), - FEE_RATE, - MIN_CONFIRMATIONS, - ) -} + fn db_transfer_transport_endpoints_data( + &self, + idx: i32, + ) -> Vec<(DbTransferTransportEndpoint, DbTransportEndpoint)> { + let txn = self.wlt().database().begin_transaction().unwrap(); + let tte_data = txn.get_transfer_transport_endpoints_data(idx).unwrap(); + txn.commit().unwrap(); + tte_data + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_inflate_begin( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - inflation_amounts: &[u64], -) -> String { - test_inflate_begin_result(wallet, online, asset_id, inflation_amounts) - .unwrap() - .psbt -} + fn db_transfers(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let transfers = txn.iter_transfers().unwrap(); + txn.commit().unwrap(); + transfers + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_inflate_begin_result( - wallet: &mut Wallet, - online: Online, - asset_id: &str, - inflation_amounts: &[u64], -) -> Result { - wallet.inflate_begin( - online, - asset_id.to_string(), - inflation_amounts.to_vec(), - FEE_RATE, - MIN_CONFIRMATIONS, - true, - ) -} + fn db_transfers_filtered(&self, asset_transfer_idx: i32) -> Vec { + self.db_transfers() + .into_iter() + .filter(|t| t.asset_transfer_idx == asset_transfer_idx) + .collect() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_inflate_end_result( - wallet: &mut Wallet, - online: Online, - signed_psbt: &str, -) -> Result { - wallet.inflate_end(online, signed_psbt.to_string()) -} + fn db_txo(&self, outpoint: &Outpoint) -> Option { + let txn = self.wlt().database().begin_transaction().unwrap(); + let txo = txn.get_txo(outpoint).unwrap(); + txn.commit().unwrap(); + txo + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_uda( - wallet: &mut Wallet, - online: Online, - details: Option<&str>, - media_file_path: Option<&str>, - attachments_file_paths: Vec<&str>, -) -> AssetUDA { - test_issue_asset_uda_result( - wallet, - online, - details, - media_file_path, - attachments_file_paths, - ) - .unwrap() -} + fn db_txos(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let txos = txn.iter_txos().unwrap(); + txn.commit().unwrap(); + txos + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_uda_result( - wallet: &mut Wallet, - online: Online, - details: Option<&str>, - media_file_path: Option<&str>, - attachments_file_paths: Vec<&str>, -) -> Result { - test_fail_transfers_all(wallet, online); - wallet.issue_asset_uda( - TICKER.to_string(), - NAME.to_string(), - details.map(|d| d.to_string()), - PRECISION, - media_file_path.map(|m| m.to_string()), - attachments_file_paths + fn db_unspent_txos(&self, txos: Vec) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let unspent_txos = txn.get_unspent_txos(txos).unwrap(); + txn.commit().unwrap(); + unspent_txos + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn db_update_asset(&self, asset: &mut DbAssetActMod) -> DbAsset { + let txn = self.wlt().database().begin_transaction().unwrap(); + let asset = txn.update_asset(asset).unwrap(); + txn.commit().unwrap(); + asset + } + + fn db_wallet_transaction_with_reserved_txos_by_txid( + &self, + txid: &str, + ) -> Option<(DbWalletTransaction, Vec)> { + let txn = self.wlt().database().begin_transaction().unwrap(); + let res = txn + .get_wallet_transaction_with_reserved_txos_by_txid(txid) + .unwrap(); + txn.commit().unwrap(); + res + } + + fn db_wallet_transactions(&self) -> Vec { + let txn = self.wlt().database().begin_transaction().unwrap(); + let transactions = txn.iter_wallet_transactions().unwrap(); + txn.commit().unwrap(); + transactions + } + + fn delete_transfers(&mut self, batch_transfer_idx: Option, no_asset_only: bool) -> bool { + self.delete_transfers_result(batch_transfer_idx, no_asset_only) + .unwrap() + } + + fn delete_transfers_result( + &self, + batch_transfer_idx: Option, + no_asset_only: bool, + ) -> Result { + self.wlt() + .delete_transfers(batch_transfer_idx, no_asset_only) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn extract_opouts_from_transfer(&self, asset_id: &str, txid: &str) -> Vec { + let batch_transfers = self.db_batch_transfers_filtered(txid); + assert_eq!(batch_transfers.len(), 1); + let batch_transfer = batch_transfers.first().unwrap(); + let asset_transfers = self.db_asset_transfers_filtered(batch_transfer.idx); + let asset_transfers = asset_transfers .iter() - .map(|a| a.to_string()) - .collect(), - ) -} + .filter(|at| at.asset_id.as_ref() == Some(&asset_id.to_string())) + .filter(|t| t.user_driven) + .collect::>(); + assert_eq!(asset_transfers.len(), 1); + let asset_transfer = asset_transfers.first().unwrap(); + let colorings: Vec = self + .db_colorings() + .into_iter() + .filter(|c| c.asset_transfer_idx == asset_transfer.idx) + .collect(); + if colorings.is_empty() { + panic!("cannot find colorings for this transfer"); + } + let txo_indices = colorings.iter().map(|c| c.txo_idx).collect::>(); + let relevant_txos = self + .db_txos() + .into_iter() + .filter(|t| txo_indices.contains(&t.idx)); + let mut outpoints = relevant_txos + .map(|txo| OutPoint::from(txo.clone())) + .peekable(); + if outpoints.peek().is_none() { + panic!("cannot find outpoints for this transfer"); + } + let contract_id = ContractId::from_str(asset_id).unwrap(); + let runtime = self.wlt().rgb_runtime().unwrap(); + let assignments = runtime + .contract_assignments_for(contract_id, outpoints) + .unwrap(); + let mut opouts = Vec::new(); + for (_explicit_seal, opout_state_map) in assignments { + for (opout, _state) in opout_state_map { + opouts.push(opout); + } + } + opouts + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_cfa( - wallet: &mut Wallet, - online: Online, - amounts: Option<&[u64]>, - file_path: Option, -) -> AssetCFA { - test_issue_asset_cfa_result(wallet, online, amounts, file_path).unwrap() -} + fn get_asset_balance(&self, asset_id: &str) -> Balance { + self.get_asset_balance_result(asset_id).unwrap() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_cfa_result( - wallet: &mut Wallet, - online: Online, - amounts: Option<&[u64]>, - file_path: Option, -) -> Result { - test_fail_transfers_all(wallet, online); - let amounts = if let Some(a) = amounts { - a.to_vec() - } else { - vec![AMOUNT] - }; - wallet.issue_asset_cfa( - NAME.to_string(), - Some(DETAILS.to_string()), - PRECISION, - amounts, - file_path, - ) -} + fn get_asset_balance_result(&self, asset_id: &str) -> Result { + self.wlt().get_asset_balance(asset_id.to_string()) + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_nia( - wallet: &mut Wallet, - online: Online, - amounts: Option<&[u64]>, -) -> AssetNIA { - test_issue_asset_nia_result(wallet, online, amounts).unwrap() -} + fn get_asset_metadata(&self, asset_id: &str) -> Metadata { + self.get_asset_metadata_result(asset_id).unwrap() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_nia_result( - wallet: &mut Wallet, - online: Online, - amounts: Option<&[u64]>, -) -> Result { - test_fail_transfers_all(wallet, online); - let amounts = if let Some(a) = amounts { - a.to_vec() - } else { - vec![AMOUNT] - }; - wallet.issue_asset_nia(TICKER.to_string(), NAME.to_string(), PRECISION, amounts) -} + fn get_asset_metadata_result(&self, asset_id: &str) -> Result { + self.wlt().get_asset_metadata(asset_id.to_string()) + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_ifa( - wallet: &mut Wallet, - online: Online, - amounts: Option<&[u64]>, - inflation_amounts: Option<&[u64]>, - reject_list_url: Option, -) -> AssetIFA { - test_issue_asset_ifa_result(wallet, online, amounts, inflation_amounts, reject_list_url) - .unwrap() -} + fn get_btc_balance(&mut self) -> BtcBalance { + self.wlt_mut().get_btc_balance(None, true).unwrap() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_issue_asset_ifa_result( - wallet: &mut Wallet, - online: Online, - amounts: Option<&[u64]>, - inflation_amounts: Option<&[u64]>, - reject_list_url: Option, -) -> Result { - test_fail_transfers_all(wallet, online); - let amounts = if let Some(a) = amounts { - a.to_vec() - } else { - vec![AMOUNT] - }; - let inflation_amounts = if let Some(a) = inflation_amounts { - a.to_vec() - } else { - vec![AMOUNT_INFLATION] - }; - wallet.issue_asset_ifa( - TICKER.to_string(), - NAME.to_string(), - PRECISION, - amounts, - inflation_amounts, - reject_list_url, - ) -} + fn get_pending_blind_transfers(&self) -> Vec { + self.wlt() + .list_transfers(None) + .unwrap() + .into_iter() + .filter(|t| t.status.pending() && t.kind == TransferKind::ReceiveBlind) + .collect() + } -pub(crate) fn test_list_assets(wallet: &Wallet, filter_asset_schemas: &[AssetSchema]) -> Assets { - wallet.list_assets(filter_asset_schemas.to_vec()).unwrap() -} + fn get_test_asset_transfer(&self, batch_transfer_idx: i32) -> DbAssetTransfer { + let asset_transfers = self.db_asset_transfers_filtered(batch_transfer_idx); + let mut user_driven_transfers = asset_transfers.into_iter().filter(|t| t.user_driven); + let user_driven_transfer = user_driven_transfers.next().unwrap(); + assert!(user_driven_transfers.next().is_none()); + user_driven_transfer + } -pub(crate) fn test_list_transactions( - wallet: &mut impl RgbWalletOpsOffline, - online: Option, -) -> Vec { - let skip_sync = online.is_none(); - wallet.list_transactions(online, skip_sync).unwrap() -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn get_test_transfer_data(&self, transfer: &DbTransfer) -> (TransferData, DbAssetTransfer) { + let db_data = self.db_data(false); + let (asset_transfer, batch_transfer) = + transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers); + let transfer_data = self + .wlt() + .get_transfer_data( + transfer, + &asset_transfer, + &batch_transfer, + &db_data.txos, + &db_data.colorings, + ) + .unwrap(); + (transfer_data, asset_transfer) + } -pub(crate) fn test_list_transfers( - wallet: &impl RgbWalletOpsOffline, - asset_id: Option<&str>, -) -> Vec { - test_list_transfers_result(wallet, asset_id).unwrap() -} + fn get_test_transfer_recipient(&self, recipient_id: &str) -> DbTransfer { + let mut transfers = self + .db_transfers() + .into_iter() + .filter(|t| t.recipient_id == Some(recipient_id.to_string()) && t.incoming); + let transfer = transfers.next().unwrap(); + assert!(transfers.next().is_none()); + transfer + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn get_test_transfer_related( + &self, + transfer: &DbTransfer, + ) -> (DbAssetTransfer, DbBatchTransfer) { + let db_data = self.db_data(false); + transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) + } + + fn get_test_transfer_sender( + &self, + txid: &str, + ) -> (DbTransfer, DbAssetTransfer, DbBatchTransfer) { + let batch_transfers = self.db_batch_transfers_filtered(txid); + assert_eq!(batch_transfers.len(), 1); + let batch_transfer = batch_transfers.into_iter().next().unwrap(); + let asset_transfer = self.get_test_asset_transfer(batch_transfer.idx); + let mut transfers = self.db_transfers_filtered(asset_transfer.idx).into_iter(); + let transfer = transfers.next().unwrap(); + assert!(transfers.next().is_none()); + (transfer, asset_transfer, batch_transfer) + } + + fn get_test_transfers_sender( + &self, + txid: &str, + ) -> ( + HashMap>, + Vec, + DbBatchTransfer, + ) { + let batch_transfers = self.db_batch_transfers_filtered(txid); + assert_eq!(batch_transfers.len(), 1); + let batch_transfer = batch_transfers.into_iter().next().unwrap(); + let asset_transfers = self.db_asset_transfers_filtered(batch_transfer.idx); + let mut transfers: HashMap> = HashMap::new(); + for asset_transfer in &asset_transfers { + let asset_id = asset_transfer.asset_id.clone().unwrap(); + transfers.insert(asset_id, self.db_transfers_filtered(asset_transfer.idx)); + } + (transfers, asset_transfers, batch_transfer) + } + + fn get_wallet_data(&self) -> WalletData { + self.wlt().get_wallet_data() + } + + fn list_assets(&self, filter_asset_schemas: &[AssetSchema]) -> Assets { + self.wlt() + .list_assets(filter_asset_schemas.to_vec()) + .unwrap() + } + + fn list_transactions(&mut self) -> Vec { + self.wlt_mut().list_transactions(None, true).unwrap() + } -pub(crate) fn test_list_transfers_result( - wallet: &impl RgbWalletOpsOffline, - asset_id: Option<&str>, -) -> Result, Error> { - let asset_id = asset_id.map(|a| a.to_string()); - wallet.list_transfers(asset_id) + fn list_transfers(&self, asset_id: Option<&str>) -> Vec { + self.list_transfers_result(asset_id).unwrap() + } + + fn list_transfers_result(&self, asset_id: Option<&str>) -> Result, Error> { + self.wlt().list_transfers(asset_id.map(|a| a.to_string())) + } + + fn list_unspents(&mut self, settled_only: bool) -> Vec { + self.wlt_mut() + .list_unspents(None, settled_only, true) + .unwrap() + } + + /// print the provided message, then get colorings for each wallet unspent and print their + /// status, type, amount and asset + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn show_unspent_colorings(&mut self, msg: &str) { + println!( + "\nwallet {} unspent colorings ({msg})", + self.wlt().get_wallet_data().data_dir + ); + let unspents = self + .wlt_mut() + .list_unspents(None, false, true) + .unwrap() + .into_iter() + .filter(|u| u.utxo.colorable); + let db_txos = self.db_txos(); + let db_colorings = self.db_colorings(); + let db_asset_transfers = self.db_asset_transfers(); + let db_batch_transfers = self.db_batch_transfers(); + let pending_blind_transfers = self.get_pending_blind_transfers(); + for unspent in unspents { + let outpoint = unspent.utxo.outpoint; + let db_txo = db_txos + .iter() + .find(|t| t.txid == outpoint.txid && t.vout == outpoint.vout) + .unwrap(); + let txo_pending_blind_transfers = pending_blind_transfers.iter().filter(|t| { + if let Some(txo) = &t.receive_utxo { + db_txo.outpoint() == *txo + } else { + false + } + }); + println!( + "> {}:{}, {} sat{}", + outpoint.txid, + outpoint.vout, + unspent.utxo.btc_amount, + if !unspent.utxo.exists { + " - tx not broadcast yet" + } else { + "" + }, + ); + let txo_db_colorings = db_colorings.iter().filter(|c| c.txo_idx == db_txo.idx); + for db_coloring in txo_db_colorings { + let db_asset_transfer = db_asset_transfers + .iter() + .find(|a| a.idx == db_coloring.asset_transfer_idx) + .unwrap(); + let db_batch_transfer = db_batch_transfers + .iter() + .find(|b| b.idx == db_asset_transfer.batch_transfer_idx) + .unwrap(); + println!( + "\t- {:?} {:?} of {:?} for {:?}", + db_batch_transfer.status, + db_coloring.r#type, + db_coloring.assignment, + db_asset_transfer.asset_id.as_ref(), + ); + } + for pbt in txo_pending_blind_transfers { + println!("\t- pending blind receive with transfer ID {}", pbt.idx); + } + } + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn wait_for_asset_balance(&self, asset_id: &str, expected_balance: &Balance) { + println!("waiting for asset balance"); + let mut current_balance = Balance::default(); + let check = || { + current_balance = self.get_asset_balance(asset_id); + if ¤t_balance == expected_balance { + return true; + } + false + }; + if !wait_for_function(check, 10, 500) { + println!("current balance: {current_balance:?}"); + println!("expected balance: {expected_balance:?}"); + panic!("asset balance is not becoming the expected one"); + } + } } +// convenience trait to allow uniform access to online functionality from all parties #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_list_unspents( - wallet: &mut impl RgbWalletOpsOnline, - online: Option, - settled_only: bool, -) -> Vec { - let skip_sync = online.is_none(); - wallet - .list_unspents(online, settled_only, skip_sync) - .unwrap() +pub(crate) trait SigParty: OfflineSigParty { + fn party_online(&self) -> Online; + + fn fail_transfers( + &mut self, + batch_transfer_idx: Option, + no_asset_only: bool, + skip_sync: bool, + ) -> Result { + let online = self.party_online(); + self.wlt_mut() + .fail_transfers(online, batch_transfer_idx, no_asset_only, skip_sync) + } + + fn fail_transfers_all(&mut self) -> bool { + let online = self.party_online(); + self.wlt_mut() + .fail_transfers(online, None, false, false) + .unwrap() + } + + fn fail_transfers_single(&mut self, batch_transfer_idx: i32) -> bool { + let online = self.party_online(); + self.wlt_mut() + .fail_transfers(online, Some(batch_transfer_idx), false, false) + .unwrap() + } + + fn get_btc_balance_with_sync(&mut self) -> BtcBalance { + let online = self.party_online(); + self.wlt_mut().get_btc_balance(Some(online), false).unwrap() + } + + fn get_colorable_unspents_with_sync(&mut self, settled_only: bool) -> Vec { + self.list_unspents_with_sync(settled_only) + .into_iter() + .filter(|u| u.utxo.colorable) + .collect() + } + + fn list_transactions_with_sync(&mut self) -> Vec { + let online = self.party_online(); + self.wlt_mut() + .list_transactions(Some(online), false) + .unwrap() + } + + fn list_unspents_with_sync(&mut self, settled_only: bool) -> Vec { + let online = self.party_online(); + self.wlt_mut() + .list_unspents(Some(online), settled_only, false) + .unwrap() + } + + fn wait_for_refresh(&mut self, asset_id: Option<&str>) { + self.wait_for_refresh_raw(asset_id, None); + } + + fn refresh_result( + &mut self, + asset_id: Option<&str>, + filter: &[RefreshFilter], + ) -> Result { + let online = self.party_online(); + self.wlt_mut().refresh( + online, + asset_id.map(|a| a.to_string()), + filter.to_vec(), + false, + ) + } + + fn sync(&mut self, options: SyncOptions) { + self.sync_result(options).unwrap() + } + + fn sync_result(&mut self, options: SyncOptions) -> Result<(), Error> { + let online = self.party_online(); + self.wlt_mut().sync(online, options) + } + + fn wait_for_btc_balance(&mut self, expected_balance: &BtcBalance) { + println!("waiting for BTC balance"); + let mut current_balance = BtcBalance::default(); + let check = || { + current_balance = self.get_btc_balance_with_sync(); + if ¤t_balance == expected_balance { + return true; + } + false + }; + if !wait_for_function(check, 10, 500) { + println!("current balance: {current_balance:?}"); + println!("expected balance: {expected_balance:?}"); + panic!("BTC balance is not becoming the expected one"); + } + } + + fn wait_for_refresh_raw(&mut self, asset_id: Option<&str>, transfer_ids: Option<&[i32]>) { + println!( + "waiting for refresh ({})", + self.wlt().get_wallet_data().data_dir + ); + let mut seen = HashSet::new(); + let mut target_set = HashSet::new(); + if let Some(t_ids) = transfer_ids { + assert!(!t_ids.is_empty()); + target_set = t_ids.iter().copied().collect(); + } + let check = || { + let result = self.refresh_result(asset_id, &[]); + if let Ok(refresh_res) = result { + let mut non_fatal_error = false; + refresh_res.iter().for_each(|(i, rt)| { + if let Some(ref e) = rt.failure { + eprintln!("refresh of {i} failure: {e} ({e:?})"); + match e { + Error::Internal { details } => { + println!("refresh of {i} internal error: {e}, details: {details}"); + non_fatal_error = true; + } + Error::InvalidTxid => { + println!("refresh of {i} invalid TXID: {e}"); + non_fatal_error = true; + } + Error::Network { details } => { + println!("refresh of {i} network error: {e}, details: {details}"); + non_fatal_error = true; + } + _ => panic!("refresh of {i} fatal error: {e}"), + } + } + }); + if non_fatal_error { + return false; + } + if transfer_ids.is_some() { + for (id, rt) in refresh_res { + if rt.updated_status.is_some() && target_set.contains(&id) { + seen.insert(id); + } + } + if seen == target_set { + return true; + } + } else if refresh_res.transfers_changed() { + return true; + } + } else { + eprintln!("refresh error: {result:?}"); + return false; + }; + false + }; + if !wait_for_function(check, 10, 500) { + panic!("transfer(s) are not refreshing"); + } + } + + fn wait_for_unspents(&mut self, settled_only: bool, expected_len: u8) { + println!("waiting for unspents"); + let mut unspents = vec![]; + let check = || { + unspents = self.list_unspents_with_sync(settled_only); + unspents.len() == expected_len as usize + }; + if !wait_for_function(check, 10, 500) { + panic!( + "UTXO num {} is not becoming the expected {expected_len}", + unspents.len() + ); + } + } } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_list_unspents_vanilla( - wallet: &mut Wallet, - online: Online, - min_confirmations: Option, -) -> Vec { - let min_confirmations = min_confirmations.unwrap_or(MIN_CONFIRMATIONS); - wallet - .list_unspents_vanilla(online, min_confirmations, false) - .unwrap() +// shared singlesig-party test helpers that call inherent Wallet methods +// (which OfflineSigParty's RgbWalletOpsOffline bound can't reach) +pub(crate) trait SinglesigWalletParty { + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn abort_pending_vanilla_tx(&self, txid: &str); + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn abort_pending_vanilla_tx_result(&self, txid: &str) -> Result<(), Error>; + + fn blind_receive(&mut self) -> ReceiveData; + + fn blind_receive_asset_expiry( + &mut self, + asset_id: Option, + expiration: Option, + ) -> ReceiveData; + + fn blind_receive_result(&mut self) -> Result; + + fn blind_receive_with_endpoints( + &mut self, + expiration: Option, + transport_endpoints: Vec, + ) -> ReceiveData; + + fn get_address(&mut self) -> String; + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn go_online(&mut self, skip_consistency_check: bool, indexer_url: Option<&str>) -> Online; + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn go_online_result( + &mut self, + skip_consistency_check: bool, + indexer_url: Option<&str>, + ) -> Result; + + fn issue_asset_cfa(&mut self, amounts: Option<&[u64]>, file_path: Option) -> AssetCFA; + + fn issue_asset_cfa_result( + &mut self, + amounts: Option<&[u64]>, + file_path: Option, + ) -> Result; + + fn issue_asset_ifa( + &mut self, + amounts: Option<&[u64]>, + inflation_amounts: Option<&[u64]>, + reject_list_url: Option, + ) -> AssetIFA; + + fn issue_asset_ifa_result( + &mut self, + amounts: Option<&[u64]>, + inflation_amounts: Option<&[u64]>, + reject_list_url: Option, + ) -> Result; + + fn issue_asset_nia(&mut self, amounts: Option<&[u64]>) -> AssetNIA; + + fn issue_asset_nia_result(&mut self, amounts: Option<&[u64]>) -> Result; + + fn issue_asset_uda( + &mut self, + details: Option<&str>, + media_file_path: Option<&str>, + attachments_file_paths: Vec<&str>, + ) -> AssetUDA; + + fn issue_asset_uda_result( + &mut self, + details: Option<&str>, + media_file_path: Option<&str>, + attachments_file_paths: Vec<&str>, + ) -> Result; + + fn witness_receive(&mut self) -> ReceiveData; } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_refresh_all(wallet: &mut Wallet, online: Online) -> bool { - test_refresh_result(wallet, online, None, &[]) - .unwrap() - .transfers_changed() +impl OfflineSigParty for OfflineSinglesigParty { + type W = Wallet; + + fn wlt(&self) -> &Wallet { + &self.wallet + } + + fn wlt_mut(&mut self) -> &mut Wallet { + &mut self.wallet + } } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_refresh_asset(wallet: &mut Wallet, online: Online, asset_id: &str) -> bool { - test_refresh_result(wallet, online, Some(asset_id), &[]) - .unwrap() - .transfers_changed() +impl OfflineSigParty for SinglesigParty { + type W = Wallet; + + fn wlt(&self) -> &Wallet { + &self.wallet + } + + fn wlt_mut(&mut self) -> &mut Wallet { + &mut self.wallet + } } #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_refresh_result( - wallet: &mut impl RgbWalletOpsOnline, - online: Online, - asset_id: Option<&str>, - filter: &[RefreshFilter], -) -> Result { - wallet.refresh( - online, - asset_id.map(|a| a.to_string()), - filter.to_vec(), - false, - ) +impl SigParty for SinglesigParty { + fn party_online(&self) -> Online { + self.online + } } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_save_new_asset( - wallet: &mut Wallet, - online: Online, - rcv_wallet: &mut Wallet, - asset_id: &String, - assignment: Assignment, -) { - let receive_data = test_witness_receive(rcv_wallet); - let recipient_map = HashMap::from([( - asset_id.to_owned(), - vec![Recipient { - assignment, - recipient_id: receive_data.recipient_id.clone(), - witness_data: Some(WitnessData { - amount_sat: 1000, - blinding: None, - }), - transport_endpoints: TRANSPORT_ENDPOINTS.clone(), - }], - )]); - let txid = test_send(wallet, online, &recipient_map); - assert!(!txid.is_empty()); - - let consignment_path = wallet.get_send_consignment_path(asset_id, &txid); - let consignment = RgbTransfer::load_file(consignment_path).unwrap(); - - let contract = consignment.clone().into_contract(); - let asset_schema: AssetSchema = consignment.schema_id().try_into().unwrap(); - let validation_config = ValidationConfig { - chain_net: rcv_wallet.chain_net(), - trusted_typesystem: asset_schema.types(), - ..Default::default() - }; - let mut runtime = rcv_wallet.rgb_runtime().unwrap(); - let valid_contract = contract - .clone() - .validate(&DumbResolver, &validation_config) - .unwrap(); - runtime - .import_contract(valid_contract, rcv_wallet.blockchain_resolver()) - .unwrap(); - drop(runtime); - - rcv_wallet.save_new_asset(consignment, txid).unwrap(); +impl> SinglesigWalletParty for T { + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn abort_pending_vanilla_tx(&self, txid: &str) { + self.abort_pending_vanilla_tx_result(txid).unwrap(); + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn abort_pending_vanilla_tx_result(&self, txid: &str) -> Result<(), Error> { + self.wlt().abort_pending_vanilla_tx(txid.to_string()) + } + + fn blind_receive(&mut self) -> ReceiveData { + self.blind_receive_result().unwrap() + } + + fn blind_receive_asset_expiry( + &mut self, + asset_id: Option, + expiration: Option, + ) -> ReceiveData { + self.wlt_mut() + .blind_receive( + asset_id, + Assignment::Any, + expiration, + TRANSPORT_ENDPOINTS.clone(), + MIN_CONFIRMATIONS, + ) + .unwrap() + } + + fn blind_receive_result(&mut self) -> Result { + self.wlt_mut().blind_receive( + None, + Assignment::Any, + Some((now().unix_timestamp() + DURATION_RCV_TRANSFER as i64) as u64), + TRANSPORT_ENDPOINTS.clone(), + MIN_CONFIRMATIONS, + ) + } + + fn blind_receive_with_endpoints( + &mut self, + expiration: Option, + transport_endpoints: Vec, + ) -> ReceiveData { + self.wlt_mut() + .blind_receive( + None, + Assignment::Any, + expiration, + transport_endpoints, + MIN_CONFIRMATIONS, + ) + .unwrap() + } + + fn get_address(&mut self) -> String { + self.wlt_mut().get_address().unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn go_online(&mut self, skip_consistency_check: bool, indexer_url: Option<&str>) -> Online { + self.go_online_result(skip_consistency_check, indexer_url) + .unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + fn go_online_result( + &mut self, + skip_consistency_check: bool, + indexer_url: Option<&str>, + ) -> Result { + let mut online_options = test_go_online_options(indexer_url); + online_options.skip_consistency_check = skip_consistency_check; + self.wlt_mut().go_online(online_options) + } + + fn issue_asset_cfa(&mut self, amounts: Option<&[u64]>, file_path: Option) -> AssetCFA { + self.issue_asset_cfa_result(amounts, file_path).unwrap() + } + + fn issue_asset_cfa_result( + &mut self, + amounts: Option<&[u64]>, + file_path: Option, + ) -> Result { + let amounts = if let Some(a) = amounts { + a.to_vec() + } else { + vec![AMOUNT] + }; + self.wlt_mut().issue_asset_cfa( + NAME.to_string(), + Some(DETAILS.to_string()), + PRECISION, + amounts, + file_path, + ) + } + + fn issue_asset_ifa( + &mut self, + amounts: Option<&[u64]>, + inflation_amounts: Option<&[u64]>, + reject_list_url: Option, + ) -> AssetIFA { + self.issue_asset_ifa_result(amounts, inflation_amounts, reject_list_url) + .unwrap() + } + + fn issue_asset_ifa_result( + &mut self, + amounts: Option<&[u64]>, + inflation_amounts: Option<&[u64]>, + reject_list_url: Option, + ) -> Result { + let amounts = if let Some(a) = amounts { + a.to_vec() + } else { + vec![AMOUNT] + }; + let inflation_amounts = if let Some(a) = inflation_amounts { + a.to_vec() + } else { + vec![AMOUNT_INFLATION] + }; + self.wlt_mut().issue_asset_ifa( + TICKER.to_string(), + NAME.to_string(), + PRECISION, + amounts, + inflation_amounts, + reject_list_url, + ) + } + + fn issue_asset_nia(&mut self, amounts: Option<&[u64]>) -> AssetNIA { + self.issue_asset_nia_result(amounts).unwrap() + } + + fn issue_asset_nia_result(&mut self, amounts: Option<&[u64]>) -> Result { + let amounts = if let Some(a) = amounts { + a.to_vec() + } else { + vec![AMOUNT] + }; + self.wlt_mut() + .issue_asset_nia(TICKER.to_string(), NAME.to_string(), PRECISION, amounts) + } + + fn issue_asset_uda( + &mut self, + details: Option<&str>, + media_file_path: Option<&str>, + attachments_file_paths: Vec<&str>, + ) -> AssetUDA { + self.issue_asset_uda_result(details, media_file_path, attachments_file_paths) + .unwrap() + } + + fn issue_asset_uda_result( + &mut self, + details: Option<&str>, + media_file_path: Option<&str>, + attachments_file_paths: Vec<&str>, + ) -> Result { + self.wlt_mut().issue_asset_uda( + TICKER.to_string(), + NAME.to_string(), + details.map(|d| d.to_string()), + PRECISION, + media_file_path.map(|m| m.to_string()), + attachments_file_paths + .iter() + .map(|a| a.to_string()) + .collect(), + ) + } + + fn witness_receive(&mut self) -> ReceiveData { + self.wlt_mut() + .witness_receive( + None, + Assignment::Any, + Some((now().unix_timestamp() + DURATION_RCV_TRANSFER as i64) as u64), + TRANSPORT_ENDPOINTS.clone(), + MIN_CONFIRMATIONS, + ) + .unwrap() + } } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_send( - wallet: &mut Wallet, - online: Online, - recipient_map: &HashMap>, -) -> String { - let start = Instant::now(); - let timeout = Duration::from_secs(10); - loop { - if start.elapsed() > timeout { - panic!("send failed") +impl SinglesigParty { + pub(crate) fn get_keys(&self) -> SinglesigKeys { + self.wallet.get_keys() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn burn(&mut self, asset_id: &str, amount: u64) -> OperationResult { + self.burn_result(asset_id, amount).unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn burn_begin(&mut self, asset_id: &str, amount: u64) -> String { + self.burn_begin_result(asset_id, amount).unwrap().psbt + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn burn_begin_result( + &mut self, + asset_id: &str, + amount: u64, + ) -> Result { + self.wallet.burn_begin( + self.online, + asset_id.to_string(), + amount, + FEE_RATE, + MIN_CONFIRMATIONS, + true, + ) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn burn_result( + &mut self, + asset_id: &str, + amount: u64, + ) -> Result { + self.wallet.burn( + self.online, + asset_id.to_string(), + amount, + FEE_RATE, + MIN_CONFIRMATIONS, + ) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn create_utxos( + &mut self, + up_to: bool, + num: Option, + size: Option, + fee_rate: u64, + expected: Option, + ) { + let unspents = self.list_unspents_with_sync(false); + let colorable_before = unspents.iter().filter(|u| u.utxo.colorable).count(); + let expected = expected.unwrap_or(num.unwrap_or(UTXO_NUM)); + let _ = self + .wallet + .create_utxos(self.online, up_to, num, size, fee_rate, false) + .unwrap(); + let check = || { + let unspents = self.list_unspents_with_sync(false); + let colorable = unspents.iter().filter(|u| u.utxo.colorable).count(); + if (colorable - colorable_before) == expected as usize { + return true; + } + false + }; + if !wait_for_function(check, 10, 500) { + panic!( + "created utxo number ({}) didn't match the expected one ({expected})", + num.unwrap_or(UTXO_NUM) + ); } - let result = test_send_result(wallet, online, recipient_map); - if let Err(e) = result { - println!("send error: {e}"); - std::thread::sleep(Duration::from_millis(500)); - wallet - .sync( - online, - SyncOptions { - keychain: SyncKeychain::Colored, - strategy: SyncStrategy::FastSync, - }, - ) - .unwrap(); - continue; + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn create_utxos_begin_result( + &mut self, + up_to: bool, + num: Option, + size: Option, + fee_rate: u64, + ) -> Result { + self.wallet + .create_utxos_begin(self.online, up_to, num, size, fee_rate, false, true) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn create_utxos_default(&mut self) { + self.create_utxos(false, None, None, FEE_RATE, None); + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn drain_to(&mut self, address: &str) -> String { + self.wallet + .drain_to(self.online, address.to_string(), FEE_RATE) + .unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn inflate_begin(&mut self, asset_id: &str, inflation_amounts: &[u64]) -> String { + self.inflate_begin_result(asset_id, inflation_amounts) + .unwrap() + .psbt + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn inflate_begin_result( + &mut self, + asset_id: &str, + inflation_amounts: &[u64], + ) -> Result { + self.wallet.inflate_begin( + self.online, + asset_id.to_string(), + inflation_amounts.to_vec(), + FEE_RATE, + MIN_CONFIRMATIONS, + true, + ) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn inflate(&mut self, asset_id: &str, inflation_amounts: &[u64]) -> OperationResult { + self.inflate_result(asset_id, inflation_amounts).unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn inflate_result( + &mut self, + asset_id: &str, + inflation_amounts: &[u64], + ) -> Result { + self.wallet.inflate( + self.online, + asset_id.to_string(), + inflation_amounts.to_vec(), + FEE_RATE, + MIN_CONFIRMATIONS, + ) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn list_unspents_vanilla( + &mut self, + min_confirmations: Option, + ) -> Vec { + let min_confirmations = min_confirmations.unwrap_or(MIN_CONFIRMATIONS); + self.wallet + .list_unspents_vanilla(self.online, min_confirmations, false) + .unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn refresh_asset(&mut self, asset_id: &str) -> bool { + self.refresh_result(Some(asset_id), &[]) + .unwrap() + .transfers_changed() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn refresh_all(&mut self) -> bool { + self.refresh_result(None, &[]).unwrap().transfers_changed() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn check_save_new_asset( + &mut self, + rcv_party: &mut SinglesigParty, + asset_id: &str, + assignment: Assignment, + ) { + let receive_data = rcv_party.witness_receive(); + let recipient_map = HashMap::from([( + asset_id.to_owned(), + vec![Recipient { + assignment, + recipient_id: receive_data.recipient_id.clone(), + witness_data: Some(WitnessData { + amount_sat: 1000, + blinding: None, + }), + transport_endpoints: TRANSPORT_ENDPOINTS.clone(), + }], + )]); + let txid = self.send_retry(&recipient_map); + assert!(!txid.is_empty()); + + let consignment_path = self.wallet.get_send_consignment_path(asset_id, &txid); + let consignment = RgbTransfer::load_file(consignment_path).unwrap(); + + let contract = consignment.clone().into_contract(); + let asset_schema: AssetSchema = consignment.schema_id().try_into().unwrap(); + let validation_config = ValidationConfig { + chain_net: rcv_party.wallet.chain_net(), + trusted_typesystem: asset_schema.types(), + ..Default::default() + }; + let mut runtime = rcv_party.wallet.rgb_runtime().unwrap(); + let valid_contract = contract + .clone() + .validate(&DumbResolver, &validation_config) + .unwrap(); + runtime + .import_contract(valid_contract, rcv_party.wallet.blockchain_resolver()) + .unwrap(); + drop(runtime); + + rcv_party.wallet.save_new_asset(consignment, txid).unwrap(); + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn send_retry(&mut self, recipient_map: &HashMap>) -> String { + let start = Instant::now(); + let timeout = Duration::from_secs(10); + loop { + if start.elapsed() > timeout { + panic!("send failed") + } + let result = self.send_result(recipient_map); + if let Err(e) = result { + println!("send error: {e}"); + std::thread::sleep(Duration::from_millis(500)); + self.wallet + .sync( + self.online, + SyncOptions { + keychain: SyncKeychain::Colored, + strategy: SyncStrategy::FastSync, + }, + ) + .unwrap(); + continue; + } + break result.unwrap().txid; } - break result.unwrap().txid; } -} -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_send_result( - wallet: &mut Wallet, - online: Online, - recipient_map: &HashMap>, -) -> Result { - wallet.send( - online, - recipient_map.clone(), - false, - FEE_RATE, - MIN_CONFIRMATIONS, - Some((now().unix_timestamp() + DURATION_SEND_TRANSFER as i64) as u64), - ) -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn send_result( + &mut self, + recipient_map: &HashMap>, + ) -> Result { + self.wallet.send( + self.online, + recipient_map.clone(), + false, + FEE_RATE, + MIN_CONFIRMATIONS, + Some((now().unix_timestamp() + DURATION_SEND_TRANSFER as i64) as u64), + ) + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_send_begin_result( - wallet: &mut Wallet, - online: Online, - recipient_map: &HashMap>, -) -> Result { - wallet.send_begin( - online, - recipient_map.clone(), - false, - FEE_RATE, - MIN_CONFIRMATIONS, - None, - false, - ) -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn send_begin_result( + &mut self, + recipient_map: &HashMap>, + ) -> Result { + self.wallet.send_begin( + self.online, + recipient_map.clone(), + false, + FEE_RATE, + MIN_CONFIRMATIONS, + None, + false, + ) + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_send_btc( - wallet: &mut Wallet, - online: Online, - address: &str, - amount: u64, -) -> String { - test_send_btc_result(wallet, online, address, amount).unwrap() -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn send_btc(&mut self, address: &str, amount: u64) -> String { + self.send_btc_result(address, amount).unwrap() + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_send_btc_result( - wallet: &mut Wallet, - online: Online, - address: &str, - amount: u64, -) -> Result { - wallet.send_btc(online, address.to_string(), amount, FEE_RATE, false) -} + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn send_btc_result(&mut self, address: &str, amount: u64) -> Result { + self.wallet + .send_btc(self.online, address.to_string(), amount, FEE_RATE, false) + } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn test_sync_result( - wallet: &mut Wallet, - online: Online, - options: SyncOptions, -) -> Result<(), Error> { - wallet.sync(online, options) + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn inflate_end_result( + &mut self, + signed_psbt: &str, + ) -> Result { + self.wallet + .inflate_end(self.online, signed_psbt.to_string()) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn drain_wallet(&mut self) { + let mut rcv_wallet = get_test_wallet(false, None); + self.drain_to(&rcv_wallet.get_address().unwrap()); + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn drain_to_result(&mut self, address: &str) -> Result { + self.wallet + .drain_to(self.online, address.to_string(), FEE_RATE) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn send( + &mut self, + recipient_map: HashMap>, + fee_rate: u64, + expiration_timestamp: Option, + ) -> OperationResult { + self.wallet + .send( + self.online, + recipient_map, + false, + fee_rate, + MIN_CONFIRMATIONS, + expiration_timestamp, + ) + .unwrap() + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn burn_end_result(&mut self, signed_psbt: &str) -> Result { + self.wallet.burn_end(self.online, signed_psbt.to_string()) + } + + #[cfg(any(feature = "electrum", feature = "esplora"))] + pub(crate) fn drain_to_begin_result( + &mut self, + address: &str, + fee_rate: u64, + ) -> Result { + self.wallet + .drain_to_begin(self.online, address.to_string(), fee_rate, true) + } } diff --git a/src/wallet/test/utils/helpers.rs b/src/wallet/test/utils/helpers.rs index 565fd5a8..6d1c9211 100644 --- a/src/wallet/test/utils/helpers.rs +++ b/src/wallet/test/utils/helpers.rs @@ -101,7 +101,7 @@ pub(crate) fn get_test_wallet_raw( wallet_keys.clone(), ) .unwrap(); - println!("wallet directory: {:?}", test_get_wallet_dir(&wallet)); + println!("wallet directory: {:?}", wallet.get_wallet_dir()); wallet } @@ -115,24 +115,15 @@ pub(crate) fn get_test_wallet(private_keys: bool, max_allocations_per_utxo: Opti } #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn get_funded_wallet_p2wpkh() -> (Wallet, Online) { - create_test_data_dir(); +pub(crate) fn get_funded_party_p2wpkh() -> SinglesigParty { let keys = generate_keys(BitcoinNetwork::Regtest, WitnessVersion::SegWitV0); - let mut wallet = Wallet::new( - WalletData { - data_dir: get_test_data_dir_string(), - bitcoin_network: BitcoinNetwork::Regtest, - database_type: DatabaseType::Sqlite, - max_allocations_per_utxo: MAX_ALLOCATIONS_PER_UTXO, - supported_schemas: AssetSchema::VALUES.to_vec(), - }, - SinglesigKeys::from_keys(&keys, None), - ) - .unwrap(); + let wallet_keys = SinglesigKeys::from_keys(&keys, None); + let mut wallet = get_test_wallet_raw(&wallet_keys, None, BitcoinNetwork::Regtest); let online = wallet.go_online(test_go_online_options(None)).unwrap(); - fund_wallet(wallet.get_address().unwrap()); - test_create_utxos_default(&mut wallet, online); - (wallet, online) + let mut party = party!(wallet, online); + fund_wallet(party.get_address()); + party.create_utxos_default(); + party } #[cfg(any(feature = "electrum", feature = "esplora"))] @@ -158,19 +149,26 @@ pub(crate) fn get_funded_noutxo_wallet( } #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn get_funded_wallet( - private_keys: bool, - indexer_url: Option, -) -> (Wallet, Online) { - let (mut wallet, online) = get_funded_noutxo_wallet(private_keys, indexer_url); - test_create_utxos_default(&mut wallet, online); - (wallet, online) +pub(crate) fn get_funded_party(private_keys: bool, indexer_url: Option) -> SinglesigParty { + let (wallet, online) = get_funded_noutxo_wallet(private_keys, indexer_url); + let mut party = party!(wallet, online); + party.create_utxos_default(); + party } #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn drain_wallet(wallet: &mut Wallet, online: Online) { - let mut rcv_wallet = get_test_wallet(false, None); - test_drain_to(wallet, online, &rcv_wallet.get_address().unwrap()); +pub(crate) fn get_empty_party(private_keys: bool, indexer_url: Option) -> SinglesigParty { + let (wallet, online) = get_empty_wallet(private_keys, indexer_url); + party!(wallet, online) +} + +#[cfg(any(feature = "electrum", feature = "esplora"))] +pub(crate) fn get_funded_noutxo_party( + private_keys: bool, + indexer_url: Option, +) -> SinglesigParty { + let (wallet, online) = get_funded_noutxo_wallet(private_keys, indexer_url); + party!(wallet, online) } #[cfg(any(feature = "electrum", feature = "esplora"))] @@ -218,91 +216,6 @@ pub(crate) fn fund_wallet(address: String) { mine(false); } -pub(crate) fn check_test_transfer_status_recipient( - wallet: &Wallet, - recipient_id: &str, - expected_status: TransferStatus, -) -> bool { - let txn = wallet.database().begin_transaction().unwrap(); - let transfers = txn.iter_transfers().unwrap(); - txn.commit().unwrap(); - let mut recipient_transfers = transfers - .iter() - .filter(|t| t.recipient_id.as_deref() == Some(recipient_id)); - let transfer = recipient_transfers.next().unwrap(); - assert!(recipient_transfers.next().is_none()); - let (transfer_data, _) = get_test_transfer_data(wallet, transfer); - println!( - "receive with recipient_id {} is in status {:?}", - recipient_id, &transfer_data.status - ); - transfer_data.status == expected_status -} - -pub(crate) fn check_test_transfer_status_sender( - wallet: &Wallet, - txid: &str, - expected_status: TransferStatus, -) -> bool { - let batch_transfers = get_test_batch_transfers(wallet, txid); - assert_eq!(batch_transfers.len(), 1); - let batch_transfer = batch_transfers.first().unwrap(); - println!( - "send with txid {} is in status {:?}", - txid, &batch_transfer.status - ); - batch_transfer.status == expected_status -} - -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn check_test_wallet_data( - wallet: &mut Wallet, - asset: &AssetNIA, - custom_issued_supply: Option, - transfer_num: usize, - spent_amount: u64, -) { - println!("checking wallet data..."); - let issued_supply = match custom_issued_supply { - Some(supply) => supply, - None => AMOUNT, - }; - // asset list - let assets = test_list_assets(wallet, &[]); - let nia_assets = assets.nia.unwrap(); - let cfa_assets = assets.cfa.unwrap(); - assert_eq!(nia_assets.len(), 1); - assert_eq!(cfa_assets.len(), 0); - let nia_asset = nia_assets.first().unwrap(); - assert_eq!(nia_asset.asset_id, asset.asset_id); - // asset balance - let balance = wallet.get_asset_balance(asset.asset_id.clone()).unwrap(); - assert_eq!( - balance, - Balance { - settled: asset.balance.settled - spent_amount, - future: asset.balance.future - spent_amount, - spendable: asset.balance.spendable - spent_amount, - } - ); - // asset metadata - let metadata = test_get_asset_metadata(wallet, &asset.asset_id); - assert_eq!(metadata.asset_schema, AssetSchema::Nia); - assert_eq!(metadata.initial_supply, issued_supply); - assert_eq!(metadata.name, asset.name); - assert_eq!(metadata.precision, asset.precision); - assert_eq!(metadata.ticker.unwrap(), asset.ticker); - // transfer list - let transfers = test_list_transfers(wallet, Some(&asset.asset_id)); - assert_eq!(transfers.len(), 1 + transfer_num); - assert_eq!(transfers.first().unwrap().kind, TransferKind::Issuance); - assert_eq!(transfers.last().unwrap().kind, TransferKind::Send); - assert_eq!(transfers.last().unwrap().status, TransferStatus::Settled); - // unspent list - let unspents = test_list_unspents(wallet, None, false); - assert_eq!(unspents.len(), 6); -} - pub(crate) fn compare_test_directories(src: &Path, dst: &Path, skip: &[&str]) { let ignores = RegexSet::new(skip).unwrap(); let cmp = dircmp::Comparison::new(ignores); @@ -310,156 +223,6 @@ pub(crate) fn compare_test_directories(src: &Path, dst: &Path, skip: &[&str]) { assert!(diff.is_empty()); } -pub(crate) fn get_test_batch_transfers(wallet: &Wallet, txid: &str) -> Vec { - let txn = wallet.database().begin_transaction().unwrap(); - let batch_transfers = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); - batch_transfers - .into_iter() - .filter(|b| b.txid == Some(txid.to_string())) - .collect() -} - -pub(crate) fn get_test_asset_transfers( - wallet: &Wallet, - batch_transfer_idx: i32, -) -> Vec { - let txn = wallet.database().begin_transaction().unwrap(); - let asset_transfers = txn.iter_asset_transfers().unwrap(); - txn.commit().unwrap(); - asset_transfers - .into_iter() - .filter(|at| at.batch_transfer_idx == batch_transfer_idx) - .collect() -} - -pub(crate) fn get_test_transfers( - wallet: &Wallet, - asset_transfer_idx: i32, -) -> impl Iterator { - let txn = wallet.database().begin_transaction().unwrap(); - let transfers = txn.iter_transfers().unwrap(); - txn.commit().unwrap(); - transfers - .into_iter() - .filter(move |t| t.asset_transfer_idx == asset_transfer_idx) -} - -pub(crate) fn get_test_asset_transfer(wallet: &Wallet, batch_transfer_idx: i32) -> DbAssetTransfer { - let asset_transfers = get_test_asset_transfers(wallet, batch_transfer_idx); - let mut user_driven_transfers = asset_transfers.into_iter().filter(|t| t.user_driven); - let user_driven_transfer = user_driven_transfers.next().unwrap(); - assert!(user_driven_transfers.next().is_none()); - user_driven_transfer -} - -pub(crate) fn get_test_colorings(wallet: &Wallet, asset_transfer_idx: i32) -> Vec { - let txn = wallet.database().begin_transaction().unwrap(); - let colorings = txn.iter_colorings().unwrap(); - txn.commit().unwrap(); - colorings - .into_iter() - .filter(|c| c.asset_transfer_idx == asset_transfer_idx) - .collect() -} - -pub(crate) fn get_test_transfer_recipient(wallet: &Wallet, recipient_id: &str) -> DbTransfer { - let txn = wallet.database().begin_transaction().unwrap(); - let transfers = txn.iter_transfers().unwrap(); - txn.commit().unwrap(); - let mut transfers = transfers - .into_iter() - .filter(|t| t.recipient_id == Some(recipient_id.to_string()) && t.incoming); - let transfer = transfers.next().unwrap(); - assert!(transfers.next().is_none()); - transfer -} - -pub(crate) fn get_test_transfer_sender( - wallet: &Wallet, - txid: &str, -) -> (DbTransfer, DbAssetTransfer, DbBatchTransfer) { - let batch_transfers = get_test_batch_transfers(wallet, txid); - assert_eq!(batch_transfers.len(), 1); - let batch_transfer = batch_transfers.into_iter().next().unwrap(); - let asset_transfer = get_test_asset_transfer(wallet, batch_transfer.idx); - let mut transfers = get_test_transfers(wallet, asset_transfer.idx); - let transfer = transfers.next().unwrap(); - assert!(transfers.next().is_none()); - (transfer, asset_transfer, batch_transfer) -} - -pub(crate) fn get_test_transfers_sender( - wallet: &Wallet, - txid: &str, -) -> ( - HashMap>, - Vec, - DbBatchTransfer, -) { - let batch_transfers = get_test_batch_transfers(wallet, txid); - assert_eq!(batch_transfers.len(), 1); - let batch_transfer = batch_transfers.into_iter().next().unwrap(); - let asset_transfers = get_test_asset_transfers(wallet, batch_transfer.idx); - let mut transfers: HashMap> = HashMap::new(); - for asset_transfer in &asset_transfers { - let asset_id = asset_transfer.asset_id.clone().unwrap(); - let transfers_for_asset = get_test_transfers(wallet, asset_transfer.idx); - transfers.insert(asset_id, transfers_for_asset.collect()); - } - (transfers, asset_transfers, batch_transfer) -} - -pub(crate) fn get_test_transfer_data( - wallet: &Wallet, - transfer: &DbTransfer, -) -> (TransferData, DbAssetTransfer) { - let txn = wallet.database().begin_transaction().unwrap(); - let db_data = txn.get_db_data(false).unwrap(); - txn.commit().unwrap(); - let (asset_transfer, batch_transfer) = - transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers); - let transfer_data = wallet - .get_transfer_data( - transfer, - &asset_transfer, - &batch_transfer, - &db_data.txos, - &db_data.colorings, - ) - .unwrap(); - (transfer_data, asset_transfer) -} - -pub(crate) fn get_test_transfer_related( - wallet: &Wallet, - transfer: &DbTransfer, -) -> (DbAssetTransfer, DbBatchTransfer) { - let txn = wallet.database().begin_transaction().unwrap(); - let db_data = txn.get_db_data(false).unwrap(); - txn.commit().unwrap(); - transfer.related_transfers(&db_data.asset_transfers, &db_data.batch_transfers) -} - -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn list_test_unspents(wallet: &mut Wallet, msg: &str) -> Vec { - let unspents = test_list_unspents(wallet, None, false); - print_unspents(&unspents, msg); - unspents -} - -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn get_colorable_unspents( - wallet: &mut Wallet, - online: Option, - settled_only: bool, -) -> Vec { - test_list_unspents(wallet, online, settled_only) - .into_iter() - .filter(|u| u.utxo.colorable) - .collect() -} - pub(crate) fn print_unspents(unspents: &[Unspent], msg: &str) { println!("\n{msg} ({} unspents)", unspents.len()); for u in unspents { @@ -484,46 +247,6 @@ pub(crate) fn print_unspents(unspents: &[Unspent], msg: &str) { } } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn wait_for_asset_balance(wallet: &Wallet, asset_id: &str, expected_balance: &Balance) { - println!("waiting for asset balance"); - let mut current_balance = test_get_asset_balance(wallet, asset_id); - let check = || { - current_balance = test_get_asset_balance(wallet, asset_id); - if ¤t_balance == expected_balance { - return true; - } - false - }; - if !wait_for_function(check, 10, 500) { - println!("current balance: {current_balance:?}"); - println!("expected balance: {expected_balance:?}"); - panic!("asset balance is not becoming the expected one"); - } -} - -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn wait_for_btc_balance( - wallet: &mut Wallet, - online: Online, - expected_balance: &BtcBalance, -) { - println!("waiting for BTC balance"); - let mut current_balance = test_get_btc_balance(wallet, online); - let check = || { - current_balance = test_get_btc_balance(wallet, online); - if ¤t_balance == expected_balance { - return true; - } - false - }; - if !wait_for_function(check, 10, 500) { - println!("current balance: {current_balance:?}"); - println!("expected balance: {expected_balance:?}"); - panic!("BTC balance is not becoming the expected one"); - } -} - pub(crate) fn wait_for_function(mut func: F, timeout_secs: u8, interval_ms: u16) -> bool where F: FnMut() -> bool, @@ -539,155 +262,6 @@ where false } -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn wait_for_refresh( - wallet: &mut impl RgbWalletOpsOnline, - online: Online, - asset_id: Option<&str>, - transfer_ids: Option<&[i32]>, -) { - println!( - "waiting for refresh ({})", - wallet.internals().wallet_data.data_dir - ); - let mut seen = HashSet::new(); - let mut target_set = HashSet::new(); - if let Some(t_ids) = transfer_ids { - assert!(!t_ids.is_empty()); - target_set = t_ids.iter().copied().collect(); - } - let check = || { - let result = test_refresh_result(wallet, online, asset_id, &[]); - if let Ok(refresh_res) = result { - let mut non_fatal_error = false; - refresh_res.iter().for_each(|(i, rt)| { - if let Some(ref e) = rt.failure { - eprintln!("refresh of {i} failure: {e} ({e:?})"); - match e { - Error::Internal { details } => { - println!("refresh of {i} internal error: {e}, details: {details}"); - non_fatal_error = true; - } - Error::InvalidTxid => { - println!("refresh of {i} invalid TXID: {e}"); - non_fatal_error = true; - } - Error::Network { details } => { - println!("refresh of {i} network error: {e}, details: {details}"); - non_fatal_error = true; - } - _ => panic!("refresh of {i} fatal error: {e}"), - } - } - }); - if non_fatal_error { - return false; - } - if transfer_ids.is_some() { - for (id, rt) in refresh_res { - if rt.updated_status.is_some() && target_set.contains(&id) { - seen.insert(id); - } - } - if seen == target_set { - return true; - } - } else if refresh_res.transfers_changed() { - return true; - } - } else { - eprintln!("refresh error: {result:?}"); - return false; - }; - false - }; - if !wait_for_function(check, 10, 500) { - panic!("transfer(s) are not refreshing"); - } -} - -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn wait_for_unspents( - wallet: &mut Wallet, - online: Option, - settled_only: bool, - expected_len: u8, -) { - println!("waiting for unspents"); - let mut unspents = test_list_unspents(wallet, online, settled_only); - let check = || { - unspents = test_list_unspents(wallet, online, settled_only); - unspents.len() == expected_len as usize - }; - if !wait_for_function(check, 10, 500) { - panic!( - "UTXO num {} is not becoming the expected {expected_len}", - unspents.len() - ); - } -} - -pub(crate) fn get_pending_blind_transfers(wallet: &mut impl RgbWalletOpsOffline) -> Vec { - let transfers = test_list_transfers(wallet, None); - transfers - .into_iter() - .filter(|t| t.status.pending() && t.kind == TransferKind::ReceiveBlind) - .collect() -} - -#[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn extract_opouts_from_transfer( - wallet: &Wallet, - asset_id: &str, - txid: &str, -) -> Vec { - let batch_transfers = get_test_batch_transfers(wallet, txid); - assert_eq!(batch_transfers.len(), 1); - let batch_transfer = batch_transfers.first().unwrap(); - let asset_transfers = get_test_asset_transfers(wallet, batch_transfer.idx); - let asset_transfers = asset_transfers - .iter() - .filter(|at| at.asset_id.as_ref() == Some(&asset_id.to_string())) - .filter(|t| t.user_driven) - .collect::>(); - assert_eq!(asset_transfers.len(), 1); - let asset_transfer = asset_transfers.first().unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let colorings: Vec = txn - .iter_colorings() - .unwrap() - .into_iter() - .filter(|c| c.asset_transfer_idx == asset_transfer.idx) - .collect(); - txn.commit().unwrap(); - if colorings.is_empty() { - panic!("cannot find colorings for this transfer"); - } - let txo_indices = colorings.iter().map(|c| c.txo_idx).collect::>(); - let txn = wallet.database().begin_transaction().unwrap(); - let db_txos = txn.iter_txos().unwrap(); - txn.commit().unwrap(); - let relevant_txos = db_txos.into_iter().filter(|t| txo_indices.contains(&t.idx)); - let mut outpoints = relevant_txos - .map(|txo| OutPoint::from(txo.clone())) - .peekable(); - if outpoints.peek().is_none() { - panic!("cannot find outpoints for this transfer"); - } - let contract_id = ContractId::from_str(asset_id).unwrap(); - let runtime = wallet.rgb_runtime().unwrap(); - let assignments = runtime - .contract_assignments_for(contract_id, outpoints) - .unwrap(); - let mut opouts = Vec::new(); - for (_explicit_seal, opout_state_map) in assignments { - for (opout, _state) in opout_state_map { - opouts.push(opout); - } - } - opouts -} - #[cfg(any(feature = "electrum", feature = "esplora"))] pub(crate) fn write_opouts_to_reject_list(filename: &str, opouts: &[String]) { let lists_dir = PathBuf::from(join_with_sep(&LISTS_DIR_PARTS)); @@ -701,73 +275,16 @@ pub(crate) fn write_opouts_to_reject_list(filename: &str, opouts: &[String]) { } } -/// print the provided message, then get colorings for each wallet unspent and print their status, -/// type, amount and asset #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn show_unspent_colorings(wallet: &mut impl RgbWalletOpsOnline, msg: &str) { - println!( - "\nwallet {} unspent colorings ({msg})", - wallet.get_wallet_data().data_dir - ); - let unspents = test_list_unspents(wallet, None, false) - .into_iter() - .filter(|u| u.utxo.colorable); - let txn = wallet.database().begin_transaction().unwrap(); - let db_txos = txn.iter_txos().unwrap(); - let db_colorings = txn.iter_colorings().unwrap(); - let db_asset_transfers = txn.iter_asset_transfers().unwrap(); - let db_batch_transfers = txn.iter_batch_transfers().unwrap(); - txn.commit().unwrap(); - let pending_blind_transfers = get_pending_blind_transfers(wallet); - for unspent in unspents { - let outpoint = unspent.utxo.outpoint; - let db_txo = db_txos - .iter() - .find(|t| t.txid == outpoint.txid && t.vout == outpoint.vout) - .unwrap(); - let txo_pending_blind_transfers = pending_blind_transfers.iter().filter(|t| { - if let Some(txo) = &t.receive_utxo { - db_txo.outpoint() == *txo - } else { - false - } - }); - println!( - "> {}:{}, {} sat{}", - outpoint.txid, - outpoint.vout, - unspent.utxo.btc_amount, - if !unspent.utxo.exists { - " - tx not broadcast yet" - } else { - "" - }, - ); - let txo_db_colorings = db_colorings.iter().filter(|c| c.txo_idx == db_txo.idx); - for db_coloring in txo_db_colorings { - let db_asset_transfer = db_asset_transfers - .iter() - .find(|a| a.idx == db_coloring.asset_transfer_idx) - .unwrap(); - let db_batch_transfer = db_batch_transfers - .iter() - .find(|b| b.idx == db_asset_transfer.batch_transfer_idx) - .unwrap(); - println!( - "\t- {:?} {:?} of {:?} for {:?}", - db_batch_transfer.status, - db_coloring.r#type, - db_coloring.assignment, - db_asset_transfer.asset_id.as_ref(), - ); - } - for pbt in txo_pending_blind_transfers { - println!("\t- pending blind receive with transfer ID {}", pbt.idx); - } - } +pub(crate) fn get_proxy_client(proxy_url: Option<&str>) -> ProxyClient { + ProxyClient::new(proxy_url.unwrap_or(PROXY_URL)).unwrap() } #[cfg(any(feature = "electrum", feature = "esplora"))] -pub(crate) fn get_proxy_client(proxy_url: Option<&str>) -> ProxyClient { - ProxyClient::new(proxy_url.unwrap_or(PROXY_URL)).unwrap() +pub(crate) fn test_go_online_options(indexer_url: Option<&str>) -> OnlineOptions { + OnlineOptions { + indexer_url: indexer_url.unwrap_or(ELECTRUM_URL).to_string(), + skip_consistency_check: true, + vanilla_sync_lookback: INDEXER_SYNC_LOOKBACK as u32, + } } diff --git a/src/wallet/test/utils/mod.rs b/src/wallet/test/utils/mod.rs index 9030be1b..4be273ed 100644 --- a/src/wallet/test/utils/mod.rs +++ b/src/wallet/test/utils/mod.rs @@ -1,5 +1,6 @@ use super::*; +#[macro_use] pub(super) mod api; pub(super) mod chain; pub(crate) mod helpers; diff --git a/src/wallet/test/witness_receive.rs b/src/wallet/test/witness_receive.rs index f89cae92..9c9f32d4 100644 --- a/src/wallet/test/witness_receive.rs +++ b/src/wallet/test/witness_receive.rs @@ -8,13 +8,12 @@ fn success() { let amount = 69; let expiration_secs = 60i64; - let (mut wallet, online) = get_funded_wallet!(); + let mut party = get_funded_party!(); // only mandatory fields - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_before = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); - let receive_data = wallet + let bak_info_before = party.db_backup_info(); + let receive_data = party + .wallet .witness_receive( None, Assignment::Any, @@ -23,26 +22,25 @@ fn success() { MIN_CONFIRMATIONS, ) .unwrap(); - let txn = wallet.database().begin_transaction().unwrap(); - let bak_info_after = txn.get_backup_info().unwrap().unwrap(); - txn.commit().unwrap(); + let bak_info_after = party.db_backup_info(); assert!(bak_info_after.last_operation_timestamp > bak_info_before.last_operation_timestamp); assert!(receive_data.expiration_timestamp.is_none()); let decoded_invoice = Invoice::new(receive_data.invoice).unwrap(); assert_eq!( decoded_invoice.invoice_data.network, - wallet.get_wallet_data().bitcoin_network + party.get_wallet_data().bitcoin_network ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); - let (_, batch_transfer) = get_test_transfer_related(&wallet, &transfer); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (_, batch_transfer) = party.get_test_transfer_related(&transfer); assert_eq!(batch_transfer.min_confirmations, MIN_CONFIRMATIONS); // asset ID + expiration + 0 min confirmations - let asset = test_issue_asset_cfa(&mut wallet, online, None, None); + let asset = party.issue_asset_cfa(None, None); let asset_id = asset.asset_id; let expiration_timestamp = (now().unix_timestamp() + expiration_secs) as u64; let min_confirmations = 0; - let receive_data = wallet + let receive_data = party + .wallet .witness_receive( Some(asset_id.clone()), Assignment::Fungible(amount), @@ -55,8 +53,8 @@ fn success() { receive_data.expiration_timestamp, Some(expiration_timestamp) ); - let transfer = get_test_transfer_recipient(&wallet, &receive_data.recipient_id); - let (_, batch_transfer) = get_test_transfer_related(&wallet, &transfer); + let transfer = party.get_test_transfer_recipient(&receive_data.recipient_id); + let (_, batch_transfer) = party.get_test_transfer_related(&transfer); assert_eq!(batch_transfer.min_confirmations, min_confirmations); let invoice = Invoice::new(receive_data.invoice.clone()).unwrap(); let invoice_data = invoice.invoice_data(); @@ -89,7 +87,7 @@ fn success() { format!("rpc://{}", "127.0.0.1:3001/json-rpc"), format!("rpc://{}", "127.0.0.1:3002/json-rpc"), ]; - let result = wallet.witness_receive( + let result = party.wallet.witness_receive( None, Assignment::Any, None, @@ -97,12 +95,8 @@ fn success() { MIN_CONFIRMATIONS, ); assert!(result.is_ok()); - let transfer = get_test_transfer_recipient(&wallet, &result.unwrap().recipient_id); - let txn = wallet.database().begin_transaction().unwrap(); - let tte_data = txn - .get_transfer_transport_endpoints_data(transfer.idx) - .unwrap(); - txn.commit().unwrap(); + let transfer = party.get_test_transfer_recipient(&result.unwrap().recipient_id); + let tte_data = party.db_transfer_transport_endpoints_data(transfer.idx); assert_eq!(tte_data.len(), transport_endpoints.len()); }