From 2302135709df5f8f9a0d5aeeee7b7807258275e3 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Wed, 16 Sep 2026 15:53:57 +0300 Subject: [PATCH] Lock outputs before sending with Tor (#814) Co-authored-by: wiesche (cherry picked from commit 452a3ec51b302091e12fc1a7b2eb24c0ac2625b0) --- api/src/owner.rs | 73 +- controller/src/command.rs | 34 +- controller/src/controller.rs | 17 - controller/tests/accounts.rs | 294 +++---- controller/tests/build_chain.rs | 91 +-- controller/tests/build_output.rs | 35 +- controller/tests/check.rs | 648 +++++---------- controller/tests/common/mod.rs | 35 +- controller/tests/config_api.rs | 18 +- controller/tests/file.rs | 265 ++---- controller/tests/invoice.rs | 397 ++++----- controller/tests/late_lock.rs | 145 ++-- controller/tests/mwixnet.rs | 168 ++-- controller/tests/no_change.rs | 214 ++--- controller/tests/payment_proofs.rs | 136 ++-- controller/tests/repost.rs | 232 ++---- controller/tests/revert.rs | 289 +++---- controller/tests/self_send.rs | 103 +-- controller/tests/slatepack.rs | 512 +++++------- controller/tests/transaction.rs | 1108 ++++++++++++-------------- controller/tests/ttl_cutoff.rs | 155 ++-- controller/tests/tx_list_filter.rs | 434 +++++----- controller/tests/updater_thread.rs | 31 +- impls/src/adapters/tor.rs | 2 +- libwallet/src/mwixnet/onion/onion.rs | 2 +- tests/cmd_line_basic.rs | 248 +++--- tests/owner_v3_lifecycle.rs | 41 +- 27 files changed, 2275 insertions(+), 3452 deletions(-) diff --git a/api/src/owner.rs b/api/src/owner.rs index 1296db8..c180934 100644 --- a/api/src/owner.rs +++ b/api/src/owner.rs @@ -40,6 +40,7 @@ use grin_wallet_util::OnionV3Address; use chrono::prelude::*; use ed25519_dalek::SigningKey as DalekSecretKey; +use libwallet::wallet_lock; use std::convert::TryFrom; use std::fs::File; use std::io::Write; @@ -709,9 +710,9 @@ where /// is confirmed. This method also returns a function that will perform that locking, and it is /// up to the caller to decide the best time to call the lock function /// (via the [`tx_lock_outputs`](struct.Owner.html#method.tx_lock_outputs) method). - /// If the exchange method is intended to be synchronous (such as via a direct http call,) + /// If the exchange method is intended to be synchronous (such as via a direct http call) /// then the lock call can wait until the response is confirmed. If it is asynchronous, (such - /// as via file transfer,) the lock call should happen immediately (before the file is sent + /// as via file transfer) the lock call should happen immediately (before the file is sent /// to the recipient). /// /// If the `send_args` [`InitTxSendArgs`](../grin_wallet_libwallet/types/struct.InitTxSendArgs.html), @@ -719,7 +720,7 @@ where /// function will attempt to send the slate back to the sender using the slatepack sync /// send (TOR). If providing this argument, check the `state` field of the slate to see if the /// sync_send was successful (it should be S2 if the sync sent successfully). It will also post - /// the transction if the `post_tx` field is set. + /// the transaction if the `post_tx` field is set. /// /// # Arguments /// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if @@ -730,11 +731,15 @@ where /// # Returns /// * a result containing: /// * The transaction [Slate](../grin_wallet_libwallet/slate/struct.Slate.html), - /// which can be forwarded to the recieving party by any means. Once the caller is relatively - /// certain that the transaction has been sent to the recipient, the associated wallet - /// transaction outputs should be locked via a call to - /// [`tx_lock_outputs`](struct.Owner.html#method.tx_lock_outputs). This must be called before calling - /// [`finalize_tx`](struct.Owner.html#method.finalize_tx). + /// which can be forwarded to the receiving party by any means. With normal locking, an + /// attempted Tor send already locks the outputs, even if sending fails. Do not call + /// [`tx_lock_outputs`](struct.Owner.html#method.tx_lock_outputs) again when forwarding manually. + /// If sending was not requested or was skipped, lock the outputs before forwarding the slate. + /// With late locking, outputs are locked during finalization instead. + /// If `skip_tor` is omitted, `skip_send_attempt` in the Tor config decides whether to send. + /// With normal locking, a returned S1 slate alone does not tell you whether outputs are locked. + /// Set `skip_tor` explicitly or check [`retrieve_txs`](struct.Owner.html#method.retrieve_txs) + /// for the slate ID before locking manually. /// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered. /// /// # Remarks @@ -768,7 +773,7 @@ where /// if let Ok(slate) = result { /// // Send slate somehow /// // ... - /// // Lock our outputs if we're happy the slate was (or is being) sent + /// // Lock outputs for manual sending without late locking /// api_owner.tx_lock_outputs(None, &slate); /// } /// ``` @@ -785,32 +790,36 @@ where } _ => None, }; - let (slate, tor_config) = { - let mut w_lock = self.wallet_inst.lock(); - let tor_config = send_args - .as_ref() - .map(|_| crate::tor_config::load(&self.config_path())) - .transpose()?; - let w = w_lock.lc_provider()?.wallet_inst()?; - let slate = owner::init_send_tx(w, keychain_mask, args, self.doctest_mode)?; - (slate, tor_config) - }; + + let tor_config = send_args + .as_ref() + .map(|_| crate::tor_config::load(&self.config_path())) + .transpose()?; + // Helper functionality. If send arguments exist, attempt to send sync and // finalize match send_args { Some(sa) => { - let tc = tor_config.ok_or_else(|| { - Error::TorConfig("Tor config was not loaded with send arguments".into()) - })?; - let can_send = tc.send_tor(sa.skip_tor); - if self.doctest_mode || !can_send || dest.is_none() { - return Ok(slate); - } + let slate = { + wallet_lock!(self.wallet_inst, w); + let late_lock = args.late_lock.unwrap_or(false); + let slate = owner::init_send_tx(w, keychain_mask, args, self.doctest_mode)?; + let tc = tor_config.as_ref().ok_or_else(|| { + Error::TorConfig("Tor config was not loaded with send arguments".into()) + })?; + let can_send = tc.send_tor(sa.skip_tor); + if self.doctest_mode || !can_send || dest.is_none() { + return Ok(slate); + } + if !late_lock { + owner::tx_lock_outputs(w, keychain_mask, &slate)?; + } + slate + }; let res = - try_slatepack_sync_workflow(&slate, &dest.unwrap(), Some(tc), None, false); + try_slatepack_sync_workflow(&slate, &dest.unwrap(), tor_config, None, false); match res { Ok(s) => { - self.tx_lock_outputs(keychain_mask, &s)?; let ret_slate = self.finalize_tx(keychain_mask, &s)?; if sa.post_tx { let result = self.post_tx(keychain_mask, &ret_slate, sa.fluff); @@ -834,7 +843,11 @@ where } } } - None => Ok(slate), + None => { + wallet_lock!(self.wallet_inst, w); + let slate = owner::init_send_tx(w, keychain_mask, args, self.doctest_mode)?; + Ok(slate) + } } } @@ -2353,7 +2366,7 @@ where /// /// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if /// * `slatepack` - A string representing an armored slatepack - /// * `secret_indices` - Indices along this wallet's deriviation path with which to attempt + /// * `secret_indices` - Indices along this wallet's derivation path with which to attempt /// decryption. This function will attempt to use secret keys at each index along this path /// to attempt to decrypt the payload, returning an error if none of the keys match. /// diff --git a/controller/src/command.rs b/controller/src/command.rs index daeb256..97b59d5 100644 --- a/controller/src/command.rs +++ b/controller/src/command.rs @@ -439,7 +439,6 @@ where target_slate_version: args.target_slate_version, payment_proof_recipient_address, ttl_blocks: args.ttl_blocks, - send_args: None, late_lock: Some(args.late_lock), ..Default::default() }; @@ -494,14 +493,14 @@ where tor_config.bridge.bridge_line = Some(b); } - let output_sp = || -> Result<(), Error> { + let output_sp = |owner_api: &mut Owner, lock_outputs: bool| -> Result<(), Error> { Ok(output_slatepack( owner_api, keychain_mask, &slate, dest.clone(), args.outfile, - true, + lock_outputs, false, args.slatepack_qr, )?) @@ -509,7 +508,11 @@ where let can_send = tor_config.send_tor(args.skip_tor); if test_mode || !can_send || dest.is_none() { - return output_sp(); + return output_sp(owner_api, !args.late_lock); + } + + if !args.late_lock { + owner_api.tx_lock_outputs(keychain_mask, &slate)?; } let dest = dest.as_ref().unwrap(); @@ -517,7 +520,6 @@ where match res { Ok(s) => { - owner_api.tx_lock_outputs(keychain_mask, &s)?; let ret_slate = owner_api.finalize_tx(keychain_mask, &s)?; let result = owner_api.post_tx(keychain_mask, &ret_slate, args.fluff); match result { @@ -532,7 +534,13 @@ where } Err(e) => { error!("Error sending slate sync: {}", e); - output_sp()?; + output_sp(owner_api, false)?; + if !args.late_lock { + println!( + "Outputs are locked. To unlock them, cancel with `cancel -t {}`.", + slate.id + ); + } } } Ok(()) @@ -581,7 +589,18 @@ where println!(); if !finalizing { - println!("Slatepack data follows. Please provide this output to the other party"); + let cancel_hint = if lock { + format!( + " or cancel it manually with `cancel -t {}` command", + slate.id + ) + } else { + "".to_string() + }; + println!( + "Slatepack data follows. Please provide this output to the other party{}.", + cancel_hint + ); } else { println!("Slatepack data follows."); } @@ -1074,7 +1093,6 @@ where selection_strategy_is_use_all: args.selection_strategy == "all", refresh_outputs_from_node: !info_updated, ttl_blocks: args.ttl_blocks, - send_args: None, ..Default::default() }; let result = owner_api.process_invoice_tx(keychain_mask, &slate, init_args); diff --git a/controller/src/controller.rs b/controller/src/controller.rs index ef61152..49fa040 100644 --- a/controller/src/controller.rs +++ b/controller/src/controller.rs @@ -136,23 +136,6 @@ fn init_tor_listener( Ok(process) } -/// Instantiate wallet Owner API for a single-use (command line) call -/// Return a function containing a loaded API context to call -pub fn owner_single_use( - wallet: Arc>>>, - keychain_mask: Option<&SecretKey>, - config_path: PathBuf, - f: F, -) -> Result<(), Error> -where - L: WalletLCProvider<'static, C, K> + 'static, - F: FnOnce(&mut Owner, Option<&SecretKey>) -> Result<(), Error>, - C: NodeClient + 'static, - K: Keychain + 'static, -{ - f(&mut Owner::new(wallet, None, config_path), keychain_mask) -} - /// Instantiate wallet Foreign API for a single-use (command line) call /// Return a function containing a loaded API context to call pub fn foreign_single_use<'a, L, F, C, K>( diff --git a/controller/tests/accounts.rs b/controller/tests/accounts.rs index 59645f8..fd19c28 100644 --- a/controller/tests/accounts.rs +++ b/controller/tests/accounts.rs @@ -19,7 +19,6 @@ extern crate grin_wallet_impls as impls; use grin_core as core; use grin_keychain as keychain; -use std::path::PathBuf; use self::core::global; use self::keychain::{ExtKeychain, Keychain}; @@ -49,7 +48,8 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -62,7 +62,8 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -79,48 +80,30 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height // test default accounts exist - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let accounts = api.accounts(m)?; - assert_eq!(accounts[0].label, "default"); - assert_eq!(accounts[0].path, ExtKeychain::derive_key_id(2, 0, 0, 0, 0)); - Ok(()) - }, - )?; + { + let accounts = api1.accounts(mask1)?; + assert_eq!(accounts[0].label, "default"); + assert_eq!(accounts[0].path, ExtKeychain::derive_key_id(2, 0, 0, 0, 0)); + } // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let new_path = api.create_account_path(m, "account1").unwrap(); - assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0)); - let new_path = api.create_account_path(m, "account2").unwrap(); - assert_eq!(new_path, ExtKeychain::derive_key_id(2, 2, 0, 0, 0)); - let new_path = api.create_account_path(m, "account3").unwrap(); - assert_eq!(new_path, ExtKeychain::derive_key_id(2, 3, 0, 0, 0)); - // trying to add same label again should fail - let res = api.create_account_path(m, "account1"); - assert!(res.is_err()); - Ok(()) - }, - )?; + { + let new_path = api1.create_account_path(mask1, "account1").unwrap(); + assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0)); + let new_path = api1.create_account_path(mask1, "account2").unwrap(); + assert_eq!(new_path, ExtKeychain::derive_key_id(2, 2, 0, 0, 0)); + let new_path = api1.create_account_path(mask1, "account3").unwrap(); + assert_eq!(new_path, ExtKeychain::derive_key_id(2, 3, 0, 0, 0)); + // trying to add same label again should fail + let res = api1.create_account_path(mask1, "account1"); + assert!(res.is_err()); + } // add account to wallet 2 - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let new_path = api.create_account_path(m, "listener_account").unwrap(); - assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0)); - Ok(()) - }, - )?; + { + let new_path = api2.create_account_path(mask2, "listener_account").unwrap(); + assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0)); + } // Default wallet 2 to listen on that account { @@ -144,120 +127,85 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false); // Should have 5 in account1 (5 spendable), 5 in account (2 spendable) - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, 12); - assert_eq!(wallet1_info.total, 5 * reward); - assert_eq!(wallet1_info.amount_currently_spendable, (5 - cm) * reward); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 5); - Ok(()) - }, - )?; + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, 12); + assert_eq!(wallet1_info.total, 5 * reward); + assert_eq!(wallet1_info.amount_currently_spendable, (5 - cm) * reward); + // check tx log as well + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert_eq!(txs.len(), 5); + } // now check second account { - // let mut w_lock = wallet1.lock(); - // let lc = w_lock.lc_provider()?; - // let w = lc.wallet_inst()?; wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("account1")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let labels: Vec<_> = api.accounts(m)?.into_iter().map(|a| a.label).collect(); - assert_eq!(labels, ["account1", "default", "account2", "account3"]); - // check last confirmed height on this account is different from above (should be 0) - let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?; - assert_eq!(wallet1_info.last_confirmed_height, 0); - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, 12); - assert_eq!(wallet1_info.total, 7 * reward); - assert_eq!(wallet1_info.amount_currently_spendable, 7 * reward); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 7); - Ok(()) - }, - )?; - + { + let labels: Vec<_> = api1.accounts(mask1)?.into_iter().map(|a| a.label).collect(); + assert_eq!(labels, ["account1", "default", "account2", "account3"]); + // check last confirmed height on this account is different from above (should be 0) + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, false, 1)?; + assert_eq!(wallet1_info.last_confirmed_height, 0); + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, 12); + assert_eq!(wallet1_info.total, 7 * reward); + assert_eq!(wallet1_info.amount_currently_spendable, 7 * reward); + // check tx log as well + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert_eq!(txs.len(), 7); + } // should be nothing in default account { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("default")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?; - assert_eq!(wallet1_info.last_confirmed_height, 0); - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, 12); - assert_eq!(wallet1_info.total, 0,); - assert_eq!(wallet1_info.amount_currently_spendable, 0,); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 0); - Ok(()) - }, - )?; + { + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, false, 1)?; + assert_eq!(wallet1_info.last_confirmed_height, 0); + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, 12); + assert_eq!(wallet1_info.total, 0,); + assert_eq!(wallet1_info.amount_currently_spendable, 0,); + // check tx log as well + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert_eq!(txs.len(), 0); + } // Send a tx to another wallet { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("account1")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let args = InitTxArgs { - src_acct_name: None, - amount: reward, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let mut slate = api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate)?; - api.tx_lock_outputs(m, &slate)?; - slate = api.finalize_tx(m, &slate)?; - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; - - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, 13); - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 9); - Ok(()) - }, - )?; + { + let args = InitTxArgs { + src_acct_name: None, + amount: reward, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + slate = client1.send_tx_slate_direct("wallet2", &slate)?; + api1.tx_lock_outputs(mask1, &slate)?; + slate = api1.finalize_tx(mask1, &slate)?; + api1.post_tx(mask1, &slate, false)?; + } + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, 13); + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert_eq!(txs.len(), 9); + } // Use the requested account's stored height { wallet_inst!(wallet1, w); @@ -272,59 +220,41 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("account2")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?; - assert_eq!(wallet1_info.last_confirmed_height, 12); - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert_eq!(wallet1_info.last_confirmed_height, 13); - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - println!("{:?}", txs); - assert_eq!(txs.len(), 5); - Ok(()) - }, - )?; + { + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, false, 1)?; + assert_eq!(wallet1_info.last_confirmed_height, 12); + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert_eq!(wallet1_info.last_confirmed_height, 13); + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + println!("{:?}", txs); + assert_eq!(txs.len(), 5); + } // wallet 2 should only have this tx on the listener account - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.last_confirmed_height, 13); - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - Ok(()) - }, - )?; + { + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.last_confirmed_height, 13); + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + } // Default account on wallet 2 should be untouched { wallet_inst!(wallet2, w); w.set_parent_key_id_by_name("default")?; } - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet2_info) = api.retrieve_summary_info(m, false, 1)?; - assert_eq!(wallet2_info.last_confirmed_height, 0); - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.last_confirmed_height, 13); - assert_eq!(wallet2_info.total, 0,); - assert_eq!(wallet2_info.amount_currently_spendable, 0,); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 0); - Ok(()) - }, - )?; + { + let (_, wallet2_info) = api2.retrieve_summary_info(mask2, false, 1)?; + assert_eq!(wallet2_info.last_confirmed_height, 0); + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.last_confirmed_height, 13); + assert_eq!(wallet2_info.total, 0,); + assert_eq!(wallet2_info.amount_currently_spendable, 0,); + // check tx log as well + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 0); + } // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/build_chain.rs b/controller/tests/build_chain.rs index 7120e44..12210e8 100644 --- a/controller/tests/build_chain.rs +++ b/controller/tests/build_chain.rs @@ -21,9 +21,8 @@ extern crate grin_wallet_impls as impls; extern crate grin_wallet_libwallet as libwallet; use grin_core as core; -use std::path::PathBuf; -use self::libwallet::{InitTxArgs, Slate}; +use self::libwallet::InitTxArgs; use impls::test_framework::{self, LocalWalletClient}; use rand::Rng; use std::sync::atomic::Ordering; @@ -48,7 +47,8 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); debug!("Mask1: {:?}", mask1); @@ -60,7 +60,8 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); debug!("Mask2: {:?}", mask2); @@ -74,25 +75,8 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal // Stop the scanning updater threads because it extends the time needed to build the chain // exponentially - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, _m| { - api.stop_updater()?; - Ok(()) - }, - )?; - - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, _m| { - api.stop_updater()?; - Ok(()) - }, - )?; + api1.stop_updater()?; + api2.stop_updater()?; // few values to keep things shorter let reward = core::consensus::REWARD; @@ -105,22 +89,14 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal let mut wallet_1_has_funds = false; // Check wallet 1 contents - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - debug!( - "Wallet 1 spendable - {}", - wallet1_info.amount_currently_spendable - ); - if wallet1_info.amount_currently_spendable > reward { - wallet_1_has_funds = true; - } - Ok(()) - }, - )?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + debug!( + "Wallet 1 spendable - {}", + wallet1_info.amount_currently_spendable + ); + if wallet1_info.amount_currently_spendable > reward { + wallet_1_has_funds = true; + } // let's say 1 in every 3 blocks has a transaction (i.e. random 0 here and wallet1 has funds) let transact = rng.gen_range(0, 2) == 0; @@ -134,30 +110,21 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal let num_txs = rng.gen_range(0, 3); for _ in 0..num_txs { let amount: u64 = rng.gen_range(1, 10_000_000_001); - let mut slate = Slate::blank(1, false); debug!("Creating TX for {}", amount); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount, - minimum_confirmations: 1, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; - slate = sender_api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 1, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + let slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; + api1.finalize_tx(mask1, &slate)?; } } // let logging finish diff --git a/controller/tests/build_output.rs b/controller/tests/build_output.rs index 491e916..798732d 100644 --- a/controller/tests/build_output.rs +++ b/controller/tests/build_output.rs @@ -25,7 +25,6 @@ use grin_util::{secp, ZeroingString}; use grin_wallet_libwallet as libwallet; use impls::test_framework::LocalWalletClient; use rand::{thread_rng, Rng}; -use std::path::PathBuf; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -37,7 +36,7 @@ use common::{clean_output_dir, create_wallet_proxy, setup}; fn build_output_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { // Generate seed so we can verify the blinding factor is derived correctly let seed: [u8; 32] = thread_rng().gen(); - let keychain = ExtKeychain::from_seed(&seed, false).unwrap(); + let keychain = ExtKeychain::from_seed(&seed, false)?; let mnemonic = mnemonic::from_entropy(&seed).unwrap(); // Create a new proxy to simulate server and wallet responses @@ -52,7 +51,8 @@ fn build_output_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error "wallet1", Some(ZeroingString::from(mnemonic)), &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -67,28 +67,19 @@ fn build_output_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit); let features = OutputFeatures::Plain; let amount = 60_000_000_000; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - let built_output = sender_api.build_output(m, features, amount)?; + let built_output = api1.build_output(mask1, features, amount)?; - let key_id = built_output.key_id; - assert_eq!(key_id.to_path(), ExtKeychainPath::new(3, 0, 0, 0, 0)); + let key_id = built_output.key_id; + assert_eq!(key_id.to_path(), ExtKeychainPath::new(3, 0, 0, 0, 0)); - let blind = built_output.blind; - let key = keychain.derive_key(amount, &key_id, SwitchCommitmentType::Regular)?; - assert_eq!(blind, BlindingFactor::from_secret_key(key.clone())); + let blind = built_output.blind; + let key = keychain.derive_key(amount, &key_id, SwitchCommitmentType::Regular)?; + assert_eq!(blind, BlindingFactor::from_secret_key(key.clone())); - let output = built_output.output; - assert_eq!(output.features(), features); - assert_eq!(output.commitment(), secp.commit(amount, key)?); - output.verify_proof()?; - - Ok(()) - }, - )?; + let output = built_output.output; + assert_eq!(output.features(), features); + assert_eq!(output.commitment(), secp.commit(amount, key)?); + output.verify_proof()?; // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/check.rs b/controller/tests/check.rs index d526335..6d7fbdb 100644 --- a/controller/tests/check.rs +++ b/controller/tests/check.rs @@ -27,7 +27,6 @@ use impls::test_framework::{self, LocalWalletClient}; use impls::{PathToSlate, SlatePutter as _}; use libwallet::{InitTxArgs, NodeClient}; use std::cmp; -use std::path::PathBuf; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -66,7 +65,8 @@ fn scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -77,7 +77,8 @@ fn scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -89,34 +90,22 @@ fn scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { }); // few values to keep things shorter - let reward = core::consensus::REWARD; - let cm = global::coinbase_maturity() as u64; // assume all testing precedes soft fork height + let reward = consensus::REWARD; + let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "named_account_1")?; - api.create_account_path(m, "account_2")?; - api.create_account_path(m, "account_3")?; - api.set_active_account(m, "named_account_1")?; - Ok(()) - }, - )?; + { + api1.create_account_path(mask1, "named_account_1")?; + api1.create_account_path(mask1, "account_2")?; + api1.create_account_path(mask1, "account_3")?; + api1.set_active_account(mask1, "named_account_1")?; + } // add account to wallet 2 - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account_1")?; - api.set_active_account(m, "account_1")?; - Ok(()) - }, - )?; + { + api2.create_account_path(mask2, "account_1")?; + api2.set_active_account(mask2, "account_1")?; + } // Do some mining let bh = 20u64; @@ -124,36 +113,21 @@ fn scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); // Sanity check contents - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward); - assert_eq!(wallet1_info.amount_currently_spendable, (bh - cm) * reward); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs); - assert_eq!(wallet1_info.total, c); - assert_eq!(txs.len(), bh as usize); - Ok(()) - }, - )?; + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward); + assert_eq!(wallet1_info.amount_currently_spendable, (bh - cm) * reward); + // check tx log as well + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs); + assert_eq!(wallet1_info.total, c); + assert_eq!(txs.len(), bh as usize); + } // Accidentally delete some outputs - let mut w1_outputs_commits = vec![]; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - w1_outputs_commits = api.retrieve_outputs(m, false, true, None)?.1; - Ok(()) - }, - )?; + let w1_outputs_commits = api1.retrieve_outputs(mask1, false, true, None)?.1; let w1_outputs: Vec = w1_outputs_commits.into_iter().map(|m| m.output).collect(); { @@ -170,108 +144,54 @@ fn scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { } // check we have a problem now - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs); - assert_ne!(wallet1_info.total, c); - Ok(()) - }, - )?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs); + assert_ne!(wallet1_info.total, c); // this should restore our missing outputs - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, true)?; - Ok(()) - }, - )?; + api1.scan(mask1, None, true)?; // check our outputs match again - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.total, bh * reward); - // And check account names haven't been splatted - let accounts = api.accounts(m)?; - assert_eq!(accounts.len(), 4); - assert!(api.set_active_account(m, "account_1").is_err()); - assert!(api.set_active_account(m, "named_account_1").is_ok()); - Ok(()) - }, - )?; - + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.total, bh * reward); + // And check account names haven't been splatted + let accounts = api1.accounts(mask1)?; + assert_eq!(accounts.len(), 4); + assert!(api1.set_active_account(mask1, "account_1").is_err()); + assert!(api1.set_active_account(mask1, "named_account_1").is_ok()); + } // perform a transaction, but don't let it finish - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // send to send - let args = InitTxArgs { - src_acct_name: None, - amount: reward * 2, - minimum_confirmations: cm, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - // output tx file - let send_file = format!("{}/part_tx_1.tx", test_dir); - PathToSlate(send_file.into()).put_tx(&slate, false)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + { + // send to send + let args = InitTxArgs { + src_acct_name: None, + amount: reward * 2, + minimum_confirmations: cm, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate = api1.init_send_tx(mask1, args)?; + // output tx file + let send_file = format!("{}/part_tx_1.tx", test_dir); + PathToSlate(send_file.into()).put_tx(&slate, false)?; + api1.tx_lock_outputs(mask1, &slate)?; + } // check we're all locked - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.amount_currently_spendable, 0); - Ok(()) - }, - )?; - + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.amount_currently_spendable, 0); // unlock/restore - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, true)?; - Ok(()) - }, - )?; + api1.scan(mask1, None, true)?; // check spendable amount again - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert_eq!(wallet1_info.amount_currently_spendable, (bh - cm) * reward); - Ok(()) - }, - )?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert_eq!(wallet1_info.amount_currently_spendable, (bh - cm) * reward); // let logging finish stopper.store(false, Ordering::Relaxed); @@ -300,7 +220,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "miner", None, &mut wallet_proxy, - false + false, + _m_api ); let miner_mask = (&miner_mask_i).as_ref(); @@ -313,7 +234,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet1", seed_phrase, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -324,7 +246,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet2", seed_phrase, &mut wallet_proxy, - false + false, + _api2 ); let mask2 = (&mask2_i).as_ref(); // we'll restore into here @@ -336,7 +259,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet3", seed_phrase, &mut wallet_proxy, - false + false, + api3 ); let mask3 = (&mask3_i).as_ref(); // also restore into here @@ -348,7 +272,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet4", seed_phrase, &mut wallet_proxy, - false + false, + api4 ); let mask4 = (&mask4_i).as_ref(); // Simulate a recover from seed without restore into here @@ -360,7 +285,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet5", seed_phrase, &mut wallet_proxy, - false + false, + api5 ); //simulate a recover from seed without restore into here let mask5 = (&mask5_i).as_ref(); @@ -372,7 +298,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet6", seed_phrase, &mut wallet_proxy, - false + false, + api6 ); let mask6 = (&mask6_i).as_ref(); @@ -384,7 +311,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet7", seed_phrase, &mut wallet_proxy, - false + false, + api7 ); let mask7 = (&mask7_i).as_ref(); create_wallet_and_add!( @@ -395,7 +323,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet8", seed_phrase, &mut wallet_proxy, - false + false, + api8 ); let mask8 = (&mask8_i).as_ref(); create_wallet_and_add!( @@ -406,7 +335,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet9", seed_phrase, &mut wallet_proxy, - false + false, + api9 ); let mask9 = (&mask9_i).as_ref(); create_wallet_and_add!( @@ -417,7 +347,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er "wallet10", seed_phrase, &mut wallet_proxy, - false + false, + api10 ); let mask10 = (&mask10_i).as_ref(); @@ -468,18 +399,10 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er bh += 3; // 0) Check repair when all is okay should leave wallet contents alone - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, true)?; - let info = wallet_info!(wallet1.clone(), m)?; - assert_eq!(info.amount_currently_spendable, base_amount * 6); - assert_eq!(info.total, base_amount * 6); - Ok(()) - }, - )?; + api1.scan(mask1, None, true)?; + let info = wallet_info!(wallet1.clone(), mask1)?; + assert_eq!(info.amount_currently_spendable, base_amount * 6); + assert_eq!(info.total, base_amount * 6); // send some funds to wallet 2 send_to_dest!( @@ -523,53 +446,21 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er // seed + BIP32 path. // 1) a full restore should recover all of them: - wallet::controller::owner_single_use( - wallet3.clone(), - mask3, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, false)?; - Ok(()) - }, - )?; + api3.scan(mask3, None, false)?; - wallet::controller::owner_single_use( - wallet3.clone(), - mask3, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet3.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 6); - assert_eq!(info.amount_currently_spendable, base_amount * 21); - assert_eq!(info.total, base_amount * 21); - Ok(()) - }, - )?; + let info = wallet_info!(wallet3.clone(), mask3)?; + let outputs = api3.retrieve_outputs(mask3, true, false, None)?.1; + assert_eq!(outputs.len(), 6); + assert_eq!(info.amount_currently_spendable, base_amount * 21); + assert_eq!(info.total, base_amount * 21); // 2) scan should recover them into a single wallet - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, true)?; - Ok(()) - }, - )?; + api1.scan(mask1, None, true)?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet1.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 6); - assert_eq!(info.amount_currently_spendable, base_amount * 21); - Ok(()) - }, - )?; + let info = wallet_info!(wallet1.clone(), mask1)?; + let outputs = api1.retrieve_outputs(mask1, true, false, None)?.1; + assert_eq!(outputs.len(), 6); + assert_eq!(info.amount_currently_spendable, base_amount * 21); // 3) If I recover from seed and start using the wallet without restoring, // scan should restore the older outputs @@ -601,41 +492,17 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false); bh += cm as u64; - wallet::controller::owner_single_use( - wallet4.clone(), - mask4, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet4.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 9); - assert_eq!(info.amount_currently_spendable, base_amount * 45); - Ok(()) - }, - )?; + let info = wallet_info!(wallet4.clone(), mask4)?; + let outputs = api4.retrieve_outputs(mask4, true, false, None)?.1; + assert_eq!(outputs.len(), 9); + assert_eq!(info.amount_currently_spendable, base_amount * 45); - wallet::controller::owner_single_use( - wallet5.clone(), - mask5, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, false)?; - Ok(()) - }, - )?; + api5.scan(mask5, None, false)?; - wallet::controller::owner_single_use( - wallet5.clone(), - mask5, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet5.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 9); - assert_eq!(info.amount_currently_spendable, base_amount * (45)); - Ok(()) - }, - )?; + let info = wallet_info!(wallet5.clone(), mask5)?; + let outputs = api5.retrieve_outputs(mask5, true, false, None)?.1; + assert_eq!(outputs.len(), 9); + assert_eq!(info.amount_currently_spendable, base_amount * (45)); // 4) If I recover from seed and start using the wallet without restoring, // scan should restore the older outputs @@ -662,50 +529,20 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er )?; bh += 3; - let _ = test_framework::award_blocks_to_wallet( - &chain, - miner.clone(), - miner_mask, - cm as usize, - false, - ); + let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false); bh += cm as u64; - wallet::controller::owner_single_use( - wallet6.clone(), - mask6, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet6.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 12); - assert_eq!(info.amount_currently_spendable, base_amount * 78); - Ok(()) - }, - )?; + let info = wallet_info!(wallet6.clone(), mask6)?; + let outputs = api6.retrieve_outputs(mask6, true, false, None)?.1; + assert_eq!(outputs.len(), 12); + assert_eq!(info.amount_currently_spendable, base_amount * 78); - wallet::controller::owner_single_use( - wallet6.clone(), - mask6, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, true)?; - Ok(()) - }, - )?; + api6.scan(mask6, None, true)?; - wallet::controller::owner_single_use( - wallet6.clone(), - mask6, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet6.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 12); - assert_eq!(info.amount_currently_spendable, base_amount * (78)); - Ok(()) - }, - )?; + let info = wallet_info!(wallet6.clone(), mask6)?; + let outputs = api6.retrieve_outputs(mask6, true, false, None)?.1; + assert_eq!(outputs.len(), 12); + assert_eq!(info.amount_currently_spendable, base_amount * (78)); // 5) Start using same seed with a different account, amounts should // be distinct and restore should return funds from other account @@ -734,16 +571,8 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er bh += 3; // mix it up a bit - wallet::controller::owner_single_use( - wallet7.clone(), - mask7, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account_1")?; - api.set_active_account(m, "account_1")?; - Ok(()) - }, - )?; + api7.create_account_path(mask7, "account_1")?; + api7.set_active_account(mask7, "account_1")?; send_to_dest!( miner.clone(), @@ -772,57 +601,33 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false); bh += cm as u64; - wallet::controller::owner_single_use( - wallet7.clone(), - mask7, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet7.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 3); - assert_eq!(info.amount_currently_spendable, base_amount * 6); - api.set_active_account(m, "default")?; - let info = wallet_info!(wallet7.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 15); - assert_eq!(info.amount_currently_spendable, base_amount * 120); - Ok(()) - }, - )?; + let info = wallet_info!(wallet7.clone(), mask7)?; + let outputs = api7.retrieve_outputs(mask7, true, false, None)?.1; + assert_eq!(outputs.len(), 3); + assert_eq!(info.amount_currently_spendable, base_amount * 6); + api7.set_active_account(mask7, "default")?; + let info = wallet_info!(wallet7.clone(), mask7)?; + let outputs = api7.retrieve_outputs(mask7, true, false, None)?.1; + assert_eq!(outputs.len(), 15); + assert_eq!(info.amount_currently_spendable, base_amount * 120); - wallet::controller::owner_single_use( - wallet8.clone(), - mask8, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, false)?; - let info = wallet_info!(wallet8.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 15); - assert_eq!(info.amount_currently_spendable, base_amount * 120); - api.set_active_account(m, "account_1")?; - let info = wallet_info!(wallet8.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 3); - assert_eq!(info.amount_currently_spendable, base_amount * 6); - Ok(()) - }, - )?; + api8.scan(mask8, None, false)?; + let info = wallet_info!(wallet8.clone(), mask8)?; + let outputs = api8.retrieve_outputs(mask8, true, false, None)?.1; + assert_eq!(outputs.len(), 15); + assert_eq!(info.amount_currently_spendable, base_amount * 120); + api8.set_active_account(mask8, "account_1")?; + let info = wallet_info!(wallet8.clone(), mask8)?; + let outputs = api8.retrieve_outputs(mask8, true, false, None)?.1; + assert_eq!(outputs.len(), 3); + assert_eq!(info.amount_currently_spendable, base_amount * 6); // 6) Start using same seed with a different account, now overwriting // ids on account 2 as well, scan should get all outputs created // to now into 2 accounts - wallet::controller::owner_single_use( - wallet9.clone(), - mask9, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account_1")?; - api.set_active_account(m, "account_1")?; - Ok(()) - }, - )?; + api9.create_account_path(mask9, "account_1")?; + api9.set_active_account(mask9, "account_1")?; send_to_dest!( miner.clone(), @@ -848,53 +653,37 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er bh += 3; let _bh = bh; - wallet::controller::owner_single_use( - wallet9.clone(), - mask9, - PathBuf::from(test_dir), - |api, m| { - let info = wallet_info!(wallet9.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 6); - assert_eq!(info.amount_currently_spendable, base_amount * 21); - api.scan(m, None, true)?; - let info = wallet_info!(wallet9.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 6); - assert_eq!(info.amount_currently_spendable, base_amount * 21); + let info = wallet_info!(wallet9.clone(), mask9)?; + let outputs = api9.retrieve_outputs(mask9, true, false, None)?.1; + assert_eq!(outputs.len(), 6); + assert_eq!(info.amount_currently_spendable, base_amount * 21); + api9.scan(mask9, None, true)?; + let info = wallet_info!(wallet9.clone(), mask9)?; + let outputs = api9.retrieve_outputs(mask9, true, false, None)?.1; + assert_eq!(outputs.len(), 6); + assert_eq!(info.amount_currently_spendable, base_amount * 21); - api.set_active_account(m, "default")?; - let info = wallet_info!(wallet9.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 15); - assert_eq!(info.amount_currently_spendable, base_amount * 120); - Ok(()) - }, - )?; + api9.set_active_account(mask9, "default")?; + let info = wallet_info!(wallet9.clone(), mask9)?; + let outputs = api9.retrieve_outputs(mask9, true, false, None)?.1; + assert_eq!(outputs.len(), 15); + assert_eq!(info.amount_currently_spendable, base_amount * 120); let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false); // 7) Ensure scan creates missing accounts - wallet::controller::owner_single_use( - wallet10.clone(), - mask10, - PathBuf::from(test_dir), - |api, m| { - api.scan(m, None, true)?; - api.set_active_account(m, "account_1")?; - let info = wallet_info!(wallet10.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 6); - assert_eq!(info.amount_currently_spendable, base_amount * 21); + api10.scan(mask10, None, true)?; + api10.set_active_account(mask10, "account_1")?; + let info = wallet_info!(wallet10.clone(), mask10)?; + let outputs = api10.retrieve_outputs(mask10, true, false, None)?.1; + assert_eq!(outputs.len(), 6); + assert_eq!(info.amount_currently_spendable, base_amount * 21); - api.set_active_account(m, "default")?; - let info = wallet_info!(wallet10.clone(), m)?; - let outputs = api.retrieve_outputs(m, true, false, None)?.1; - assert_eq!(outputs.len(), 15); - assert_eq!(info.amount_currently_spendable, base_amount * 120); - Ok(()) - }, - )?; + api10.set_active_account(mask10, "default")?; + let info = wallet_info!(wallet10.clone(), mask10)?; + let outputs = api10.retrieve_outputs(mask10, true, false, None)?.1; + assert_eq!(outputs.len(), 15); + assert_eq!(info.amount_currently_spendable, base_amount * 120); // let logging finish stopper.store(false, Ordering::Relaxed); @@ -918,7 +707,8 @@ fn output_scanning_impl(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet1", None, &mut wallet_proxy, - false + false, + _api1 ); let mask1 = (&mask1_i).as_ref(); thread::spawn(move || { @@ -952,7 +742,7 @@ fn output_scanning_impl(test_dir: &'static str) -> Result<(), libwallet::Error> ); assert_eq!(outputs.2.len(), 14); - // mid range + // mid-range let ranges = client1.height_range_to_pmmr_indices(5, Some(14))?; assert_eq!(ranges, (8, 25)); let outputs = client1.get_outputs_by_pmmr_index(ranges.0, Some(ranges.1), 1000)?; @@ -1002,7 +792,8 @@ fn multi_batch_scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -1017,19 +808,10 @@ fn multi_batch_scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); - let mut output_commits = vec![]; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, info) = api.retrieve_summary_info(m, true, 1)?; - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, bh * reward); - output_commits = api.retrieve_outputs(m, false, true, None)?.1; - Ok(()) - }, - )?; + let (_, info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, bh * reward); + let output_commits = api1.retrieve_outputs(mask1, false, true, None)?.1; { wallet_inst!(wallet1, w); @@ -1076,18 +858,10 @@ fn multi_batch_scan_impl(test_dir: &'static str) -> Result<(), libwallet::Error> } assert!(batches > 1); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, restored_outputs) = api.retrieve_outputs(m, false, true, None)?; - let (_, info) = api.retrieve_summary_info(m, false, 1)?; - assert_eq!(info.total, bh * reward); - assert_eq!(restored_outputs.len(), bh as usize); - Ok(()) - }, - )?; + let (_, restored_outputs) = api1.retrieve_outputs(mask1, false, true, None)?; + let (_, info) = api1.retrieve_summary_info(mask1, false, 1)?; + assert_eq!(info.total, bh * reward); + assert_eq!(restored_outputs.len(), bh as usize); stopper.store(false, Ordering::Relaxed); thread::sleep(Duration::from_millis(200)); @@ -1109,7 +883,8 @@ fn restore_corrupted_outputs_across_batches_impl( "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -1124,18 +899,9 @@ fn restore_corrupted_outputs_across_batches_impl( let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); - let mut output_commits = vec![]; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, info) = api.retrieve_summary_info(m, true, 1)?; - assert_eq!(info.total, bh * reward); - output_commits = api.retrieve_outputs(m, false, true, None)?.1; - Ok(()) - }, - )?; + let (_, info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert_eq!(info.total, bh * reward); + let output_commits = api1.retrieve_outputs(mask1, false, true, None)?.1; { wallet_inst!(wallet1, w); @@ -1173,30 +939,22 @@ fn restore_corrupted_outputs_across_batches_impl( assert_eq!(last_scanned.hash, ""); } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, outputs_after_first_batch) = api.retrieve_outputs(m, false, false, None)?; - assert_eq!(outputs_after_first_batch.len(), (bh - 1) as usize); + let (_, outputs_after_first_batch) = api1.retrieve_outputs(mask1, false, false, None)?; + assert_eq!(outputs_after_first_batch.len(), (bh - 1) as usize); - let (_, info) = api.retrieve_summary_info(m, true, 1)?; - let (_, restored_outputs) = api.retrieve_outputs(m, false, true, None)?; - let unique_keys = restored_outputs - .iter() - .map(|o| o.output.key_id.clone()) - .collect::>(); + let (_, info) = api1.retrieve_summary_info(mask1, true, 1)?; + let (_, restored_outputs) = api1.retrieve_outputs(mask1, false, true, None)?; + let unique_keys = restored_outputs + .iter() + .map(|o| o.output.key_id.clone()) + .collect::>(); - assert_eq!(info.total, bh * reward); - assert_eq!(restored_outputs.len(), bh as usize); - assert_eq!(unique_keys.len(), bh as usize); - assert!(restored_outputs - .iter() - .all(|o| o.output.status == libwallet::OutputStatus::Unspent)); - Ok(()) - }, - )?; + assert_eq!(info.total, bh * reward); + assert_eq!(restored_outputs.len(), bh as usize); + assert_eq!(unique_keys.len(), bh as usize); + assert!(restored_outputs + .iter() + .all(|o| o.output.status == libwallet::OutputStatus::Unspent)); stopper.store(false, Ordering::Relaxed); thread::sleep(Duration::from_millis(200)); diff --git a/controller/tests/common/mod.rs b/controller/tests/common/mod.rs index 725160e..716b79e 100644 --- a/controller/tests/common/mod.rs +++ b/controller/tests/common/mod.rs @@ -19,11 +19,15 @@ extern crate grin_wallet_libwallet as libwallet; use grin_core as core; use grin_keychain as keychain; use grin_util as util; +use std::env; +use std::path::PathBuf; use self::core::global; use self::core::global::ChainTypes; use self::keychain::ExtKeychain; use self::libwallet::WalletInst; +use grin_wallet_api::Owner; +use grin_wallet_config::{initial_setup_wallet, GRIN_WALLET_DIR}; use impls::test_framework::{LocalWalletClient, WalletProxy}; use impls::{DefaultLCProvider, DefaultWalletImpl}; use std::sync::Arc; @@ -41,9 +45,9 @@ macro_rules! wallet_inst { #[macro_export] macro_rules! create_wallet_and_add { - ($client:ident, $wallet: ident, $mask: ident, $test_dir: expr, $name: expr, $seed_phrase: expr, $proxy: expr, $create_mask: expr) => { + ($client:ident, $wallet: ident, $mask: ident, $test_dir: expr, $name: expr, $seed_phrase: expr, $proxy: expr, $create_mask: expr, $owner_api: ident) => { let $client = LocalWalletClient::new($name, $proxy.tx.clone()); - let ($wallet, $mask) = common::create_local_wallet( + let ($wallet, $mask, $owner_api) = common::create_local_wallet( $test_dir, $name, $seed_phrase.clone(), @@ -125,7 +129,18 @@ pub fn create_local_wallet( >, >, Option, + Owner, LocalWalletClient, ExtKeychain>, ) { + let mut current_dir; + current_dir = env::current_dir().unwrap_or_else(|e| { + panic!("Error creating config file: {}", e); + }); + current_dir.push(test_dir); + current_dir.push(name); + let config = + initial_setup_wallet(&ChainTypes::AutomatedTesting, Some(current_dir), true).unwrap(); + let mut wallet_config = config.clone().members.wallet; + let mut wallet = Box::new(DefaultWalletImpl::::new(client).unwrap()) as Box< dyn WalletInst< @@ -135,13 +150,25 @@ pub fn create_local_wallet( >, >; let lc = wallet.lc_provider().unwrap(); - let _ = lc.set_top_level_directory(&format!("{}/{}", test_dir, name)); + // legacy hack to avoid the need for changes in existing grin-wallet.toml files + // remove `wallet_data` from end of path as + // new lifecycle provider assumes grin_wallet.toml is in root of data directory + let mut top_level_wallet_dir = PathBuf::from(wallet_config.clone().data_file_dir); + if top_level_wallet_dir.ends_with(GRIN_WALLET_DIR) { + top_level_wallet_dir.pop(); + wallet_config.data_file_dir = top_level_wallet_dir.to_str().unwrap().into(); + } + let _ = lc.set_top_level_directory(&wallet_config.data_file_dir); lc.create_wallet(None, mnemonic, 32, ZeroingString::from(""), false) .unwrap(); let mask = lc .open_wallet(None, ZeroingString::from(""), create_mask, false) .unwrap(); - (Arc::new(Mutex::new(wallet)), mask) + + let wallet = Arc::new(Mutex::new(wallet)); + let owner_api = Owner::new(wallet.clone(), None, config.config_file_path.clone()); + + (wallet, mask, owner_api) } #[allow(dead_code)] diff --git a/controller/tests/config_api.rs b/controller/tests/config_api.rs index 5936a7f..6d1ac20 100644 --- a/controller/tests/config_api.rs +++ b/controller/tests/config_api.rs @@ -21,9 +21,9 @@ use config::config::{get_global_config, reload_global_config}; use config::GlobalWalletConfig; use impls::test_framework::LocalWalletClient; use libwallet::{InitTxArgs, InitTxSendArgs}; -use std::fs; use std::path::{Path, PathBuf}; use std::sync::atomic::Ordering; +use std::{env, fs}; mod common; use common::{clean_output_dir, create_wallet_proxy, setup}; @@ -63,7 +63,8 @@ fn tor_disable() { "wallet", None, &mut wallet_proxy, - false + false, + _api ); let path = PathBuf::from(test_dir).join("grin-wallet.toml"); let mut config = @@ -94,6 +95,7 @@ fn tor_disable() { ); assert_eq!(cached, stored); + drop(_api); drop(owner); drop(wallet); drop(wallet_proxy); @@ -113,7 +115,8 @@ fn send_preflight() { "wallet", None, &mut wallet_proxy, - false + false, + _api ); let owner = api::Owner::new( wallet.clone(), @@ -144,6 +147,7 @@ fn send_preflight() { assert!(after_txs.is_empty()); assert_eq!(snapshot(&wallet_data), before_data); + drop(_api); drop(owner); drop(wallet); drop(wallet_proxy); @@ -163,9 +167,13 @@ fn directory_change() { "wallet", None, &mut wallet_proxy, - false + false, + _api ); - let old_dir = PathBuf::from(test_dir).join("wallet"); + let old_dir = env::current_dir().unwrap_or_else(|e| { + panic!("Error creating config file: {}", e); + }); + let old_dir = old_dir.join(test_dir).join("wallet"); let old_config = old_dir.join("grin-wallet.toml"); let new_dir = PathBuf::from(test_dir).join("other"); let owner = api::Owner::new(wallet.clone(), None, old_config.clone()); diff --git a/controller/tests/file.rs b/controller/tests/file.rs index e313407..a4e1fc4 100644 --- a/controller/tests/file.rs +++ b/controller/tests/file.rs @@ -27,7 +27,7 @@ use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; -use grin_wallet_libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate}; +use grin_wallet_libwallet::{InitTxArgs, IssueInvoiceTxArgs}; #[macro_use] mod common; @@ -50,7 +50,8 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -61,7 +62,8 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -76,28 +78,12 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), let reward = core::consensus::REWARD; // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; // add some accounts - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account1")?; - api.create_account_path(m, "account2")?; - Ok(()) - }, - )?; + api2.create_account_path(mask2, "account1")?; + api2.create_account_path(mask2, "account2")?; // Get some mining done { @@ -122,32 +108,24 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), }; // Should have 5 in account1 (5 spendable), 5 in account (2 spendable) - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward); - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - // output tx file - PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward); + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate = api1.init_send_tx(mask1, args)?; + // output tx file + PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?; + api1.tx_lock_outputs(mask1, &slate)?; // Get some mining done { @@ -169,52 +147,28 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), }, )?; - // wallet 1 finalises and posts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let mut slate = PathToSlate(receive_file.into()).get_tx()?.0; - slate = api.finalize_tx(m, &slate)?; - // Output final file for reference - PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?; - api.post_tx(m, &slate, false)?; - bh += 1; - Ok(()) - }, - )?; + // wallet 1 finalizes and posts + let mut slate = PathToSlate(receive_file.into()).get_tx()?.0; + slate = api1.finalize_tx(mask1, &slate)?; + // Output final file for reference + PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?; + api1.post_tx(mask1, &slate, false)?; + bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; // Check total in mining account - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward - reward * 2); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward - reward * 2); // Check total in 'wallet 2' account - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.last_confirmed_height, bh); - assert_eq!(wallet2_info.total, 2 * reward); - Ok(()) - }, - )?; + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.last_confirmed_height, bh); + assert_eq!(wallet2_info.total, 2 * reward); // Now other types of exchange, for reference // Invoice transaction @@ -231,44 +185,27 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), ), }; - let mut slate = Slate::blank(2, true); + let args = IssueInvoiceTxArgs { + amount: 1000000000, + ..Default::default() + }; + let mut slate = api2.issue_invoice_tx(mask2, args)?; + PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?; - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let args = IssueInvoiceTxArgs { - amount: 1000000000, - ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?; - Ok(()) - }, - )?; + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + slate = PathToSlate((&send_file).into()).get_tx()?.0; + slate = api1.process_invoice_tx(mask1, &slate, args)?; + api1.tx_lock_outputs(mask1, &slate)?; + PathToSlate((&receive_file).into()).put_tx(&slate, use_bin)?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - slate = PathToSlate((&send_file).into()).get_tx()?.0; - slate = api.process_invoice_tx(m, &slate, args)?; - api.tx_lock_outputs(m, &slate)?; - PathToSlate((&receive_file).into()).put_tx(&slate, use_bin)?; - Ok(()) - }, - )?; wallet::controller::foreign_single_use( wallet2.clone(), PathBuf::from(test_dir), @@ -281,15 +218,8 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), Ok(()) }, )?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; + + api1.post_tx(mask1, &slate, false)?; // Standard, with payment proof let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); @@ -305,40 +235,22 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), format!("{}/standard_pp_S3.txbin", test_dir), ), }; - let mut slate = Slate::blank(2, true); - let mut address = None; - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - address = Some(api.get_slatepack_address(m, 0)?); - Ok(()) - }, - )?; + let address = Some(api2.get_slatepack_address(mask2, 0)?); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - payment_proof_recipient_address: address.clone(), - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + payment_proof_recipient_address: address.clone(), + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + PathToSlate((&send_file).into()).put_tx(&slate, use_bin)?; + api1.tx_lock_outputs(mask1, &slate)?; wallet::controller::foreign_single_use( wallet2.clone(), @@ -352,21 +264,12 @@ fn file_exchange_test_impl(test_dir: &'static str, use_bin: bool) -> Result<(), }, )?; - // wallet 1 finalises and posts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - slate = PathToSlate(receive_file.into()).get_tx()?.0; - slate = api.finalize_tx(m, &slate)?; - // Output final file for reference - PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?; - api.post_tx(m, &slate, false)?; - bh += 1; - Ok(()) - }, - )?; + // wallet 1 finalizes and posts + slate = PathToSlate(receive_file.into()).get_tx()?.0; + slate = api1.finalize_tx(mask1, &slate)?; + // Output final file for reference + PathToSlate((&final_file).into()).put_tx(&slate, use_bin)?; + api1.post_tx(mask1, &slate, false)?; // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/invoice.rs b/controller/tests/invoice.rs index b48f66e..8b76998 100644 --- a/controller/tests/invoice.rs +++ b/controller/tests/invoice.rs @@ -22,7 +22,7 @@ use grin_wallet_libwallet as libwallet; use std::path::PathBuf; use impls::test_framework::{self, LocalWalletClient}; -use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate, SlateState}; +use libwallet::{InitTxArgs, IssueInvoiceTxArgs, SlateState}; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -46,7 +46,8 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -57,7 +58,8 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet2", None, &mut wallet_proxy, - true + true, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -72,16 +74,8 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let reward = core::consensus::REWARD; // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; // Get some mining done { @@ -93,46 +87,28 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, _bh as usize, false); // Sanity check wallet 1 contents - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, _bh); - assert_eq!(wallet1_info.total, _bh * reward); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, _bh); + assert_eq!(wallet1_info.total, _bh * reward); - let mut slate = Slate::blank(2, true); - - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let error = api - .issue_invoice_tx( - m, - IssueInvoiceTxArgs { - amount: 0, - ..Default::default() - }, - ) - .unwrap_err(); - assert_eq!(error, libwallet::Error::InvalidAmount); - - // Wallet 2 inititates an invoice transaction, requesting payment - let args = IssueInvoiceTxArgs { - amount: reward * 2, + let error = api2 + .issue_invoice_tx( + mask2, + IssueInvoiceTxArgs { + amount: 0, ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - Ok(()) - }, - )?; + }, + ) + .unwrap_err(); + assert_eq!(error, libwallet::Error::InvalidAmount); + + // Wallet 2 initiates an invoice transaction, requesting payment + let args = IssueInvoiceTxArgs { + amount: reward * 2, + ..Default::default() + }; + let mut slate = api2.issue_invoice_tx(mask2, args)?; assert_eq!(slate.state, SlateState::Invoice1); let receive_result = wallet::controller::foreign_single_use( @@ -142,16 +118,8 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { |api| api.receive_tx(&slate, None, None).map(|_| ()), ); assert_eq!(receive_result, Err(libwallet::Error::SlateState)); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, txs) = api.retrieve_txs(m, false, None, Some(slate.id), None)?; - assert!(txs.is_empty()); - Ok(()) - }, - )?; + let (_, txs) = api1.retrieve_txs(mask1, false, None, Some(slate.id), None)?; + assert!(txs.is_empty()); // receive must reject every slate state except S1 for state in [ @@ -173,51 +141,34 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { assert_eq!(res, Err(libwallet::Error::SlateState), "state {}", state); } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // Wallet 1 receives the invoice transaction - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let mut zero_amount_slate = slate.clone(); - zero_amount_slate.amount = 0; - assert_eq!( - api.process_invoice_tx(m, &zero_amount_slate, args.clone()) - .unwrap_err(), - libwallet::Error::InvalidAmount - ); - - slate = api.process_invoice_tx(m, &slate, args)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + // Wallet 1 receives the invoice transaction + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let mut zero_amount_slate = slate.clone(); + zero_amount_slate.amount = 0; + assert_eq!( + api1.process_invoice_tx(mask1, &zero_amount_slate, args.clone()) + .unwrap_err(), + libwallet::Error::InvalidAmount + ); + slate = api1.process_invoice_tx(mask1, &slate, args)?; + api1.tx_lock_outputs(mask1, &slate)?; assert_eq!(slate.state, SlateState::Invoice2); - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - assert_eq!( - api.tx_lock_outputs(m, &slate), - Err(libwallet::Error::SlateState) - ); - let (_, txs) = api.retrieve_txs(m, false, None, None, None)?; - assert_eq!(txs.len(), 1); - assert_eq!(txs[0].tx_type, libwallet::TxLogEntryType::TxReceived); - Ok(()) - }, - )?; + assert_eq!( + api2.tx_lock_outputs(mask2, &slate), + Err(libwallet::Error::SlateState) + ); + let (_, txs) = api2.retrieve_txs(mask2, false, None, None, None)?; + assert_eq!(txs.len(), 1); + assert_eq!(txs[0].tx_type, libwallet::TxLogEntryType::TxReceived); // wallet 2 finalizes and posts wallet::controller::foreign_single_use( @@ -233,86 +184,54 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { assert_eq!(slate.state, SlateState::Invoice3); // wallet 1 posts so wallet 2 doesn't get the mined amount - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; + api1.post_tx(mask1, &slate, false)?; _bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); _bh += 3; // Check transaction log for wallet 2 - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - assert!(txs.len() == 1); - println!( - "last confirmed height: {}, bh: {}", - wallet2_info.last_confirmed_height, _bh - ); - assert!(refreshed); - Ok(()) - }, - )?; + let (_, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert!(refreshed); + assert_eq!(txs.len(), 1); + println!( + "last confirmed height: {}, bh: {}", + wallet2_info.last_confirmed_height, _bh + ); + assert!(refreshed); // Check transaction log for wallet 1, ensure only 1 entry // exists - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - assert_eq!(txs.len() as u64, _bh + 1); - println!( - "Wallet 1: last confirmed height: {}, bh: {}", - wallet1_info.last_confirmed_height, _bh - ); - Ok(()) - }, - )?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert!(refreshed); + assert_eq!(txs.len() as u64, _bh + 1); + println!( + "Wallet 1: last confirmed height: {}, bh: {}", + wallet1_info.last_confirmed_height, _bh + ); // Test self-sending - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // Wallet 1 inititates an invoice transaction, requesting payment - let args = IssueInvoiceTxArgs { - amount: reward * 2, - ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - // Wallet 1 receives the invoice transaction - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - println!("Self invoice slate init: {}", slate); - slate = api.process_invoice_tx(m, &slate, args)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + // Wallet 1 initiates an invoice transaction, requesting payment + let args = IssueInvoiceTxArgs { + amount: reward * 2, + ..Default::default() + }; + slate = api1.issue_invoice_tx(mask1, args)?; + // Wallet 1 receives the invoice transaction + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + println!("Self invoice slate init: {}", slate); + slate = api1.process_invoice_tx(mask1, &slate, args)?; + api1.tx_lock_outputs(mask1, &slate)?; println!("Self invoice slate after process: {}", slate); @@ -329,112 +248,66 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { )?; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); - //bh += 3; - // As above, but use owner API to finalize - let mut slate = Slate::blank(2, true); - - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - // Wallet 2 inititates an invoice transaction, requesting payment - let args = IssueInvoiceTxArgs { - amount: reward * 2, - ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - Ok(()) - }, - )?; + // Wallet 2 initiates an invoice transaction, requesting payment + let args = IssueInvoiceTxArgs { + amount: reward * 2, + ..Default::default() + }; + slate = api2.issue_invoice_tx(mask2, args)?; assert_eq!(slate.state, SlateState::Invoice1); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // Wallet 1 receives the invoice transaction - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - slate = api.process_invoice_tx(m, &slate, args)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + // Wallet 1 receives the invoice transaction + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + slate = api1.process_invoice_tx(mask1, &slate, args)?; + api1.tx_lock_outputs(mask1, &slate)?; assert_eq!(slate.state, SlateState::Invoice2); - // wallet 2 finalizes via owner API - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - // Wallet 2 receives the invoice transaction - slate = api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; + // Wallet 2 receives and finalizes via owner API + slate = api2.finalize_tx(mask2, &slate)?; assert_eq!(slate.state, SlateState::Invoice3); // test that payee can only cancel once let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); _bh += 3; - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - // Wallet 2 inititates an invoice transaction, requesting payment - let args = IssueInvoiceTxArgs { - amount: reward * 2, - ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - Ok(()) - }, - )?; + // Wallet 2 initiates an invoice transaction, requesting payment + let args = IssueInvoiceTxArgs { + amount: reward * 2, + ..Default::default() + }; + slate = api2.issue_invoice_tx(mask2, args)?; assert_eq!(slate.state, SlateState::Invoice1); let orig_slate = slate.clone(); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // Wallet 1 receives the invoice transaction - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - slate = api.process_invoice_tx(m, &slate, args.clone())?; - api.tx_lock_outputs(m, &slate)?; + // Wallet 1 receives the invoice transaction + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + slate = api1.process_invoice_tx(mask1, &slate, args.clone())?; + api1.tx_lock_outputs(mask1, &slate)?; - // Wallet 1 cancels the invoice transaction - api.cancel_tx(m, None, Some(slate.id))?; + // Wallet 1 cancels the invoice transaction + api1.cancel_tx(mask1, None, Some(slate.id))?; - // Wallet 1 attempts to repay again - let res = api.process_invoice_tx(m, &orig_slate, args); - assert!(res.is_err()); - - Ok(()) - }, - )?; + // Wallet 1 attempts to repay again + let res = api1.process_invoice_tx(mask1, &orig_slate, args); + assert!(res.is_err()); assert_eq!(slate.state, SlateState::Invoice2); // let logging finish diff --git a/controller/tests/late_lock.rs b/controller/tests/late_lock.rs index 2d1ec29..8783610 100644 --- a/controller/tests/late_lock.rs +++ b/controller/tests/late_lock.rs @@ -18,9 +18,8 @@ extern crate grin_wallet_controller as wallet; extern crate grin_wallet_impls as impls; extern crate grin_wallet_libwallet as libwallet; -use self::libwallet::{InitTxArgs, Slate}; +use self::libwallet::InitTxArgs; use impls::test_framework::{self, LocalWalletClient}; -use std::path::PathBuf; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -28,6 +27,7 @@ use std::time::Duration; #[macro_use] mod common; use common::{clean_output_dir, create_wallet_proxy, setup}; +use libwallet::InitTxSendArgs; /// self send impl fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { @@ -46,7 +46,8 @@ fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -57,7 +58,8 @@ fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -69,26 +71,8 @@ fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { }); // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - Ok(()) - }, - )?; - - // add some accounts - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account1")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api2.create_account_path(mask2, "account1")?; // Get some mining done { @@ -102,70 +86,75 @@ fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false)?; - let mut slate = Slate::blank(2, false); let amount = 100_000_000_000; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - late_lock: Some(true), - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - println!("S1 SLATE: {}", slate_i); - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - println!("S2 SLATE: {}", slate); + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + late_lock: Some(true), + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + println!("S1 SLATE: {}", slate_i); + let mut slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + println!("S2 SLATE: {}", slate); - // Note we don't call `tx_lock_outputs` on the sender side here, - // as the outputs will only be locked during finalization + // Note we don't call `tx_lock_outputs` on the sender side here, + // as the outputs will only be locked during finalization - slate = sender_api.finalize_tx(m, &slate)?; - println!("S3 SLATE: {}", slate); + slate = api1.finalize_tx(mask1, &slate)?; + println!("S3 SLATE: {}", slate); - // Now post tx to our node for inclusion in the next block. - sender_api.post_tx(m, &slate, true)?; - - Ok(()) - }, - )?; + // Now post tx to our node for inclusion in the next block. + api1.post_tx(mask1, &slate, true)?; test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false)?; // update/test contents of both accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - // Reward from mining 11 blocks, minus the amount sent. - // Note: We mined the block containing the tx, so fees are effectively refunded. - assert_eq!(560_000_000_000, wallet_info.amount_currently_spendable); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + // Reward from mining 11 blocks, minus the amount sent. + // Note: We mined the block containing the tx, so fees are effectively refunded. + assert_eq!(560_000_000_000, wallet_info.amount_currently_spendable); - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(amount, wallet_info.amount_currently_spendable); - Ok(()) - }, - )?; + // Make sure outputs are not locked on failed send with arguments. + // Fail sending without starting Tor + api1.set_tor_config(Some(grin_wallet_config::TorConfig { + use_integrated: Some(false), + socks_proxy_addr: "invalid".into(), + ..Default::default() + }))?; + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + late_lock: Some(true), + send_args: Some(InitTxSendArgs { + dest: "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp".into(), + post_tx: false, + fluff: false, + skip_tor: Some(false), + }), + ..Default::default() + }; + let slate = api1.init_send_tx(mask1, args)?; + let (_, txs) = api1.retrieve_txs(mask1, false, None, Some(slate.id), None)?; + assert!(txs.is_empty()); + // Make sure spendable balance not changed. + let (wallet1_refreshed, wallet_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(560_000_000_000, wallet_info.amount_currently_spendable); + + let (wallet2_refreshed, wallet_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(amount, wallet_info.amount_currently_spendable); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/mwixnet.rs b/controller/tests/mwixnet.rs index 60e4bd8..5ae886b 100644 --- a/controller/tests/mwixnet.rs +++ b/controller/tests/mwixnet.rs @@ -50,7 +50,8 @@ fn mwixnet_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -65,16 +66,8 @@ fn mwixnet_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let reward = core::consensus::REWARD; // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; // Get some mining done { @@ -86,123 +79,84 @@ fn mwixnet_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); // Should have 5 in account1 (5 spendable), 5 in account (2 spendable) - wallet::controller::owner_single_use( + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward); + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + api1.tx_lock_outputs(mask1, &slate)?; + // Send directly to self + wallet::controller::foreign_single_use( wallet1.clone(), - mask1, PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward); - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let mut slate = api.init_send_tx(m, args)?; - api.tx_lock_outputs(m, &slate)?; - // Send directly to self - wallet::controller::foreign_single_use( - wallet1.clone(), - PathBuf::from(test_dir), - mask1_i.clone(), - |api| { - slate = api.receive_tx(&slate, Some("listener"), None)?; - Ok(()) - }, - )?; - slate = api.finalize_tx(m, &slate)?; - api.post_tx(m, &slate, false)?; // mines a block - bh += 1; + mask1_i.clone(), + |api| { + slate = api.receive_tx(&slate, Some("listener"), None)?; Ok(()) }, )?; + slate = api1.finalize_tx(mask1, &slate)?; + api1.post_tx(mask1, &slate, false)?; // mines a block + bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; // Check total in mining account - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward - reward * 2); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward - reward * 2); // Check total in 'listener' account { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("listener")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, 2 * reward); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, 2 * reward); // Recipient wallet creates a mwixnet request from the last output - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let secp_locked = util::static_secp_instance(); - let secp = secp_locked.lock(); - let server_pubkey_str_1 = - "97444ae673bb92c713c1a2f7b8882ffbfc1c67401a280a775dce1a8651584332"; - let server_pubkey_str_2 = - "0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e"; - let server_pubkey_str_3 = - "b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5"; - let server_key_1 = - SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap()) - .unwrap(); - let server_key_2 = - SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap()) - .unwrap(); - let server_key_3 = - SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap()) - .unwrap(); - let params = MixnetReqCreationParams { - server_keys: vec![server_key_1, server_key_2, server_key_3], - fee_per_hop: 50_000_000, - }; - let outputs = api.retrieve_outputs(mask1, false, false, None)?; - // get last output - let last_output = outputs.1[outputs.1.len() - 1].clone(); + let secp_locked = util::static_secp_instance(); + let secp = secp_locked.lock(); + let server_pubkey_str_1 = "97444ae673bb92c713c1a2f7b8882ffbfc1c67401a280a775dce1a8651584332"; + let server_pubkey_str_2 = "0c9414341f2140ed34a5a12a6479bf5a6404820d001ab81d9d3e8cc38f049b4e"; + let server_pubkey_str_3 = "b58ece97d60e71bb7e53218400b0d67bfe6a3cb7d3b4a67a44f8fb7c525cbca5"; + let server_key_1 = + SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_1).unwrap())?; + let server_key_2 = + SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_2).unwrap())?; + let server_key_3 = + SecretKey::from_slice(&secp, &grin_util::from_hex(&server_pubkey_str_3).unwrap())?; + let params = MixnetReqCreationParams { + server_keys: vec![server_key_1, server_key_2, server_key_3], + fee_per_hop: 50_000_000, + }; + let outputs = api1.retrieve_outputs(mask1, false, false, None)?; + // get last output + let last_output = outputs.1[outputs.1.len() - 1].clone(); - let mwixnet_req = api.create_mwixnet_req(m, ¶ms, &last_output.commit, true)?; + let mwixnet_req = api1.create_mwixnet_req(mask1, ¶ms, &last_output.commit, true)?; - println!("MWIXNET REQ: {:?}", mwixnet_req); + println!("MWIXNET REQ: {:?}", mwixnet_req); - // check output we created comsig for is indeed locked - let outputs = api.retrieve_outputs(mask1, false, false, None)?; - // get last output - let last_output = outputs.1[outputs.1.len() - 1].clone(); - assert!(last_output.output.status == libwallet::OutputStatus::Locked); - - Ok(()) - }, - )?; + // check output we created comsig for is indeed locked + let outputs = api1.retrieve_outputs(mask1, false, false, None)?; + // get last output + let last_output = outputs.1[outputs.1.len() - 1].clone(); + assert_eq!(last_output.output.status, libwallet::OutputStatus::Locked); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/no_change.rs b/controller/tests/no_change.rs index aa1a56e..503691e 100644 --- a/controller/tests/no_change.rs +++ b/controller/tests/no_change.rs @@ -22,7 +22,7 @@ use std::path::PathBuf; use grin_wallet_libwallet as libwallet; use impls::test_framework::{self, LocalWalletClient}; -use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate}; +use libwallet::{InitTxArgs, IssueInvoiceTxArgs}; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -44,7 +44,8 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -57,7 +58,8 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -77,109 +79,67 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let fee = core::libtx::tx_fee(1, 1, 1); // send a single block's worth of transactions with minimal strategy - let mut slate = Slate::blank(2, false); - let mut stored_excess = None; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let args = InitTxArgs { - src_acct_name: None, - amount: reward - fee, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - ..Default::default() - }; - slate = api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate)?; - api.tx_lock_outputs(m, &slate)?; - slate = api.finalize_tx(m, &slate)?; - println!("Posted Slate: {:?}", slate); - stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess); - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; + let args = InitTxArgs { + src_acct_name: None, + amount: reward - fee, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + slate = client1.send_tx_slate_direct("wallet2", &slate)?; + api1.tx_lock_outputs(mask1, &slate)?; + slate = api1.finalize_tx(mask1, &slate)?; + println!("Posted Slate: {:?}", slate); + let mut stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess); + api1.post_tx(mask1, &slate, false)?; // ensure stored excess is correct in both wallets // Wallet 1 calculated the excess with the full slate // Wallet 2 only had the excess provided by // wallet 1 // Refresh and check transaction log for wallet 1 - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?; - assert!(refreshed); - let tx = txs[0].clone(); - println!("SIMPLE SEND - SENDING WALLET"); - println!("{:?}", tx); - println!(); - assert!(tx.confirmed); - assert_eq!(stored_excess, tx.kernel_excess); - Ok(()) - }, - )?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + assert!(refreshed); + let tx = txs[0].clone(); + println!("SIMPLE SEND - SENDING WALLET"); + println!("{:?}", tx); + println!(); + assert!(tx.confirmed); + assert_eq!(stored_excess, tx.kernel_excess); // Refresh and check transaction log for wallet 2 - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?; - assert!(refreshed); - let tx = txs[0].clone(); - println!("SIMPLE SEND - RECEIVING WALLET"); - println!("{:?}", tx); - println!(); - assert!(tx.confirmed); - assert_eq!(stored_excess, tx.kernel_excess); - Ok(()) - }, - )?; + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, Some(slate.id), None)?; + assert!(refreshed); + let tx = txs[0].clone(); + println!("SIMPLE SEND - RECEIVING WALLET"); + println!("{:?}", tx); + println!(); + assert!(tx.confirmed); + assert_eq!(stored_excess, tx.kernel_excess); // ensure invoice TX works as well with no change - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - // Wallet 2 inititates an invoice transaction, requesting payment - let args = IssueInvoiceTxArgs { - amount: reward - fee, - ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - Ok(()) - }, - )?; + // Wallet 2 initiates an invoice transaction, requesting payment + let args = IssueInvoiceTxArgs { + amount: reward - fee, + ..Default::default() + }; + slate = api2.issue_invoice_tx(mask2, args)?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // Wallet 1 receives the invoice transaction - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - ..Default::default() - }; - slate = api.process_invoice_tx(m, &slate, args)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + // Wallet 1 receives the invoice transaction + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; + slate = api1.process_invoice_tx(mask1, &slate, args)?; + api1.tx_lock_outputs(mask1, &slate)?; // wallet 2 finalizes and posts wallet::controller::foreign_single_use( @@ -192,54 +152,30 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { Ok(()) }, )?; - wallet::controller::owner_single_use( - wallet2.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - println!("Invoice Posted TX: {}", slate); - stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess); - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; + println!("Invoice Posted TX: {}", slate); + stored_excess = Some(slate.tx.as_ref().unwrap().body.kernels[0].excess); + api2.post_tx(mask2, &slate, false)?; // check wallet 2's version - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?; - assert!(refreshed); - for tx in txs { - stored_excess = tx.kernel_excess; - println!("Wallet 2: {:?}", tx); - println!(); - assert!(tx.confirmed); - assert_eq!(stored_excess, tx.kernel_excess); - } - Ok(()) - }, - )?; + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, Some(slate.id), None)?; + assert!(refreshed); + for tx in txs { + stored_excess = tx.kernel_excess; + println!("Wallet 2: {:?}", tx); + println!(); + assert!(tx.confirmed); + assert_eq!(stored_excess, tx.kernel_excess); + } // Refresh and check transaction log for wallet 1 - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?; - assert!(refreshed); - for tx in txs { - println!("Wallet 1: {:?}", tx); - println!(); - assert_eq!(stored_excess, tx.kernel_excess); - assert!(tx.confirmed); - } - Ok(()) - }, - )?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + assert!(refreshed); + for tx in txs { + println!("Wallet 1: {:?}", tx); + println!(); + assert_eq!(stored_excess, tx.kernel_excess); + assert!(tx.confirmed); + } // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/payment_proofs.rs b/controller/tests/payment_proofs.rs index 651e486..5c4eeaf 100644 --- a/controller/tests/payment_proofs.rs +++ b/controller/tests/payment_proofs.rs @@ -21,7 +21,6 @@ extern crate grin_wallet_util; use grin_wallet_libwallet as libwallet; use impls::test_framework::{self, LocalWalletClient}; use libwallet::{InitTxArgs, Slate}; -use std::path::PathBuf; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -45,7 +44,8 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -58,7 +58,8 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -77,99 +78,74 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); - let mut address = None; - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - address = Some(api.get_slatepack_address(m, 0)?); - Ok(()) - }, - )?; + let address = Some(api2.get_slatepack_address(mask2, 0)?); println!("Public address is: {:?}", address); let amount = 60_000_000_000; let mut slate = Slate::blank(1, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - payment_proof_recipient_address: address.clone(), - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + payment_proof_recipient_address: address.clone(), + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; - assert_eq!( - slate_i.payment_proof.as_ref().unwrap().receiver_address, - address.as_ref().unwrap().pub_key, - ); - println!( - "Sender addr: {:?}", - slate_i.payment_proof.as_ref().unwrap().sender_address - ); + assert_eq!( + slate_i.payment_proof.as_ref().unwrap().receiver_address, + address.as_ref().unwrap().pub_key, + ); + println!( + "Sender addr: {:?}", + slate_i.payment_proof.as_ref().unwrap().sender_address + ); - // Check we are creating a tx with kernel features 0 - // We will check this produces a Plain kernel later. - assert_eq!(0, slate.kernel_features); + // Check we are creating a tx with kernel features 0 + // We will check this produces a Plain kernel later. + assert_eq!(0, slate.kernel_features); - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; + slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; - // Ensure what's stored in TX log for payment proof is correct - let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?; - assert!(txs[0].payment_proof.is_some()); - let pp = txs[0].clone().payment_proof.unwrap(); - assert_eq!( - pp.receiver_address, - slate_i.payment_proof.as_ref().unwrap().receiver_address - ); - assert!(pp.receiver_signature.is_some()); - assert_eq!(pp.sender_address_path, 0); - assert_eq!(pp.sender_signature, None); + // Ensure what's stored in TX log for payment proof is correct + let (_, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + assert!(txs[0].payment_proof.is_some()); + let pp = txs[0].clone().payment_proof.unwrap(); + assert_eq!( + pp.receiver_address, + slate_i.payment_proof.as_ref().unwrap().receiver_address + ); + assert!(pp.receiver_signature.is_some()); + assert_eq!(pp.sender_address_path, 0); + assert_eq!(pp.sender_signature, None); - // check we should get an error at this point since proof is not complete - let pp = sender_api.retrieve_payment_proof(m, true, None, Some(slate.id)); - assert!(pp.is_err()); + // check we should get an error at this point since proof is not complete + let pp = api1.retrieve_payment_proof(mask1, true, None, Some(slate.id)); + assert!(pp.is_err()); - slate = sender_api.finalize_tx(m, &slate)?; - sender_api.post_tx(m, &slate, true)?; - Ok(()) - }, - )?; + slate = api1.finalize_tx(mask1, &slate)?; + api1.post_tx(mask1, &slate, true)?; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // Check payment proof here - let mut pp = sender_api.retrieve_payment_proof(m, true, None, Some(slate.id))?; + // Check payment proof here + let mut pp = api1.retrieve_payment_proof(mask1, true, None, Some(slate.id))?; - println!("Payment proof: {:?}", pp); + println!("Payment proof: {:?}", pp); - // verify, should be good - let res = sender_api.verify_payment_proof(m, &pp)?; - assert_eq!(res, (true, false)); + // verify, should be good + let res = api1.verify_payment_proof(mask1, &pp)?; + assert_eq!(res, (true, false)); - // Modify values, should not be good - pp.amount = 20; - let res = sender_api.verify_payment_proof(m, &pp); - assert!(res.is_err()); - Ok(()) - }, - )?; + // Modify values, should not be good + pp.amount = 20; + let res = api1.verify_payment_proof(mask1, &pp); + assert!(res.is_err()); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/repost.rs b/controller/tests/repost.rs index 0718364..7f3a39b 100644 --- a/controller/tests/repost.rs +++ b/controller/tests/repost.rs @@ -21,7 +21,7 @@ extern crate grin_wallet_libwallet as libwallet; use grin_core as core; use std::path::PathBuf; -use self::libwallet::{InitTxArgs, Slate}; +use self::libwallet::InitTxArgs; use impls::test_framework::{self, LocalWalletClient}; use impls::{PathToSlate, SlateGetter as _, SlatePutter as _}; use std::sync::atomic::Ordering; @@ -49,7 +49,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -60,7 +61,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -75,28 +77,11 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> let reward = core::consensus::REWARD; // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; - // add some accounts - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account1")?; - api.create_account_path(m, "account2")?; - Ok(()) - }, - )?; + api2.create_account_path(mask2, "account1")?; + api2.create_account_path(mask2, "account2")?; // Get some mining done { @@ -110,34 +95,24 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> let send_file = format!("{}/part_tx_1.tx", test_dir); let receive_file = format!("{}/part_tx_2.tx", test_dir); - let mut slate = Slate::blank(2, false); - // Should have 5 in account1 (5 spendable), 5 in account (2 spendable) - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward); - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - PathToSlate((&send_file).into()).put_tx(&slate, false)?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward); + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + PathToSlate((&send_file).into()).put_tx(&slate, false)?; + api1.tx_lock_outputs(mask1, &slate)?; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; @@ -167,69 +142,37 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> } // wallet 1 finalize - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - slate = PathToSlate((&receive_file).into()).get_tx()?.0; - slate = api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; + slate = PathToSlate((&receive_file).into()).get_tx()?.0; + slate = api1.finalize_tx(mask1, &slate)?; // Now repost from cached - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?; - println!("TXS[0]: {:?}", txs[0]); - let stored_tx = api.get_stored_tx(m, None, Some(&txs[0].tx_slate_id.unwrap()))?; - println!("Stored tx: {:?}", stored_tx); - api.post_tx(m, &slate, false)?; - bh += 1; - Ok(()) - }, - )?; + let (_, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + println!("TXS[0]: {:?}", txs[0]); + let stored_tx = api1.get_stored_tx(mask1, None, Some(&txs[0].tx_slate_id.unwrap()))?; + println!("Stored tx: {:?}", stored_tx); + api1.post_tx(mask1, &slate, false)?; + bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; // update/test contents of both accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward - reward * 2); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward - reward * 2); { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("listener")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.last_confirmed_height, bh); - assert_eq!(wallet2_info.total, 2 * reward); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, 2 * reward); - // as above, but syncronously + // as above, but synchronously { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("mining")?; @@ -239,78 +182,45 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> w.set_parent_key_id_by_name("account1")?; } - let mut slate = Slate::blank(2, false); let amount = 60_000_000_000; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; - slate = sender_api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; + slate = api1.finalize_tx(mask1, &slate)?; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; // Now repost from cached - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?; - let stored_tx_slate = api.get_stored_tx(m, Some(txs[0].id), None)?.unwrap(); - api.post_tx(m, &stored_tx_slate, false)?; - bh += 1; - Ok(()) - }, - )?; + let (_, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + let stored_tx_slate = api1.get_stored_tx(mask1, Some(txs[0].id), None)?.unwrap(); + api1.post_tx(mask1, &stored_tx_slate, false)?; + bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; - // - // update/test contents of both accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward - reward * 4); - Ok(()) - }, - )?; - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.last_confirmed_height, bh); - assert_eq!(wallet2_info.total, 2 * amount); - Ok(()) - }, - )?; + // update/test contents of both accounts + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward - reward * 4); + + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.last_confirmed_height, bh); + assert_eq!(wallet2_info.total, 2 * amount); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/revert.rs b/controller/tests/revert.rs index ef5a887..6c4c8a6 100644 --- a/controller/tests/revert.rs +++ b/controller/tests/revert.rs @@ -24,14 +24,13 @@ use grin_core::global; use grin_keychain::ExtKeychain; use grin_util::secp::key::SecretKey; use grin_util::Mutex; -use grin_wallet_controller::controller::owner_single_use as owner; +use grin_wallet_api::Owner; use grin_wallet_impls::test_framework::*; use grin_wallet_impls::{DefaultLCProvider, PathToSlate, SlatePutter}; use grin_wallet_libwallet as libwallet; use grin_wallet_libwallet::api_impl::types::InitTxArgs; use grin_wallet_libwallet::WalletInst; use log::error; -use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; @@ -63,6 +62,8 @@ fn revert( Option, Wallet, Option, + Owner, LocalWalletClient, ExtKeychain>, + Owner, LocalWalletClient, ExtKeychain>, ), libwallet::Error, > { @@ -82,7 +83,8 @@ fn revert( "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = mask1_i.as_ref(); @@ -94,28 +96,23 @@ fn revert( "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = mask2_i.as_ref(); // Set the wallet proxy listener running - std::thread::spawn(move || { + thread::spawn(move || { if let Err(e) = wallet_proxy.run() { error!("Wallet Proxy error: {}", e); } }); - owner(wallet1.clone(), mask1, PathBuf::from(test_dir), |api, m| { - api.create_account_path(m, "a")?; - api.set_active_account(m, "a")?; - Ok(()) - })?; + api1.create_account_path(mask1, "a")?; + api1.set_active_account(mask1, "a")?; - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - api.create_account_path(m, "b")?; - api.set_active_account(m, "b")?; - Ok(()) - })?; + api2.create_account_path(mask2, "b")?; + api2.set_active_account(mask2, "b")?; let reward = core::consensus::REWARD; let cm = global::coinbase_maturity() as u64; @@ -126,76 +123,60 @@ fn revert( award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false)?; // Sanity check contents - owner(wallet1.clone(), mask1, PathBuf::from(test_dir), |api, m| { - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, bh * reward); - assert_eq!(info.amount_currently_spendable, (bh - cm) * reward); - assert_eq!(info.amount_reverted, 0); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs); - assert_eq!(info.total, c); - assert_eq!(txs.len(), bh as usize); - Ok(()) - })?; + let (refreshed, info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, bh * reward); + assert_eq!(info.amount_currently_spendable, (bh - cm) * reward); + assert_eq!(info.amount_reverted, 0); + // check tx log as well + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs); + assert_eq!(info.total, c); + assert_eq!(txs.len(), bh as usize); - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, 0); - assert_eq!(info.amount_currently_spendable, 0); - assert_eq!(info.amount_reverted, 0); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 0); - Ok(()) - })?; + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, 0); + assert_eq!(info.amount_currently_spendable, 0); + assert_eq!(info.amount_reverted, 0); + // check tx log as well + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 0); // Send some funds - let mut tx = None; - owner(wallet1.clone(), mask1, PathBuf::from(test_dir), |api, m| { - // send to send - let args = InitTxArgs { - src_acct_name: None, - amount: sent, - minimum_confirmations: cm, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - // output tx file - let send_file = format!("{}/part_tx_1.tx", test_dir); - PathToSlate(send_file.into()).put_tx(&slate, false)?; - api.tx_lock_outputs(m, &slate)?; - let slate = client1.send_tx_slate_direct("wallet2", &slate)?; - let slate = api.finalize_tx(m, &slate)?; - tx = slate.tx; - - Ok(()) - })?; - let tx = tx.expect("tx from slate"); + // send to send + let args = InitTxArgs { + src_acct_name: None, + amount: sent, + minimum_confirmations: cm, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let slate = api1.init_send_tx(mask1, args)?; + // output tx file + let send_file = format!("{}/part_tx_1.tx", test_dir); + PathToSlate(send_file.into()).put_tx(&slate, false)?; + api1.tx_lock_outputs(mask1, &slate)?; + let slate = client1.send_tx_slate_direct("wallet2", &slate)?; + let slate = api1.finalize_tx(mask1, &slate)?; + let tx = slate.tx.expect("tx from slate"); // Check funds have been received - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, 0); - assert_eq!(info.amount_currently_spendable, 0); - assert_eq!(info.amount_reverted, 0); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - let tx = &txs[0]; - assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived); - assert!(!tx.confirmed); - Ok(()) - })?; + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, 0); + assert_eq!(info.amount_currently_spendable, 0); + assert_eq!(info.amount_reverted, 0); + // check tx log as well + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + assert_eq!(txs[0].tx_type, libwallet::TxLogEntryType::TxReceived); + assert!(!&txs[0].confirmed); // Update parallel chain assert_eq!(chain2.head_header().unwrap().height, 0); @@ -223,23 +204,19 @@ fn revert( let bh = bh + 1; // Check funds have been confirmed - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, sent); - assert_eq!(info.amount_currently_spendable, sent); - assert_eq!(info.amount_reverted, 0); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - let tx = &txs[0]; - assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived); - assert!(tx.confirmed); - assert!(tx.kernel_excess.is_some()); - assert!(tx.reverted_after.is_none()); - Ok(()) - })?; + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, sent); + assert_eq!(info.amount_currently_spendable, sent); + assert_eq!(info.amount_reverted, 0); + // check tx log as well + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + assert_eq!(txs[0].tx_type, libwallet::TxLogEntryType::TxReceived); + assert!(&txs[0].confirmed); + assert!(&txs[0].kernel_excess.is_some()); + assert!(&txs[0].reverted_after.is_none()); // Attach more blocks to the parallel chain, making it the longest one award_block_to_wallet(&chain2, &[], wallet1.clone(), mask1)?; @@ -258,32 +235,29 @@ fn revert( let bh = bh + 1; // Check funds have been reverted - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - api.scan(m, None, false)?; - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, 0); - assert_eq!(info.amount_currently_spendable, 0); - assert_eq!(info.amount_reverted, sent); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - let tx = &txs[0]; - assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReverted); - assert!(!tx.confirmed); - assert!(tx.reverted_after.is_some()); - Ok(()) - })?; + api2.scan(mask2, None, false)?; + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, 0); + assert_eq!(info.amount_currently_spendable, 0); + assert_eq!(info.amount_reverted, sent); + // check tx log as well + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + assert_eq!(txs[0].tx_type, libwallet::TxLogEntryType::TxReverted); + assert!(!&txs[0].confirmed); + assert!(&txs[0].reverted_after.is_some()); stopper2.store(false, Ordering::Relaxed); Ok(( - chain, stopper, sent, bh, tx, wallet1, mask1_i, wallet2, mask2_i, + chain, stopper, sent, bh, tx, wallet1, mask1_i, wallet2, mask2_i, api1, api2, )) } fn revert_reconfirm_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { - let (chain, stopper, sent, bh, tx, wallet1, mask1_i, wallet2, mask2_i) = revert(test_dir)?; + let (chain, stopper, sent, bh, tx, wallet1, mask1_i, _wallet2, mask2_i, _api1, api2) = + revert(test_dir)?; let mask1 = mask1_i.as_ref(); let mask2 = mask2_i.as_ref(); @@ -293,22 +267,19 @@ fn revert_reconfirm_impl(test_dir: &'static str) -> Result<(), libwallet::Error> let bh = bh + 1; // Check funds have been confirmed again - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, sent); - assert_eq!(info.amount_currently_spendable, sent); - assert_eq!(info.amount_reverted, 0); - // check tx log as well - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - let tx = &txs[0]; - assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived); - assert!(tx.confirmed); - assert!(tx.reverted_after.is_none()); - Ok(()) - })?; + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, sent); + assert_eq!(info.amount_currently_spendable, sent); + assert_eq!(info.amount_reverted, 0); + // check tx log as well + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + let tx = &txs[0]; + assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived); + assert!(tx.confirmed); + assert!(tx.reverted_after.is_none()); // let logging finish stopper.store(false, Ordering::Relaxed); @@ -317,41 +288,37 @@ fn revert_reconfirm_impl(test_dir: &'static str) -> Result<(), libwallet::Error> } fn revert_cancel_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { - let (_, stopper, sent, bh, _, _, _, wallet2, mask2_i) = revert(test_dir)?; + let (_, stopper, sent, bh, _, _, _, _wallet2, mask2_i, _api1, api2) = revert(test_dir)?; let mask2 = mask2_i.as_ref(); - // Cancelling tx - owner(wallet2.clone(), mask2, PathBuf::from(test_dir), |api, m| { - // Sanity check - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, 0); - assert_eq!(info.amount_currently_spendable, 0); - assert_eq!(info.amount_reverted, sent); + // Sanity check + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, 0); + assert_eq!(info.amount_currently_spendable, 0); + assert_eq!(info.amount_reverted, sent); - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - let tx = &txs[0]; + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + let tx = &txs[0]; - // Cancel - api.cancel_tx(m, Some(tx.id), None)?; + // Cancel + api2.cancel_tx(mask2, Some(tx.id), None)?; - // Check updated summary info - let (refreshed, info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(info.last_confirmed_height, bh); - assert_eq!(info.total, 0); - assert_eq!(info.amount_currently_spendable, 0); - assert_eq!(info.amount_reverted, 0); + // Check updated summary info + let (refreshed, info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(info.last_confirmed_height, bh); + assert_eq!(info.total, 0); + assert_eq!(info.amount_currently_spendable, 0); + assert_eq!(info.amount_reverted, 0); - // Check updated tx log - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert_eq!(txs.len(), 1); - let tx = &txs[0]; - assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceivedCancelled); - Ok(()) - })?; + // Check updated tx log + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert_eq!(txs.len(), 1); + let tx = &txs[0]; + assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceivedCancelled); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/self_send.rs b/controller/tests/self_send.rs index 6cf572e..c6ca437 100644 --- a/controller/tests/self_send.rs +++ b/controller/tests/self_send.rs @@ -48,7 +48,8 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -63,16 +64,8 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let reward = core::consensus::REWARD; // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; // Get some mining done { @@ -84,78 +77,54 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); // Should have 5 in account1 (5 spendable), 5 in account (2 spendable) - wallet::controller::owner_single_use( + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward); + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + api1.tx_lock_outputs(mask1, &slate)?; + // Send directly to self + wallet::controller::foreign_single_use( wallet1.clone(), - mask1, PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward); - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let mut slate = api.init_send_tx(m, args)?; - api.tx_lock_outputs(m, &slate)?; - // Send directly to self - wallet::controller::foreign_single_use( - wallet1.clone(), - PathBuf::from(test_dir), - mask1_i.clone(), - |api| { - slate = api.receive_tx(&slate, Some("listener"), None)?; - Ok(()) - }, - )?; - slate = api.finalize_tx(m, &slate)?; - api.post_tx(m, &slate, false)?; // mines a block - bh += 1; + mask1_i.clone(), + |api| { + slate = api.receive_tx(&slate, Some("listener"), None)?; Ok(()) }, )?; + slate = api1.finalize_tx(mask1, &slate)?; + api1.post_tx(mask1, &slate, false)?; // mines a block + bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; // Check total in mining account - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward - reward * 2); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward - reward * 2); // Check total in 'listener' account { wallet_inst!(wallet1, w); w.set_parent_key_id_by_name("listener")?; } - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, 2 * reward); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, 2 * reward); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/slatepack.rs b/controller/tests/slatepack.rs index 9bdd740..d53f1c4 100644 --- a/controller/tests/slatepack.rs +++ b/controller/tests/slatepack.rs @@ -100,7 +100,8 @@ fn slatepack_exchange_test_impl( "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -111,7 +112,8 @@ fn slatepack_exchange_test_impl( "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -126,28 +128,11 @@ fn slatepack_exchange_test_impl( let reward = core::consensus::REWARD; // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; - // add some accounts - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account1")?; - api.create_account_path(m, "account2")?; - Ok(()) - }, - )?; + api2.create_account_path(mask2, "account1")?; + api2.create_account_path(mask2, "account2")?; // Get some mining done { @@ -160,19 +145,9 @@ fn slatepack_exchange_test_impl( let (recipients_1, dec_key_1, sender_1) = match use_encryption { true => { - let mut rec_address = SlatepackAddress::random(); - let mut sec_key = edDalekSecretKey::from_bytes(&[0u8; 32]); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - sec_key = api.get_slatepack_secret_key(m, 0)?; - let pub_key = edDalekPublicKey::from(&sec_key); - rec_address = SlatepackAddress::new(&pub_key); - Ok(()) - }, - )?; + let sec_key = api1.get_slatepack_secret_key(mask1, 0)?; + let pub_key = edDalekPublicKey::from(&sec_key); + let rec_address = SlatepackAddress::new(&pub_key); ( vec![rec_address.clone()], Some(sec_key), @@ -184,19 +159,9 @@ fn slatepack_exchange_test_impl( let (recipients_2, dec_key_2, sender_2) = match use_encryption { true => { - let mut rec_address = SlatepackAddress::random(); - let mut sec_key = edDalekSecretKey::from_bytes(&[0u8; 32]); - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - sec_key = api.get_slatepack_secret_key(m, 0)?; - let pub_key = edDalekPublicKey::from(&sec_key); - rec_address = SlatepackAddress::new(&pub_key); - Ok(()) - }, - )?; + let sec_key = api2.get_slatepack_secret_key(mask2, 0)?; + let pub_key = edDalekPublicKey::from(&sec_key); + let rec_address = SlatepackAddress::new(&pub_key); ( vec![rec_address.clone()], Some(sec_key), @@ -219,39 +184,31 @@ fn slatepack_exchange_test_impl( ), }; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward); - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - // output tx file - output_slatepack( - &slate, - &send_file, - use_armored, - use_bin, - sender_1.clone(), - recipients_2.clone(), - )?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward); + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate = api1.init_send_tx(mask1, args)?; + // output tx file + output_slatepack( + &slate, + &send_file, + use_armored, + use_bin, + sender_1.clone(), + recipients_2.clone(), )?; + api1.tx_lock_outputs(mask1, &slate)?; // Get some mining done { @@ -286,52 +243,27 @@ fn slatepack_exchange_test_impl( )?; // wallet 1 finalizes and posts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, mut slate) = - slate_from_packed(&receive_file, use_armored, (&dec_key_1).as_ref())?; - slate = api.finalize_tx(m, &slate)?; - // Output final file for reference - output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?; - api.post_tx(m, &slate, false)?; - bh += 1; - Ok(()) - }, - )?; + let (_, mut slate) = slate_from_packed(&receive_file, use_armored, (&dec_key_1).as_ref())?; + slate = api1.finalize_tx(mask1, &slate)?; + // Output final file for reference + output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?; + api1.post_tx(mask1, &slate, false)?; + bh += 1; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); bh += 3; // Check total in mining account - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet1_refreshed); - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.total, bh * reward - reward * 2); - Ok(()) - }, - )?; + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(wallet1_refreshed); + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.total, bh * reward - reward * 2); // Check total in 'wallet 2' account - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.last_confirmed_height, bh); - assert_eq!(wallet2_info.total, 2 * reward); - Ok(()) - }, - )?; + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.last_confirmed_height, bh); + assert_eq!(wallet2_info.total, 2 * reward); // Now other types of exchange, for reference // Invoice transaction @@ -348,61 +280,43 @@ fn slatepack_exchange_test_impl( ), }; - let mut slate = Slate::blank(2, true); - - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let args = IssueInvoiceTxArgs { - amount: 1000000000, - ..Default::default() - }; - slate = api.issue_invoice_tx(m, args)?; - output_slatepack( - &slate, - &send_file, - use_armored, - use_bin, - sender_2.clone(), - recipients_1.clone(), - )?; - Ok(()) - }, + let args = IssueInvoiceTxArgs { + amount: 1000000000, + ..Default::default() + }; + let mut slate = api2.issue_invoice_tx(mask2, args)?; + output_slatepack( + &slate, + &send_file, + use_armored, + use_bin, + sender_2.clone(), + recipients_1.clone(), )?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let res = slate_from_packed(&send_file, use_armored, (&dec_key_1).as_ref())?; - slatepack = res.0; - slate = res.1; - slate = api.process_invoice_tx(m, &slate, args)?; - api.tx_lock_outputs(m, &slate)?; - output_slatepack( - &slate, - &receive_file, - use_armored, - use_bin, - sender_1.clone(), - match slatepack.sender.clone() { - Some(s) => vec![s.clone()], - None => vec![], - }, - )?; - Ok(()) + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let res = slate_from_packed(&send_file, use_armored, (&dec_key_1).as_ref())?; + slatepack = res.0; + slate = res.1; + slate = api1.process_invoice_tx(mask1, &slate, args)?; + api1.tx_lock_outputs(mask1, &slate)?; + output_slatepack( + &slate, + &receive_file, + use_armored, + use_bin, + sender_1.clone(), + match slatepack.sender.clone() { + Some(s) => vec![s.clone()], + None => vec![], }, )?; wallet::controller::foreign_single_use( @@ -418,15 +332,7 @@ fn slatepack_exchange_test_impl( Ok(()) }, )?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; + api1.post_tx(mask1, &slate, false)?; // Standard, with payment proof let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); @@ -443,47 +349,29 @@ fn slatepack_exchange_test_impl( ), }; - let mut slate = Slate::blank(2, true); - let mut address = None; - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - address = Some(api.get_slatepack_address(m, 0)?); - Ok(()) - }, - )?; + let address = Some(api2.get_slatepack_address(mask2, 0)?); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // send to send - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - payment_proof_recipient_address: address.clone(), - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - output_slatepack( - &slate, - &send_file, - use_armored, - use_bin, - sender_1, - recipients_2.clone(), - )?; - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, + // send to send + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + payment_proof_recipient_address: address.clone(), + ..Default::default() + }; + let mut slate = api1.init_send_tx(mask1, args)?; + output_slatepack( + &slate, + &send_file, + use_armored, + use_bin, + sender_1, + recipients_2.clone(), )?; + api1.tx_lock_outputs(mask1, &slate)?; wallet::controller::foreign_single_use( wallet2.clone(), @@ -509,22 +397,13 @@ fn slatepack_exchange_test_impl( }, )?; - // wallet 1 finalises and posts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let res = slate_from_packed(&receive_file, use_armored, (&dec_key_1).as_ref())?; - slate = res.1; - slate = api.finalize_tx(m, &slate)?; - // Output final file for reference - output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?; - api.post_tx(m, &slate, false)?; - bh += 1; - Ok(()) - }, - )?; + // wallet 1 finalizes and posts + let res = slate_from_packed(&receive_file, use_armored, (&dec_key_1).as_ref())?; + slate = res.1; + slate = api1.finalize_tx(mask1, &slate)?; + // Output final file for reference + output_slatepack(&slate, &final_file, use_armored, use_bin, None, vec![])?; + api1.post_tx(mask1, &slate, false)?; // let logging finish stopper.store(false, Ordering::Relaxed); @@ -550,7 +429,8 @@ fn slatepack_api_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -569,32 +449,24 @@ fn slatepack_api_impl(test_dir: &'static str) -> Result<(), libwallet::Error> { let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), - amount: reward * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate = api.init_send_tx(m, args)?; - // create an encrypted slatepack (just encrypted for self) - let enc_addr = api.get_slatepack_address(m, 0)?; - let slatepack = api.create_slatepack_message(m, &slate, Some(0), vec![enc_addr])?; - println!("{}", slatepack); - let slatepack_raw = api.decode_slatepack_message(m, slatepack.clone(), vec![0])?; - println!("{}", slatepack_raw); - let decoded_slate = api.slate_from_slatepack_message(m, slatepack, vec![0])?; - println!("{}", decoded_slate); - Ok(()) - }, - )?; + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate = api1.init_send_tx(mask1, args)?; + // create an encrypted slatepack (just encrypted for self) + let enc_addr = api1.get_slatepack_address(mask1, 0)?; + let slatepack = api1.create_slatepack_message(mask1, &slate, Some(0), vec![enc_addr])?; + println!("{}", slatepack); + let slatepack_raw = api1.decode_slatepack_message(mask1, slatepack.clone(), vec![0])?; + println!("{}", slatepack_raw); + let decoded_slate = api1.slate_from_slatepack_message(mask1, slatepack, vec![0])?; + println!("{}", decoded_slate); // let logging finish stopper.store(false, Ordering::Relaxed); @@ -609,8 +481,7 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet: let stopper = wallet_proxy.running.clone(); let config_path = PathBuf::from(test_dir).join("grin-wallet.toml"); GlobalWalletConfig::for_chain(&core::global::ChainTypes::AutomatedTesting, &config_path) - .write_to_file(config_path.to_str().unwrap(), false, None, None) - .unwrap(); + .write_to_file(config_path.to_str().unwrap(), false, None, None)?; create_wallet_and_add!( client1, @@ -620,7 +491,8 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet: "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -632,7 +504,8 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet: "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -644,62 +517,57 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet: let reward = core::consensus::REWARD; let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 6, false); - let mut slate = Slate::blank(2, true); - - wallet::controller::owner_single_use(wallet2.clone(), mask2, config_path.clone(), |api, m| { - slate = api.issue_invoice_tx( - m, - IssueInvoiceTxArgs { - amount: reward, - ..Default::default() - }, - )?; - Ok(()) - })?; - - wallet::controller::owner_single_use(wallet1.clone(), mask1, config_path, |api, m| { - let args = InitTxArgs { - src_acct_name: Some("mining".to_owned()), + let slate = api2.issue_invoice_tx( + mask2, + IssueInvoiceTxArgs { amount: reward, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, ..Default::default() - }; + }, + )?; - let mut wrong_net_args = args.clone(); - wrong_net_args.send_args = Some(InitTxSendArgs { - dest: "grin1dvge9z4uqgqlpspmljrd7smh3grrw9xu2r9lkz3u67s3emj3ud2sd5gk9p".to_string(), - post_tx: false, - fluff: false, - skip_tor: Some(true), - }); - assert!(api.init_send_tx(m, wrong_net_args.clone()).is_err()); - assert!(api.process_invoice_tx(m, &slate, wrong_net_args).is_err()); + let args = InitTxArgs { + src_acct_name: Some("mining".to_owned()), + amount: reward, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; - let mut invalid_args = args.clone(); - invalid_args.send_args = Some(InitTxSendArgs { - dest: "tgrinaddr10qlk22rxjap2ny8qltc2tl996kenxr3hhwuu6hrzs6tdq08yaqgqnlumr7" - .to_string(), - post_tx: false, - fluff: false, - skip_tor: Some(true), - }); - assert!(api.init_send_tx(m, invalid_args.clone()).is_err()); - assert!(api.process_invoice_tx(m, &slate, invalid_args).is_err()); + let mut wrong_net_args = args.clone(); + wrong_net_args.send_args = Some(InitTxSendArgs { + dest: "grin1dvge9z4uqgqlpspmljrd7smh3grrw9xu2r9lkz3u67s3emj3ud2sd5gk9p".to_string(), + post_tx: false, + fluff: false, + skip_tor: Some(true), + }); + assert!(api1.init_send_tx(mask1, wrong_net_args.clone()).is_err()); + assert!(api1 + .process_invoice_tx(mask1, &slate, wrong_net_args) + .is_err()); - let mut valid_args = args; - valid_args.send_args = Some(InitTxSendArgs { - dest: "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp".to_string(), - post_tx: false, - fluff: false, - skip_tor: Some(true), - }); - api.process_invoice_tx(m, &slate, valid_args.clone())?; - api.init_send_tx(m, valid_args)?; - Ok(()) - })?; + let mut invalid_args = args.clone(); + invalid_args.send_args = Some(InitTxSendArgs { + dest: "tgrinaddr10qlk22rxjap2ny8qltc2tl996kenxr3hhwuu6hrzs6tdq08yaqgqnlumr7".to_string(), + post_tx: false, + fluff: false, + skip_tor: Some(true), + }); + assert!(api1.init_send_tx(mask1, invalid_args.clone()).is_err()); + assert!(api1 + .process_invoice_tx(mask1, &slate, invalid_args) + .is_err()); + + let mut valid_args = args; + valid_args.send_args = Some(InitTxSendArgs { + dest: "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp".to_string(), + post_tx: false, + fluff: false, + skip_tor: Some(true), + }); + api1.process_invoice_tx(mask1, &slate, valid_args.clone())?; + api1.init_send_tx(mask1, valid_args)?; stopper.store(false, Ordering::Relaxed); proxy_thread.join().expect("wallet proxy thread panicked"); @@ -710,7 +578,7 @@ fn slatepack_address_validation(test_dir: &'static str) -> Result<(), libwallet: fn slatepack_exchange_json() { let test_dir = "test_output/slatepack_exchange_json"; setup(test_dir); - // Json output + // JSON output if let Err(e) = slatepack_exchange_test_impl(test_dir, false, false, false) { panic!("Libwallet Error: {}", e); } @@ -743,7 +611,7 @@ fn slatepack_exchange_armored() { fn slatepack_exchange_json_enc() { let test_dir = "test_output/slatepack_exchange_json_enc"; setup(test_dir); - // Json output + // JSON output if let Err(e) = slatepack_exchange_test_impl(test_dir, false, false, true) { panic!("Libwallet Error: {}", e); } @@ -776,7 +644,7 @@ fn slatepack_exchange_armored_enc() { fn slatepack_api() { let test_dir = "test_output/slatepack_api"; setup(test_dir); - // Json output + // JSON output if let Err(e) = slatepack_api_impl(test_dir) { panic!("Libwallet Error: {}", e); } diff --git a/controller/tests/transaction.rs b/controller/tests/transaction.rs index 107c17d..6613095 100644 --- a/controller/tests/transaction.rs +++ b/controller/tests/transaction.rs @@ -33,6 +33,8 @@ use std::time::Duration; mod common; use common::{clean_output_dir, create_wallet_proxy, setup}; +use grin_wallet_api::Owner; +use libwallet::InitTxSendArgs; /// Exercises the Transaction API fully with a test NodeClient operating /// directly on a chain instance @@ -51,7 +53,8 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); println!("Mask1: {:?}", mask1); @@ -63,7 +66,8 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); println!("Mask2: {:?}", mask2); @@ -81,459 +85,425 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error> // mine a few blocks let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false); - // Check wallet 1 contents are as expected - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - debug!( - "Wallet 1 Info Pre-Transaction, after {} blocks: {:?}", - wallet1_info.last_confirmed_height, wallet1_info - ); - assert!(wallet1_refreshed); - assert_eq!( - wallet1_info.amount_currently_spendable, - (wallet1_info.last_confirmed_height - cm) * reward - ); - assert_eq!(wallet1_info.amount_immature, cm * reward); - Ok(()) - }, - )?; + // Check wallet1 contents are as expected + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + debug!( + "Wallet 1 Info Pre-Transaction, after {} blocks: {:?}", + wallet1_info.last_confirmed_height, wallet1_info + ); + assert!(wallet1_refreshed); + assert_eq!( + wallet1_info.amount_currently_spendable, + (wallet1_info.last_confirmed_height - cm) * reward + ); + assert_eq!(wallet1_info.amount_immature, cm * reward); + } // assert wallet contents // and a single use api for a send command let amount = 60_000_000_000; let header_version = core::consensus::header_version(chain.head().unwrap().height).0; let mut slate = Slate::blank(1, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // Do not allow to send 0 - let error = sender_api - .init_send_tx( - m, - InitTxArgs { - amount: 0, - ..Default::default() - }, - ) - .unwrap_err(); - assert_eq!(error, libwallet::Error::InvalidAmount); + { + // Do not allow to send 0 + let error = api1 + .init_send_tx( + mask1, + InitTxArgs { + amount: 0, + ..Default::default() + }, + ) + .unwrap_err(); + assert_eq!(error, libwallet::Error::InvalidAmount); - // Result amount can not be 0 when amount includes fee - let mut init_args = InitTxArgs { - amount_includes_fee: Some(true), - amount: 23_000_000, - estimate_only: Some(true), - ..Default::default() - }; - let est = sender_api.init_send_tx(m, init_args.clone())?; - assert_eq!(init_args.amount, est.fee_fields.fee()); + // Result amount can not be 0 when amount includes fee + let mut init_args = InitTxArgs { + amount_includes_fee: Some(true), + amount: 23_000_000, + estimate_only: Some(true), + ..Default::default() + }; + let est = api1.init_send_tx(mask1, init_args.clone())?; + assert_eq!(init_args.amount, est.fee_fields.fee()); - init_args.estimate_only = None; - let error = sender_api.init_send_tx(m, init_args).unwrap_err(); - assert_eq!( - error, - libwallet::Error::GenericError( - "Transaction amount is too small to include fee".to_string() - ) - ); + init_args.estimate_only = None; + let error = api1.init_send_tx(mask1, init_args).unwrap_err(); + assert_eq!( + error, + libwallet::Error::GenericError( + "Transaction amount is too small to include fee".to_string() + ) + ); - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; - assert_eq!(slate_i.state, SlateState::Standard1); - assert_eq!(slate_i.version_info.block_header_version, header_version); + assert_eq!(slate_i.state, SlateState::Standard1); + assert_eq!(slate_i.version_info.block_header_version, header_version); - wallet::controller::foreign_single_use( + wallet::controller::foreign_single_use( + wallet2.clone(), + PathBuf::from(test_dir), + mask2_i.clone(), + |api| { + let mut zero_amount_slate = slate_i.clone(); + zero_amount_slate.amount = 0; + assert_eq!( + api.receive_tx(&zero_amount_slate, None, None).unwrap_err(), + libwallet::Error::InvalidAmount + ); + Ok(()) + }, + )?; + + // Check we are creating a tx with the expected lock_height of 0. + // We will check this produces a Plain kernel later. + assert_eq!(0, slate.kernel_features); + + slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + assert_eq!(slate.state, SlateState::Standard2); + + // wallet2 already has this slate, so accepted versions fail on the duplicate check + for bhv in 1..=GRIN_BLOCK_HEADER_VERSION + 1 { + let mut s = slate_i.clone(); + s.version_info.block_header_version = bhv; + let res = wallet::controller::foreign_single_use( wallet2.clone(), PathBuf::from(test_dir), mask2_i.clone(), - |api| { - let mut zero_amount_slate = slate_i.clone(); - zero_amount_slate.amount = 0; - assert_eq!( - api.receive_tx(&zero_amount_slate, None, None).unwrap_err(), - libwallet::Error::InvalidAmount - ); - Ok(()) - }, - )?; - - // Check we are creating a tx with the expected lock_height of 0. - // We will check this produces a Plain kernel later. - assert_eq!(0, slate.kernel_features); - - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - assert_eq!(slate.state, SlateState::Standard2); - - // wallet2 already has this slate, so accepted versions fail on the duplicate check - for bhv in 1..=GRIN_BLOCK_HEADER_VERSION + 1 { - let mut s = slate_i.clone(); - s.version_info.block_header_version = bhv; - let res = wallet::controller::foreign_single_use( - wallet2.clone(), - PathBuf::from(test_dir), - mask2_i.clone(), - |api| api.receive_tx(&s, None, None).map(|_| ()), - ); - if bhv <= GRIN_BLOCK_HEADER_VERSION { - assert!(matches!( - res, - Err(libwallet::Error::TransactionAlreadyReceived(_)) - )); - } else { - assert!(matches!(res, Err(libwallet::Error::Compatibility(_)))); - } - } - sender_api.tx_lock_outputs(m, &slate)?; - slate = sender_api.finalize_tx(m, &slate)?; - assert_eq!(slate.state, SlateState::Standard3); - - // Check we have a single kernel and that it is a Plain kernel (no lock_height). - // fees for 7 inputs, 2 outputs, 1 kernel (weight 52) - assert_eq!(slate.tx_or_err()?.kernels().len(), 1); - assert_eq!( - slate - .tx_or_err()? - .kernels() - .first() - .map(|k| k.features) - .unwrap(), - transaction::KernelFeatures::Plain { - fee: 26_000_000.into() - } + |api| api.receive_tx(&s, None, None).map(|_| ()), ); + if bhv <= GRIN_BLOCK_HEADER_VERSION { + assert!(matches!( + res, + Err(libwallet::Error::TransactionAlreadyReceived(_)) + )); + } else { + assert!(matches!(res, Err(libwallet::Error::Compatibility(_)))); + } + } + api1.tx_lock_outputs(mask1, &slate)?; + slate = api1.finalize_tx(mask1, &slate)?; + assert_eq!(slate.state, SlateState::Standard3); - Ok(()) - }, - )?; + // Check we have a single kernel and that it is a Plain kernel (no lock_height). + // fees for 7 inputs, 2 outputs, 1 kernel (weight 52) + assert_eq!(slate.tx_or_err()?.kernels().len(), 1); + assert_eq!( + slate + .tx_or_err()? + .kernels() + .first() + .map(|k| k.features) + .unwrap(), + transaction::KernelFeatures::Plain { + fee: 26_000_000.into() + } + ); + } // Check transaction log for wallet 1 - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - let fee = core::libtx::tx_fee( - wallet1_info.last_confirmed_height as usize - cm as usize, - 2, - 1, - ); - // we should have a transaction entry for this slate - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - let tx = tx.unwrap(); - assert!(!tx.confirmed); - assert!(tx.confirmation_ts.is_none()); - assert_eq!(tx.amount_debited - tx.amount_credited, fee + amount); - println!("tx: {:?}", tx); - assert_eq!(Some(fee.try_into().unwrap()), tx.fee); - Ok(()) - }, - )?; + { + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert!(refreshed); + let fee = core::libtx::tx_fee( + wallet1_info.last_confirmed_height as usize - cm as usize, + 2, + 1, + ); + // we should have a transaction entry for this slate + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + let tx = tx.unwrap(); + assert!(!tx.confirmed); + assert!(tx.confirmation_ts.is_none()); + assert_eq!(tx.amount_debited - tx.amount_credited, fee + amount); + println!("tx: {:?}", tx); + assert_eq!(Some(fee.try_into().unwrap()), tx.fee); + } // Check transaction log for wallet 2 - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - // we should have a transaction entry for this slate - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - let tx = tx.unwrap(); - assert!(!tx.confirmed); - assert!(tx.confirmation_ts.is_none()); - assert_eq!(amount, tx.amount_credited); - assert_eq!(0, tx.amount_debited); - assert_eq!(None, tx.fee); - Ok(()) - }, - )?; + { + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert!(refreshed); + // we should have a transaction entry for this slate + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + let tx = tx.unwrap(); + assert!(!tx.confirmed); + assert!(tx.confirmation_ts.is_none()); + assert_eq!(amount, tx.amount_credited); + assert_eq!(0, tx.amount_debited); + assert_eq!(None, tx.fee); + } // post transaction - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.post_tx(m, &slate, false)?; - Ok(()) - }, - )?; + api1.post_tx(mask1, &slate, false)?; - // Check wallet 1 contents are as expected - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - debug!( - "Wallet 1 Info Post Transaction, after {} blocks: {:?}", - wallet1_info.last_confirmed_height, wallet1_info - ); - let fee = core::libtx::tx_fee( - wallet1_info.last_confirmed_height as usize - 1 - cm as usize, - 2, - 1, - ); - assert!(wallet1_refreshed); - // wallet 1 received fees, so amount should be the same - assert_eq!( - wallet1_info.total, - amount * wallet1_info.last_confirmed_height - amount - ); - assert_eq!( - wallet1_info.amount_currently_spendable, - (wallet1_info.last_confirmed_height - cm) * reward - amount - fee - ); - assert_eq!(wallet1_info.amount_immature, cm * reward + fee); + // Check wallet1 contents are as expected + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + debug!( + "Wallet 1 Info Post Transaction, after {} blocks: {:?}", + wallet1_info.last_confirmed_height, wallet1_info + ); + let fee = core::libtx::tx_fee( + wallet1_info.last_confirmed_height as usize - 1 - cm as usize, + 2, + 1, + ); + assert!(wallet1_refreshed); + // wallet 1 received fees, so amount should be the same + assert_eq!( + wallet1_info.total, + amount * wallet1_info.last_confirmed_height - amount + ); + assert_eq!( + wallet1_info.amount_currently_spendable, + (wallet1_info.last_confirmed_height - cm) * reward - amount - fee + ); + assert_eq!(wallet1_info.amount_immature, cm * reward + fee); - // check tx log entry is confirmed - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - let tx = tx.unwrap(); - assert!(tx.confirmed); - assert!(tx.confirmation_ts.is_some()); - - Ok(()) - }, - )?; + // check tx log entry is confirmed + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert!(refreshed); + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + let tx = tx.unwrap(); + assert!(tx.confirmed); + assert!(tx.confirmation_ts.is_some()); + } // mine a few more blocks let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); // refresh wallets and retrieve info/tests for each wallet after maturity - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - debug!("Wallet 1 Info: {:?}", wallet1_info); - assert!(wallet1_refreshed); - assert_eq!( - wallet1_info.total, - amount * wallet1_info.last_confirmed_height - amount - ); - assert_eq!( - wallet1_info.amount_currently_spendable, - (wallet1_info.last_confirmed_height - cm - 1) * reward - ); - Ok(()) - }, - )?; + { + let (wallet1_refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + debug!("Wallet 1 Info: {:?}", wallet1_info); + assert!(wallet1_refreshed); + assert_eq!( + wallet1_info.total, + amount * wallet1_info.last_confirmed_height - amount + ); + assert_eq!( + wallet1_info.amount_currently_spendable, + (wallet1_info.last_confirmed_height - cm - 1) * reward + ); + } - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.amount_currently_spendable, amount); + { + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.amount_currently_spendable, amount); - // check tx log entry is confirmed - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - let tx = tx.unwrap(); - assert!(tx.confirmed); - assert!(tx.confirmation_ts.is_some()); - Ok(()) - }, - )?; + // check tx log entry is confirmed + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert!(refreshed); + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + let tx = tx.unwrap(); + assert!(tx.confirmed); + assert!(tx.confirmation_ts.is_some()); + } // Estimate fee and locked amount for a transaction - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - let init_args = InitTxArgs { - src_acct_name: None, - amount: amount * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - estimate_only: Some(true), - ..Default::default() - }; - let est = sender_api.init_send_tx(m, init_args)?; - assert_eq!(est.amount, 600_000_000_000); - // fees for 5 inputs, 2 outputs, 1 kernel (weight 50) - assert_eq!(est.fee_fields.fee(), 25_000_000); + { + let init_args = InitTxArgs { + src_acct_name: None, + amount: amount * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + estimate_only: Some(true), + ..Default::default() + }; + let est = api1.init_send_tx(mask1, init_args)?; + assert_eq!(est.amount, 600_000_000_000); + // fees for 5 inputs, 2 outputs, 1 kernel (weight 50) + assert_eq!(est.fee_fields.fee(), 25_000_000); - let init_args = InitTxArgs { - src_acct_name: None, - amount: amount * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, //select smallest number - estimate_only: Some(true), - ..Default::default() - }; - let est = sender_api.init_send_tx(m, init_args)?; - assert_eq!(est.amount, 180_000_000_000); - // fees for 3 inputs, 2 outputs, 1 kernel (weight 48) - assert_eq!(est.fee_fields.fee(), 24_000_000); - - Ok(()) - }, - )?; + let init_args = InitTxArgs { + src_acct_name: None, + amount: amount * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, //select smallest number + estimate_only: Some(true), + ..Default::default() + }; + let est = api1.init_send_tx(mask1, init_args)?; + assert_eq!(est.amount, 180_000_000_000); + // fees for 3 inputs, 2 outputs, 1 kernel (weight 48) + assert_eq!(est.fee_fields.fee(), 24_000_000); + } // Send another transaction, but don't post to chain immediately and use // the stored transaction instead - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: amount * 2, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; - slate = sender_api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; + { + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount: amount * 2, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; + slate = api1.finalize_tx(mask1, &slate)?; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - let (refreshed, _wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - let (_, txs) = sender_api.retrieve_txs(m, true, None, None, None)?; - // find the transaction - let tx = txs - .iter() - .find(|t| t.tx_slate_id == Some(slate.id)) - .unwrap(); - let stored_tx_slate = sender_api - .get_stored_tx(m, None, Some(&tx.tx_slate_id.unwrap()))? - .unwrap(); - sender_api.post_tx(m, &stored_tx_slate, false)?; - let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?; - // should be mined now - assert_eq!( - wallet1_info.total, - amount * wallet1_info.last_confirmed_height - amount * 3 - ); - Ok(()) - }, - )?; + let (refreshed, _wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(refreshed); + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + // find the transaction + let tx = txs + .iter() + .find(|t| t.tx_slate_id == Some(slate.id)) + .unwrap(); + let stored_tx_slate = api1 + .get_stored_tx(mask1, None, Some(&tx.tx_slate_id.unwrap()))? + .unwrap(); + api1.post_tx(mask1, &stored_tx_slate, false)?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + // should be mined now + assert_eq!( + wallet1_info.total, + amount * wallet1_info.last_confirmed_height - amount * 3 + ); + } // mine a few more blocks let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false); // check wallet2 has stored transaction - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(wallet2_refreshed); - assert_eq!(wallet2_info.amount_currently_spendable, amount * 3); + { + let (wallet2_refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet2_refreshed); + assert_eq!(wallet2_info.amount_currently_spendable, amount * 3); - // check tx log entry is confirmed - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - let tx = tx.unwrap(); - assert!(tx.confirmed); - assert!(tx.confirmation_ts.is_some()); - Ok(()) - }, - )?; + // check tx log entry is confirmed + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert!(refreshed); + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + let tx = tx.unwrap(); + assert!(tx.confirmed); + assert!(tx.confirmation_ts.is_some()); + } // try to send a transaction with amount inclusive of fees, but amount too // small to cover fees. Should fail. - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: 1, - amount_includes_fee: Some(true), - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let res = sender_api.init_send_tx(m, args); - assert!(res.is_err()); - Ok(()) - }, - )?; + { + let args = InitTxArgs { + src_acct_name: None, + amount: 1, + amount_includes_fee: Some(true), + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let res = api1.init_send_tx(mask1, args); + assert!(res.is_err()); + } + + // Multiple send attempts, make sure same outputs not locked. + // Fail sending without starting Tor + api2.set_tor_config(Some(grin_wallet_config::TorConfig { + use_integrated: Some(false), + socks_proxy_addr: "invalid".into(), + ..Default::default() + }))?; + let mut handles = vec![]; + + let api2_1 = Owner::new(api2.wallet_inst.clone(), None, api2.config_path()); + handles.push(thread::spawn(move || { + let args = InitTxArgs { + src_acct_name: None, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + amount: 1, + send_args: Some(InitTxSendArgs { + dest: "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp".into(), + post_tx: false, + fluff: false, + skip_tor: Some(false), + }), + ..Default::default() + }; + api2_1.init_send_tx(None, args) + })); + let api2_2 = Owner::new(api2.wallet_inst.clone(), None, api2.config_path()); + handles.push(thread::spawn(move || { + let args = InitTxArgs { + src_acct_name: None, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + amount: 1, + send_args: Some(InitTxSendArgs { + dest: "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp".into(), + post_tx: false, + fluff: false, + skip_tor: Some(false), + }), + ..Default::default() + }; + api2_2.init_send_tx(None, args) + })); + let results: Vec<_> = handles + .into_iter() + .map(|handle| handle.join().unwrap()) + .collect(); + assert_eq!(results.iter().filter(|r| { r.is_ok() }).count(), 1); + let err_res = results.iter().find(|r| r.is_err()).unwrap(); + assert!(matches!( + err_res.as_ref().err().unwrap(), + libwallet::Error::NotEnoughFunds { .. } + )); // try to build a transaction with amount inclusive of fees. Confirm that tx // amount + fee is equal to the originally specified amount let amount = 60_000_000_000; - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: amount, - amount_includes_fee: Some(true), - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - assert_eq!(slate_i.state, SlateState::Standard1); - let total_spend: u64 = slate_i.amount + slate_i.fee_fields.fee(); - assert_eq!(amount, total_spend); - Ok(()) - }, - )?; + { + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + amount_includes_fee: Some(true), + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + assert_eq!(slate_i.state, SlateState::Standard1); + let total_spend: u64 = slate_i.amount + slate_i.fee_fields.fee(); + assert_eq!(amount, total_spend); + } // let logging finish stopper.store(false, Ordering::Relaxed); @@ -557,7 +527,8 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -568,7 +539,8 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -586,159 +558,121 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> { let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false); let amount = 30_000_000_000; - let mut slate = Slate::blank(1, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ..Default::default() - }; + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ..Default::default() + }; - let slate_i = sender_api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; - slate = sender_api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; + let slate_i = api1.init_send_tx(mask1, args)?; + let mut slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; + slate = api1.finalize_tx(mask1, &slate)?; // Check transaction log for wallet 1 - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - println!( - "last confirmed height: {}", - wallet1_info.last_confirmed_height - ); - assert!(refreshed); - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - // we should have a transaction entry for this slate - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - let mut locked_count = 0; - let mut unconfirmed_count = 0; - // get the tx entry, check outputs are as expected - let (_, output_mappings) = - api.retrieve_outputs(m, true, false, Some(tx.unwrap().id))?; - for m in output_mappings.clone() { - if m.output.status == OutputStatus::Locked { - locked_count = locked_count + 1; - } - if m.output.status == OutputStatus::Unconfirmed { - unconfirmed_count = unconfirmed_count + 1; - } + { + let (refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + println!( + "last confirmed height: {}", + wallet1_info.last_confirmed_height + ); + assert!(refreshed); + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + // we should have a transaction entry for this slate + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + let mut locked_count = 0; + let mut unconfirmed_count = 0; + // get the tx entry, check outputs are as expected + let (_, output_mappings) = + api1.retrieve_outputs(mask1, true, false, Some(tx.unwrap().id))?; + for m in output_mappings.clone() { + if m.output.status == OutputStatus::Locked { + locked_count = locked_count + 1; } - assert_eq!(output_mappings.len(), 3); - assert_eq!(locked_count, 2); - assert_eq!(unconfirmed_count, 1); - - Ok(()) - }, - )?; + if m.output.status == OutputStatus::Unconfirmed { + unconfirmed_count = unconfirmed_count + 1; + } + } + assert_eq!(output_mappings.len(), 3); + assert_eq!(locked_count, 2); + assert_eq!(unconfirmed_count, 1); + } // Check transaction log for wallet 2 - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - let mut unconfirmed_count = 0; - let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); - assert!(tx.is_some()); - // get the tx entry, check outputs are as expected - let (_, outputs) = api.retrieve_outputs(m, true, false, Some(tx.unwrap().id))?; - for m in outputs.clone() { - if m.output.status == OutputStatus::Unconfirmed { - unconfirmed_count = unconfirmed_count + 1; - } + { + let (refreshed, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + assert!(refreshed); + let mut unconfirmed_count = 0; + let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id)); + assert!(tx.is_some()); + // get the tx entry, check outputs are as expected + let (_, outputs) = api2.retrieve_outputs(mask2, true, false, Some(tx.unwrap().id))?; + for m in outputs.clone() { + if m.output.status == OutputStatus::Unconfirmed { + unconfirmed_count = unconfirmed_count + 1; } - assert_eq!(outputs.len(), 1); - assert_eq!(unconfirmed_count, 1); - let (refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - assert_eq!(wallet2_info.amount_currently_spendable, 0,); - assert_eq!(wallet2_info.amount_awaiting_finalization, amount); - Ok(()) - }, - )?; + } + assert_eq!(outputs.len(), 1); + assert_eq!(unconfirmed_count, 1); + let (refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + assert_eq!(wallet2_info.amount_currently_spendable, 0,); + assert_eq!(wallet2_info.amount_awaiting_finalization, amount); + } // wallet 1 is bold and doesn't ever post the transaction // mine a few more blocks let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false); // Wallet 1 decides to roll back instead - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - // can't roll back coinbase - let res = api.cancel_tx(m, Some(1), None); - assert!(res.is_err()); - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - let tx = txs - .iter() - .find(|t| t.tx_slate_id == Some(slate.id)) - .unwrap(); - api.cancel_tx(m, Some(tx.id), None)?; - let (refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - println!( - "last confirmed height: {}", - wallet1_info.last_confirmed_height - ); - // check all eligible inputs should be now be spendable - println!("cm: {}", cm); - assert_eq!( - wallet1_info.amount_currently_spendable, - (wallet1_info.last_confirmed_height - cm) * reward - ); - // can't roll back again - let res = api.cancel_tx(m, Some(tx.id), None); - assert!(res.is_err()); - - Ok(()) - }, - )?; - + { + // can't roll back coinbase + let res = api1.cancel_tx(mask1, Some(1), None); + assert!(res.is_err()); + let (_, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + let tx = txs + .iter() + .find(|t| t.tx_slate_id == Some(slate.id)) + .unwrap(); + api1.cancel_tx(mask1, Some(tx.id), None)?; + let (refreshed, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + assert!(refreshed); + println!( + "last confirmed height: {}", + wallet1_info.last_confirmed_height + ); + // check all eligible inputs should be now be spendable + println!("cm: {}", cm); + assert_eq!( + wallet1_info.amount_currently_spendable, + (wallet1_info.last_confirmed_height - cm) * reward + ); + // can't roll back again + let res = api1.cancel_tx(mask1, Some(tx.id), None); + assert!(res.is_err()); + } // Wallet 2 rolls back - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - let tx = txs - .iter() - .find(|t| t.tx_slate_id == Some(slate.id)) - .unwrap(); - api.cancel_tx(m, Some(tx.id), None)?; - let (refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?; - assert!(refreshed); - // check all eligible inputs should be now be spendable - assert_eq!(wallet2_info.amount_currently_spendable, 0,); - assert_eq!(wallet2_info.total, 0,); - // can't roll back again - let res = api.cancel_tx(m, Some(tx.id), None); - assert!(res.is_err()); - - Ok(()) - }, - )?; + { + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + let tx = txs + .iter() + .find(|t| t.tx_slate_id == Some(slate.id)) + .unwrap(); + api2.cancel_tx(mask2, Some(tx.id), None)?; + let (refreshed, wallet2_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(refreshed); + // check all eligible inputs should be now be spendable + assert_eq!(wallet2_info.amount_currently_spendable, 0,); + assert_eq!(wallet2_info.total, 0,); + // can't roll back again + let res = api2.cancel_tx(mask2, Some(tx.id), None); + assert!(res.is_err()); + } // let logging finish stopper.store(false, Ordering::Relaxed); @@ -760,7 +694,8 @@ fn big_amount_error(test_dir: &'static str) -> Result<(), libwallet::Error> { "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); println!("Mask1: {:?}", mask1); @@ -783,50 +718,35 @@ fn big_amount_error(test_dir: &'static str) -> Result<(), libwallet::Error> { let min_confirmations = 1; // Check wallet 1 content are as expected - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (wallet1_refreshed, wallet1_info) = - api.retrieve_summary_info(m, true, min_confirmations)?; - println!( - "Wallet 1 Info Pre-Transaction, after {} blocks: {:?}", - wallet1_info.last_confirmed_height, wallet1_info - ); - assert!(wallet1_refreshed); - assert_eq!( - wallet1_info.amount_currently_spendable, - (wallet1_info.last_confirmed_height - cm) * reward - ); - assert_eq!(wallet1_info.amount_immature, cm * reward); - Ok(()) - }, - )?; + { + let (wallet1_refreshed, wallet1_info) = + api1.retrieve_summary_info(mask1, true, min_confirmations)?; + println!( + "Wallet 1 Info Pre-Transaction, after {} blocks: {:?}", + wallet1_info.last_confirmed_height, wallet1_info + ); + assert!(wallet1_refreshed); + assert_eq!( + wallet1_info.amount_currently_spendable, + (wallet1_info.last_confirmed_height - cm) * reward + ); + assert_eq!(wallet1_info.amount_immature, cm * reward); + } // test selecting max amount - let result = wallet::controller::owner_single_use( - wallet1.clone(), + let result = api1.init_send_tx( mask1, - PathBuf::from(test_dir), - |api, m| { - api.init_send_tx( - m, - InitTxArgs { - amount: (reward * outputs_num as u64) - (cm * reward), - amount_includes_fee: Some(true), - minimum_confirmations: 0, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - refresh_outputs_from_node: true, - ..InitTxArgs::default() - }, - )?; - Ok(()) + InitTxArgs { + amount: (reward * outputs_num as u64) - (cm * reward), + amount_includes_fee: Some(true), + minimum_confirmations: 0, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + refresh_outputs_from_node: true, + ..InitTxArgs::default() }, ); - println!("{:?}", result); let max_tx_weight = global::max_tx_weight(); @@ -844,19 +764,11 @@ fn big_amount_error(test_dir: &'static str) -> Result<(), libwallet::Error> { Ok(_) => {} Err(e) => match e { libwallet::Error::BigAmountError(a, fee, num_inputs) => { - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, e_a, e_fee, e_num_inputs) = - api.estimate_max_sendable(m, true, min_confirmations)?; - assert_eq!(e_a, a - fee); - assert_eq!(e_fee, fee); - assert_eq!(e_num_inputs, num_inputs); - Ok(()) - }, - )?; + let (_, e_a, e_fee, e_num_inputs) = + api1.estimate_max_sendable(mask1, true, min_confirmations)?; + assert_eq!(e_a, a - fee); + assert_eq!(e_fee, fee); + assert_eq!(e_num_inputs, num_inputs); } _ => {} }, diff --git a/controller/tests/ttl_cutoff.rs b/controller/tests/ttl_cutoff.rs index faa3990..4c9bd12 100644 --- a/controller/tests/ttl_cutoff.rs +++ b/controller/tests/ttl_cutoff.rs @@ -20,8 +20,7 @@ extern crate grin_wallet_util; use grin_wallet_libwallet as libwallet; use impls::test_framework::{self, LocalWalletClient}; -use libwallet::{InitTxArgs, Slate, TxLogEntryType}; -use std::path::PathBuf; +use libwallet::{InitTxArgs, TxLogEntryType}; use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; @@ -45,7 +44,8 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); @@ -58,7 +58,8 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -78,126 +79,76 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false); let amount = 60_000_000_000; - let mut slate = Slate::blank(1, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ttl_blocks: Some(2), - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ttl_blocks: Some(2), + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; + let mut slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; - let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?; - let tx = txs[0].clone(); + let (_, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + let tx = txs[0].clone(); - assert_eq!(tx.ttl_cutoff_height, Some(12)); - Ok(()) - }, - )?; + assert_eq!(tx.ttl_cutoff_height, Some(12)); // Now mine past the block, and check again. Transaction should be gone. let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?; - let tx = txs[0].clone(); + let (_, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + let tx = txs[0].clone(); - assert_eq!(tx.ttl_cutoff_height, Some(12)); - assert_eq!(tx.tx_type, TxLogEntryType::TxSentCancelled); - Ok(()) - }, - )?; + assert_eq!(tx.ttl_cutoff_height, Some(12)); + assert_eq!(tx.tx_type, TxLogEntryType::TxSentCancelled); // Should also be gone in wallet 2, and output gone - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |sender_api, m| { - let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?; - let tx = txs[0].clone(); - let outputs = sender_api.retrieve_outputs(m, false, true, None)?.1; - assert_eq!(outputs.len(), 0); + let (_, txs) = api2.retrieve_txs(mask2, true, None, Some(slate.id), None)?; + let tx = txs[0].clone(); + let outputs = api2.retrieve_outputs(mask2, false, true, None)?.1; + assert_eq!(outputs.len(), 0); - assert_eq!(tx.ttl_cutoff_height, Some(12)); - assert_eq!(tx.tx_type, TxLogEntryType::TxReceivedCancelled); - Ok(()) - }, - )?; + assert_eq!(tx.ttl_cutoff_height, Some(12)); + assert_eq!(tx.tx_type, TxLogEntryType::TxReceivedCancelled); // try again, except try and send off the transaction for completion beyond the expiry - let mut slate = Slate::blank(1, false); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount, - minimum_confirmations: 2, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: true, - ttl_blocks: Some(2), - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - sender_api.tx_lock_outputs(m, &slate_i)?; - slate = slate_i; + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 2, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: true, + ttl_blocks: Some(2), + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + api1.tx_lock_outputs(mask1, &slate_i)?; + slate = slate_i; - let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?; - let tx = txs[0].clone(); + let (_, txs) = api1.retrieve_txs(mask1, true, None, Some(slate.id), None)?; + let tx = txs[0].clone(); - assert_eq!(tx.ttl_cutoff_height, Some(14)); - Ok(()) - }, - )?; + assert_eq!(tx.ttl_cutoff_height, Some(14)); // Mine past the ttl block and try to send let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false); // Wallet 2 will need to have updated past the TTL - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |sender_api, m| { - let (_, _) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?; - Ok(()) - }, - )?; + let (_, _) = api2.retrieve_txs(mask2, true, None, Some(slate.id), None)?; // And when wallet 1 sends, should be rejected - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |_sender_api, _m| { - let res = client1.send_tx_slate_direct("wallet2", &slate); - println!("Send after TTL result is: {:?}", res); - assert!(res.is_err()); - Ok(()) - }, - )?; + let res = client1.send_tx_slate_direct("wallet2", &slate); + println!("Send after TTL result is: {:?}", res); + assert!(res.is_err()); // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/tx_list_filter.rs b/controller/tests/tx_list_filter.rs index c7fa9c8..cc63c15 100644 --- a/controller/tests/tx_list_filter.rs +++ b/controller/tests/tx_list_filter.rs @@ -23,210 +23,183 @@ use grin_core as core; use grin_keychain as keychain; use grin_util as util; use libwallet::{RetrieveTxQueryArgs, RetrieveTxQuerySortField}; -use std::path::PathBuf; -use self::libwallet::{InitTxArgs, Slate}; +use self::libwallet::InitTxArgs; use impls::test_framework::{self, LocalWalletClient}; -use std::sync::{atomic::Ordering, Arc}; +use std::sync::atomic::Ordering; use std::thread; use std::time::Duration; use util::secp::key::SecretKey; -use util::Mutex; use self::keychain::ExtKeychain; -use self::libwallet::WalletInst; use impls::DefaultLCProvider; mod common; use common::{clean_output_dir, create_wallet_proxy, setup}; +use grin_wallet_api::Owner; fn test_wallet_tx_filtering( - wallet: Arc< - Mutex< - Box< - dyn WalletInst< - 'static, - DefaultLCProvider, - LocalWalletClient, - ExtKeychain, - >, - >, - >, - >, mask: Option<&SecretKey>, - test_dir: &'static str, + api: Owner, LocalWalletClient, ExtKeychain>, ) -> Result<(), libwallet::Error> { - wallet::controller::owner_single_use( - wallet.clone(), - mask, - PathBuf::from(test_dir), - |api, _m| { - let query = |args| { - api.retrieve_txs(mask, true, None, None, Some(args)) - .map(|(_, txs)| txs) - }; - let txs = query(RetrieveTxQueryArgs::default())?; - assert!(!txs.is_empty()); - let before_first_tx = - txs.iter().map(|tx| tx.creation_ts).min().unwrap() - Duration::from_secs(1); - let mut tx_query_args = RetrieveTxQueryArgs::default(); + let query = |args| { + api.retrieve_txs(mask, true, None, None, Some(args)) + .map(|(_, txs)| txs) + }; + let txs = query(RetrieveTxQueryArgs::default())?; + assert!(!txs.is_empty()); + let before_first_tx = + txs.iter().map(|tx| tx.creation_ts).min().unwrap() - Duration::from_secs(1); + let mut tx_query_args = RetrieveTxQueryArgs::default(); - // Max creation time before all test transactions - tx_query_args.max_creation_timestamp = Some(before_first_tx); - assert!(query(tx_query_args.clone())?.is_empty()); + // Max creation time before all test transactions + tx_query_args.max_creation_timestamp = Some(before_first_tx); + assert!(query(tx_query_args.clone())?.is_empty()); - // Min confirmation time should not affect creation time - tx_query_args.max_creation_timestamp = None; - tx_query_args.min_confirmed_timestamp = Some(before_first_tx); - assert_eq!(query(tx_query_args)?.len(), txs.len()); + // Min confirmation time should not affect creation time + tx_query_args.max_creation_timestamp = None; + tx_query_args.min_confirmed_timestamp = Some(before_first_tx); + assert_eq!(query(tx_query_args)?.len(), txs.len()); - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.min_id = Some(5); + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.min_id = Some(5); - // Min ID - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results[0].id, 5); - assert_eq!(tx_results[tx_results.len() - 1].id, 33); + // Min ID + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results[0].id, 5); + assert_eq!(tx_results[tx_results.len() - 1].id, 33); - // Max ID - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.min_id = Some(5); - tx_query_args.max_id = Some(20); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results[0].id, 5); - assert_eq!(tx_results[tx_results.len() - 1].id, 20); + // Max ID + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.min_id = Some(5); + tx_query_args.max_id = Some(20); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results[0].id, 5); + assert_eq!(tx_results[tx_results.len() - 1].id, 20); - // Exclude 1 cancelled - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.exclude_cancelled = Some(true); - tx_query_args.min_id = Some(5); - tx_query_args.max_id = Some(50); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 28); + // Exclude 1 canceled + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.exclude_cancelled = Some(true); + tx_query_args.min_id = Some(5); + tx_query_args.max_id = Some(50); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 28); - // Exclude 1 cancelled, show confirmed only - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.exclude_cancelled = Some(true); - tx_query_args.include_confirmed_only = Some(true); - tx_query_args.min_id = Some(5); - tx_query_args.max_id = Some(50); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 14); + // Exclude 1 canceled, show confirmed only + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.exclude_cancelled = Some(true); + tx_query_args.include_confirmed_only = Some(true); + tx_query_args.min_id = Some(5); + tx_query_args.max_id = Some(50); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 14); - // show outstanding only (including cancelled) - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.exclude_cancelled = Some(false); - tx_query_args.include_outstanding_only = Some(true); - tx_query_args.min_id = Some(5); - tx_query_args.max_id = Some(50); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 15); + // show outstanding only (including canceled) + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.exclude_cancelled = Some(false); + tx_query_args.include_outstanding_only = Some(true); + tx_query_args.min_id = Some(5); + tx_query_args.max_id = Some(50); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 15); - // outstanding only and confirmed only should give empty set - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.exclude_cancelled = Some(false); - tx_query_args.include_outstanding_only = Some(true); - tx_query_args.include_confirmed_only = Some(true); - tx_query_args.min_id = Some(5); - tx_query_args.max_id = Some(50); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 0); + // outstanding only and confirmed only should give empty set + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.exclude_cancelled = Some(false); + tx_query_args.include_outstanding_only = Some(true); + tx_query_args.include_confirmed_only = Some(true); + tx_query_args.min_id = Some(5); + tx_query_args.max_id = Some(50); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 0); - // include sent only - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.include_sent_only = Some(true); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 15); + // include sent only + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.include_sent_only = Some(true); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 15); - // include received only (none in this set) - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.include_received_only = Some(true); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 0); + // include received only (none in this set) + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.include_received_only = Some(true); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 0); - // include reverted only (none in this set) - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.include_reverted_only = Some(true); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 0); + // include reverted only (none in this set) + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.include_reverted_only = Some(true); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 0); - // include coinbase only - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.include_coinbase_only = Some(true); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 19); + // include coinbase only + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.include_coinbase_only = Some(true); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 19); - // Amounts - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.min_amount = Some(60_000_000_000 - 59_963_300_000); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 27); + // Amounts + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.min_amount = Some(60_000_000_000 - 59_963_300_000); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 27); - // amount, should see as above with coinbases excluded - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.min_amount = Some(60_000_000_000 - 59_963_300_000); - tx_query_args.max_amount = Some(60_000_000_000 - 1); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 8); + // amount, should see as above with coinbases excluded + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.min_amount = Some(60_000_000_000 - 59_963_300_000); + tx_query_args.max_amount = Some(60_000_000_000 - 1); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 8); - // Amount - should only see coinbase (incoming) - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.min_amount = Some(60_000_000_000); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results.len(), 19); + // Amount - should only see coinbase (incoming) + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.min_amount = Some(60_000_000_000); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results.len(), 19); - // sort order - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.sort_order = Some(libwallet::RetrieveTxQuerySortOrder::Desc); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; + // sort order + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.sort_order = Some(libwallet::RetrieveTxQuerySortOrder::Desc); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; - assert_eq!(tx_results[0].id, 33); - assert_eq!(tx_results[tx_results.len() - 1].id, 0); + assert_eq!(tx_results[0].id, 33); + assert_eq!(tx_results[tx_results.len() - 1].id, 0); - // change sort field to amount desc, should have coinbases first - let mut tx_query_args = RetrieveTxQueryArgs::default(); - tx_query_args.sort_order = Some(libwallet::RetrieveTxQuerySortOrder::Desc); - tx_query_args.sort_field = Some(RetrieveTxQuerySortField::TotalAmount); - let tx_results = api - .retrieve_txs(mask, true, None, None, Some(tx_query_args))? - .1; - assert_eq!(tx_results[0].amount_credited, 60_000_000_000); - - /*for entry in tx_results.iter() { - println!("{:?}", entry); - }*/ - - Ok(()) - }, - )?; + // change sort field to amount desc, should have coinbases first + let mut tx_query_args = RetrieveTxQueryArgs::default(); + tx_query_args.sort_order = Some(libwallet::RetrieveTxQuerySortOrder::Desc); + tx_query_args.sort_field = Some(RetrieveTxQuerySortField::TotalAmount); + let tx_results = api + .retrieve_txs(mask, true, None, None, Some(tx_query_args))? + .1; + assert_eq!(tx_results[0].amount_credited, 60_000_000_000); Ok(()) } @@ -248,7 +221,8 @@ fn build_chain_for_tx_filtering( "wallet1", None, &mut wallet_proxy, - true + true, + api1 ); let mask1 = (&mask1_i).as_ref(); debug!("Mask1: {:?}", mask1); @@ -260,7 +234,8 @@ fn build_chain_for_tx_filtering( "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); debug!("Mask2: {:?}", mask2); @@ -274,25 +249,8 @@ fn build_chain_for_tx_filtering( // Stop the scanning updater threads because it extends the time needed to build the chain // exponentially - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, _m| { - api.stop_updater()?; - Ok(()) - }, - )?; - - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, _m| { - api.stop_updater()?; - Ok(()) - }, - )?; + api1.stop_updater()?; + api2.stop_updater()?; // few values to keep things shorter let reward = core::consensus::REWARD; @@ -304,22 +262,14 @@ fn build_chain_for_tx_filtering( let mut wallet_1_has_funds = false; // Check wallet 1 contents - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - debug!( - "Wallet 1 spendable - {}", - wallet1_info.amount_currently_spendable - ); - if wallet1_info.amount_currently_spendable > reward { - wallet_1_has_funds = true; - } - Ok(()) - }, - )?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + debug!( + "Wallet 1 spendable - {}", + wallet1_info.amount_currently_spendable + ); + if wallet1_info.amount_currently_spendable > reward { + wallet_1_has_funds = true; + } if !wallet_1_has_funds { let _ = @@ -331,62 +281,44 @@ fn build_chain_for_tx_filtering( let num_txs = 1; for _ in 0..num_txs { let amount: u64 = i as u64 * 1_000_000; - let mut slate = Slate::blank(1, false); debug!("Creating TX for {}", amount); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { - // note this will increment the block count as part of the transaction "Posting" - let args = InitTxArgs { - src_acct_name: None, - amount: amount, - minimum_confirmations: 1, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - ..Default::default() - }; - let slate_i = sender_api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; - slate = sender_api.finalize_tx(m, &slate)?; - Ok(()) - }, - )?; - } - } - - // Cancel a tx for filtering testing - let amount: u64 = 1_000_000; - let mut slate = Slate::blank(1, false); - debug!("Creating TX for {}", amount); - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |sender_api, m| { // note this will increment the block count as part of the transaction "Posting" let args = InitTxArgs { src_acct_name: None, - amount: amount, + amount, minimum_confirmations: 1, max_outputs: 500, num_change_outputs: 1, selection_strategy_is_use_all: false, ..Default::default() }; - let slate_i = sender_api.init_send_tx(m, args)?; - slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; - sender_api.tx_lock_outputs(m, &slate)?; - sender_api.cancel_tx(m, Some(33), None)?; - Ok(()) - }, - )?; + let slate_i = api1.init_send_tx(mask1, args)?; + let slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; + api1.finalize_tx(mask1, &slate)?; + } + } + + // Cancel a tx for filtering testing + let amount: u64 = 1_000_000; + debug!("Creating TX for {}", amount); + // note this will increment the block count as part of the transaction "Posting" + let args = InitTxArgs { + src_acct_name: None, + amount, + minimum_confirmations: 1, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let slate_i = api1.init_send_tx(mask1, args)?; + let slate = client1.send_tx_slate_direct("wallet2", &slate_i)?; + api1.tx_lock_outputs(mask1, &slate)?; + api1.cancel_tx(mask1, Some(33), None)?; // Perform actual testing - test_wallet_tx_filtering(wallet1, mask1, test_dir)?; + test_wallet_tx_filtering(mask1, api1)?; // let logging finish stopper.store(false, Ordering::Relaxed); diff --git a/controller/tests/updater_thread.rs b/controller/tests/updater_thread.rs index 2beebab..8e33355 100644 --- a/controller/tests/updater_thread.rs +++ b/controller/tests/updater_thread.rs @@ -46,7 +46,8 @@ fn updater_thread_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err "wallet1", None, &mut wallet_proxy, - false + false, + api1 ); let mask1 = (&mask1_i).as_ref(); create_wallet_and_add!( @@ -57,7 +58,8 @@ fn updater_thread_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err "wallet2", None, &mut wallet_proxy, - false + false, + api2 ); let mask2 = (&mask2_i).as_ref(); @@ -69,28 +71,11 @@ fn updater_thread_test_impl(test_dir: &'static str) -> Result<(), libwallet::Err }); // add some accounts - wallet::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "mining")?; - api.create_account_path(m, "listener")?; - Ok(()) - }, - )?; + api1.create_account_path(mask1, "mining")?; + api1.create_account_path(mask1, "listener")?; - // add some accounts - wallet::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.create_account_path(m, "account1")?; - api.create_account_path(m, "account2")?; - Ok(()) - }, - )?; + api2.create_account_path(mask2, "account1")?; + api2.create_account_path(mask2, "account2")?; // Get some mining done { diff --git a/impls/src/adapters/tor.rs b/impls/src/adapters/tor.rs index 1394dd7..63f56c0 100644 --- a/impls/src/adapters/tor.rs +++ b/impls/src/adapters/tor.rs @@ -124,7 +124,7 @@ impl TorSlateSender { let res: String = self.post(url, req).map_err(|e| { let mut report = format!("Performing version check (is recipient listening?): {}", e); let err_string = format!("{}", e); - if err_string.contains("404") { + if !self.config.use_integrated.unwrap_or(false) && err_string.contains("404") { // Report that the other version of the wallet is out of date report = "Other wallet is incompatible and requires an upgrade. \ Please urge the other wallet owner to upgrade and try the transaction again." diff --git a/libwallet/src/mwixnet/onion/onion.rs b/libwallet/src/mwixnet/onion/onion.rs index 8159232..1958e42 100644 --- a/libwallet/src/mwixnet/onion/onion.rs +++ b/libwallet/src/mwixnet/onion/onion.rs @@ -366,7 +366,7 @@ impl From for OnionError { } #[cfg(test)] -pub mod tests { +mod tests { use super::*; use crate::mwixnet::onion::crypto::secp::random_secret; use crate::mwixnet::onion::{new_hop, Hop}; diff --git a/tests/cmd_line_basic.rs b/tests/cmd_line_basic.rs index a4d8308..f54987c 100644 --- a/tests/cmd_line_basic.rs +++ b/tests/cmd_line_basic.rs @@ -21,9 +21,9 @@ extern crate log; extern crate grin_wallet; use grin_wallet_impls::test_framework::{self, LocalWalletClient, WalletProxy}; -use std::path::PathBuf; use clap::App; +use std::sync::mpsc; use std::thread; use std::time::Duration; @@ -32,9 +32,23 @@ use grin_wallet_impls::DefaultLCProvider; mod common; use common::{clean_output_dir, execute_command, initial_setup_wallet, instantiate_wallet, setup}; +use grin_wallet_api::Owner; +use grin_wallet_libwallet::{OutputStatus, TxLogEntryType}; /// command line tests fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller::Error> { + let (logs_tx, logs_rx) = mpsc::sync_channel(100); + let panic_hook = std::panic::take_hook(); + grin_util::init_logger( + Some(grin_util::logger::LoggingConfig { + log_to_file: false, + stdout_log_level: log::Level::Error, + tui_running: Some(true), + ..Default::default() + }), + Some(logs_tx), + ); + std::panic::set_hook(panic_hook); setup(test_dir); // Create a new proxy to simulate server and wallet responses let mut wallet_proxy: WalletProxy< @@ -158,15 +172,9 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: let (wallet1, mask1_i) = instantiate_wallet(wallet_config1, client1.clone(), "password1", "default")?; let mask1 = (&mask1_i).as_ref(); - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - Ok(()) - }, - )?; + let api1 = Owner::new(wallet1.clone(), None, config1.config_file_path.clone()); + + api1.set_active_account(mask1, "mining")?; let mut bh = 10u64; let _ = @@ -236,23 +244,16 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: "default", )?; let mask1 = (&mask1_i).as_ref(); + let api1 = Owner::new(wallet1.clone(), None, config1.config_file_path.clone()); // Check our transaction log, should have 10 entries - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - assert_eq!(txs.len(), bh as usize); - for t in txs { - assert!(t.kernel_excess.is_some()); - } - Ok(()) - }, - )?; + api1.set_active_account(mask1, "mining")?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert!(refreshed); + assert_eq!(txs.len(), bh as usize); + for t in txs { + assert!(t.kernel_excess.is_some()); + } let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false); bh += 10; @@ -273,33 +274,17 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: "default", )?; let mask2 = (&mask2_i).as_ref(); + let api2 = Owner::new(wallet2.clone(), None, config2.config_file_path.clone()); - grin_wallet_controller::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "account_1")?; - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - assert_eq!(wallet1_info.last_confirmed_height, bh); - assert_eq!(wallet1_info.amount_currently_spendable, 10_000_000_000); - Ok(()) - }, - )?; + api2.set_active_account(mask2, "account_1")?; + let (_, wallet1_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert_eq!(wallet1_info.last_confirmed_height, bh); + assert_eq!(wallet1_info.amount_currently_spendable, 10_000_000_000); // Send to wallet 2 with --amount_includes_fee - let mut old_balance = 0; - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - old_balance = wallet1_info.amount_currently_spendable; - Ok(()) - }, - )?; + api1.set_active_account(mask1, "mining")?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + let old_balance = wallet1_info.amount_currently_spendable; let arg_vec = vec![ "grin-wallet", "-p", @@ -349,22 +334,14 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: // Check the new balance of wallet 1 reduced by EXACTLY the tx amount (instead of amount + fee) // This confirms that the TX amount was correctly computed to allow for the fee - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?; - // make sure the new balance is exactly equal to the old balance - the tx amount + the amount mined since then - let amt_mined = 10 * 60_000_000_000; - assert_eq!( - wallet1_info.amount_currently_spendable + 10_000_000_000, - old_balance + amt_mined - ); - Ok(()) - }, - )?; + api1.set_active_account(mask1, "mining")?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 1)?; + // make sure the new balance is exactly equal to the old balance - the tx amount + the amount mined since then + let amt_mined = 10 * 60_000_000_000; + assert_eq!( + wallet1_info.amount_currently_spendable + 10_000_000_000, + old_balance + amt_mined + ); // Send encrypted from wallet 1 to wallet 2 // output wallet 2's address for test creation purposes, @@ -435,19 +412,12 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: "default", )?; let mask1 = (&mask1_i).as_ref(); + let api1 = Owner::new(wallet1.clone(), None, config1.config_file_path.clone()); - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - assert_eq!(txs.len(), bh as usize); - Ok(()) - }, - )?; + api1.set_active_account(mask1, "mining")?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert!(refreshed); + assert_eq!(txs.len(), bh as usize); // Send to self let arg_vec = vec![ @@ -508,19 +478,12 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: "default", )?; let mask1 = (&mask1_i).as_ref(); + let api1 = Owner::new(wallet1.clone(), None, config1.config_file_path.clone()); - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?; - assert!(refreshed); - assert_eq!(txs.len(), bh as usize + 1); - Ok(()) - }, - )?; + api1.set_active_account(mask1, "mining")?; + let (refreshed, txs) = api1.retrieve_txs(mask1, true, None, None, None)?; + assert!(refreshed); + assert_eq!(txs.len(), bh as usize + 1); // Another file exchange, don't send, but unlock with repair command let arg_vec = vec![ @@ -649,24 +612,15 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: execute_command(&app, test_dir, "wallet2", &client2, arg_vec)?; // get tx output via -tx parameter - let mut tx_id = "".to_string(); - grin_wallet_controller::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "default")?; - let (_, txs) = api.retrieve_txs(m, true, None, None, None)?; - let some_tx_id = txs[0].tx_slate_id.clone(); - assert!(some_tx_id.is_some()); - tx_id = some_tx_id.unwrap().to_string().clone(); - Ok(()) - }, - )?; + api2.set_active_account(mask2, "default")?; + let (_, txs) = api2.retrieve_txs(mask2, true, None, None, None)?; + let some_tx_id = txs[0].tx_slate_id.clone(); + assert!(some_tx_id.is_some()); + let tx_id = some_tx_id.unwrap().to_string().clone(); let arg_vec = vec!["grin-wallet", "-p", "password2", "txs", "-t", &tx_id[..]]; execute_command(&app, test_dir, "wallet2", &client2, arg_vec)?; - // bit of mining + // a bit of mining let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false); // Test wallet sweep @@ -717,21 +671,77 @@ fn command_line_test_impl(test_dir: &str) -> Result<(), grin_wallet_controller:: // Check wallet 1 is now empty, except for immature coinbase outputs from recent mining), // and recently matured coinbase outputs, which were not mature at time of spending. // This confirms that the TX amount was correctly computed to allow for the fee - grin_wallet_controller::controller::owner_single_use( - wallet1.clone(), - mask1, - PathBuf::from(test_dir), - |api, m| { - api.set_active_account(m, "mining")?; - let (_, wallet1_info) = api.retrieve_summary_info(m, true, 10)?; - // Entire 'spendable' wallet balance should have been swept, except the coinbase outputs - // which matured in the last batch of mining. Check that the new spendable balance is - // exactly equal to those matured coins. - let amt_mined = 10 * 60_000_000_000; - assert_eq!(wallet1_info.amount_currently_spendable, amt_mined); - Ok(()) - }, - )?; + api1.set_active_account(mask1, "mining")?; + let (_, wallet1_info) = api1.retrieve_summary_info(mask1, true, 10)?; + // Entire 'spendable' wallet balance should have been swept, except the coinbase outputs + // which matured in the last batch of mining. Check that the new spendable balance is + // exactly equal to those matured coins. + let amt_mined = 10 * 60_000_000_000; + assert_eq!(wallet1_info.amount_currently_spendable, amt_mined); + + // Failed send, with --late-lock, make sure outputs not locked (amount not changed). + api2.set_active_account(mask2, "account_1")?; + let (_, txs_before) = api2.retrieve_txs(mask2, false, None, None, None)?; + let (_, wallet1_info) = api2.retrieve_summary_info(mask2, true, 1)?; + let old_balance = wallet1_info.amount_currently_spendable; + let mut arg_vec = vec![ + "grin-wallet", + "-p", + "password2", + "-a", + "account_1", + "send", + "-d", + "tgrin1xtxavwfgs48ckf3gk8wwgcndmn0nt4tvkl8a7ltyejjcy2mc6nfs9gm2lp", + "1", + "--late-lock", + ]; + let args = app.clone().get_matches_from(arg_vec.clone()); + let mut config = initial_setup_wallet(test_dir, "wallet2"); + config.members.tor = Some(grin_wallet_config::TorConfig { + use_integrated: Some(false), + socks_proxy_addr: "invalid".into(), + ..Default::default() + }); + let send = |args: &clap::ArgMatches| -> Result<(), grin_wallet_controller::Error> { + logs_rx.try_iter().for_each(drop); + grin_wallet::cmd::wallet_args::wallet_command( + args, + config.clone(), + client2.clone(), + false, + |_| {}, + )?; + assert!(logs_rx.try_iter().any(|entry| { + entry.log.contains("Error sending slate sync:") && entry.log.contains("AddrParseError") + })); + Ok(()) + }; + send(&args)?; + api2.set_active_account(mask2, "account_1")?; + let (_, txs_after) = api2.retrieve_txs(mask2, false, None, None, None)?; + assert_eq!(txs_before.len(), txs_after.len()); + let (_, wallet1_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert_eq!(old_balance, wallet1_info.amount_currently_spendable); + + // The same failure without late locking leaves one transaction and locked outputs + arg_vec.pop(); + let args = app.clone().get_matches_from(arg_vec); + send(&args)?; + let (_, txs_after) = api2.retrieve_txs(mask2, false, None, None, None)?; + assert_eq!(txs_after.len(), txs_before.len() + 1); + let tx = txs_after + .iter() + .find(|tx| !txs_before.iter().any(|before| before.id == tx.id)) + .unwrap(); + assert_eq!(tx.tx_type, TxLogEntryType::TxSent); + assert!(tx.tx_slate_id.is_some()); + let (_, outputs) = api2.retrieve_outputs(mask2, false, false, Some(tx.id))?; + assert!(outputs + .iter() + .any(|output| output.output.status == OutputStatus::Locked)); + let (_, wallet_info) = api2.retrieve_summary_info(mask2, true, 1)?; + assert!(wallet_info.amount_currently_spendable < old_balance); // let logging finish thread::sleep(Duration::from_millis(200)); diff --git a/tests/owner_v3_lifecycle.rs b/tests/owner_v3_lifecycle.rs index 997bdb3..bf6711e 100644 --- a/tests/owner_v3_lifecycle.rs +++ b/tests/owner_v3_lifecycle.rs @@ -19,7 +19,7 @@ extern crate log; extern crate grin_wallet; -use grin_wallet_api::{ECDHPubkey, JsonId}; +use grin_wallet_api::{ECDHPubkey, JsonId, Owner}; use grin_wallet_impls::test_framework::{self, LocalWalletClient, WalletProxy}; use clap::App; @@ -64,7 +64,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { >, >, > = Arc::new(Mutex::new(WalletProxy::new(test_dir))); - let (chain, wallet2, mask2_i) = { + let (chain, wallet2, mask2_i, config2) = { let mut wallet_proxy = wallet_proxy_a.lock(); let chain = wallet_proxy.chain.clone(); @@ -118,7 +118,7 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { ) .unwrap(); }); - (chain, wallet2, mask2_i) + (chain, wallet2, mask2_i, config2) }; // give a bit for wallet to init and populate proxy with wallet via callback in thread above thread::sleep(Duration::from_millis(500)); @@ -402,27 +402,20 @@ fn owner_v3_lifecycle() -> Result<(), grin_wallet_controller::Error> { let mut slate: Slate = res.unwrap().into(); // give this slate over to wallet 2 manually - grin_wallet_controller::controller::owner_single_use( - wallet2.clone(), - mask2, - PathBuf::from(test_dir), - |api, m| { - let args = InitTxArgs { - src_acct_name: None, - amount: slate.amount, - minimum_confirmations: 1, - max_outputs: 500, - num_change_outputs: 1, - selection_strategy_is_use_all: false, - ..Default::default() - }; - let res = api.process_invoice_tx(m, &slate, args); - assert!(res.is_ok()); - slate = res.unwrap(); - api.tx_lock_outputs(m, &slate)?; - Ok(()) - }, - )?; + let api2 = Owner::new(wallet2.clone(), None, config2.config_file_path.clone()); + let args = InitTxArgs { + src_acct_name: None, + amount: slate.amount, + minimum_confirmations: 1, + max_outputs: 500, + num_change_outputs: 1, + selection_strategy_is_use_all: false, + ..Default::default() + }; + let res = api2.process_invoice_tx(mask2, &slate, args); + assert!(res.is_ok()); + slate = res?; + api2.tx_lock_outputs(mask2, &slate)?; //16) Finalize the invoice tx (to foreign api) // (Tests that foreign API on same port also has its stored mask updated)