Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
741 changes: 434 additions & 307 deletions Cargo.lock

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mwc_wallet"
version = "5.3.4"
version = "5.3.5"
authors = ["Mwc Developers <[email protected]>"]
description = "Simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
license = "Apache-2.0"
@@ -36,12 +36,12 @@ funty = "=1.1.0"
uuid = { version = "0.8", features = ["serde", "v4"] }
shlex = "1.3.0"

mwc_wallet_api = { path = "./api", version = "5.3.4" }
mwc_wallet_impls = { path = "./impls", version = "5.3.4" }
mwc_wallet_libwallet = { path = "./libwallet", version = "5.3.4" }
mwc_wallet_controller = { path = "./controller", version = "5.3.4" }
mwc_wallet_config = { path = "./config", version = "5.3.4" }
mwc_wallet_util = { path = "./util", version = "5.3.4" }
mwc_wallet_api = { path = "./api", version = "5.3.5" }
mwc_wallet_impls = { path = "./impls", version = "5.3.5" }
mwc_wallet_libwallet = { path = "./libwallet", version = "5.3.5" }
mwc_wallet_controller = { path = "./controller", version = "5.3.5" }
mwc_wallet_config = { path = "./config", version = "5.3.5" }
mwc_wallet_util = { path = "./util", version = "5.3.5" }

[build-dependencies]
built = { version = "0.4", features = ["git2"]}
@@ -52,7 +52,7 @@ serde = "1"
serde_derive = "1"
serde_json = "1"
remove_dir_all = "0.7"
easy-jsonrpc-mw = "0.5.4"
easy-jsonrpc-mwc = { git = "https://github.com/mwcproject/easy-jsonrpc-mwc", version = "0.5.5", branch = "master" }

[patch.crates-io]
mwc_secp256k1zkp = { git = "https://github.com/mwcproject/rust-secp256k1-zkp", tag = "0.7.16" }
12 changes: 6 additions & 6 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mwc_wallet_api"
version = "5.3.4"
version = "5.3.5"
authors = ["Mwc Developers <[email protected]>"]
description = "Mwc Wallet API"
license = "Apache-2.0"
@@ -16,18 +16,18 @@ serde = "1"
rand = "0.6"
serde_derive = "1"
serde_json = "1"
easy-jsonrpc-mw = "0.5.4"
chrono = { version = "0.4.11", features = ["serde"] }
ring = "0.16"
base64 = "0.12"
ed25519-dalek = "1.0.0-pre.4"
colored = "1.6"
x25519-dalek = "0.6"
easy-jsonrpc-mwc = { git = "https://github.com/mwcproject/easy-jsonrpc-mwc", version = "0.5.5", branch = "master" }

mwc_wallet_libwallet = { path = "../libwallet", version = "5.3.4" }
mwc_wallet_config = { path = "../config", version = "5.3.4" }
mwc_wallet_impls = { path = "../impls", version = "5.3.4" }
mwc_wallet_util = { path = "../util", version = "5.3.4" }
mwc_wallet_libwallet = { path = "../libwallet", version = "5.3.5" }
mwc_wallet_config = { path = "../config", version = "5.3.5" }
mwc_wallet_impls = { path = "../impls", version = "5.3.5" }
mwc_wallet_util = { path = "../util", version = "5.3.5" }

[dev-dependencies]
serde_json = "1"
28 changes: 12 additions & 16 deletions api/src/foreign.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,7 @@ use crate::libwallet::{
use crate::util::secp::key::SecretKey;
use crate::util::Mutex;
use ed25519_dalek::PublicKey as DalekPublicKey;
use libwallet::wallet_lock;
use std::sync::Arc;

/// ForeignAPI Middleware Check callback
@@ -218,9 +219,7 @@ where
/// ```
pub fn get_proof_address(&self) -> Result<String, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;

wallet_lock!(self.wallet_inst, w);
foreign::get_proof_address(&mut **w, (&self.keychain_mask).as_ref())
}

@@ -275,8 +274,7 @@ where
/// ```
pub fn build_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
if let Some(m) = self.middleware.as_ref() {
m(
ForeignCheckMiddlewareFn::BuildCoinbase,
@@ -332,11 +330,13 @@ where
pub fn verify_slate_messages(&self, slate: &Slate) -> Result<(), Error> {
if let Some(m) = self.middleware.as_ref() {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
let version_info = {
wallet_lock!(self.wallet_inst, w);
w.w2n_client().get_version_info()
};
m(
ForeignCheckMiddlewareFn::VerifySlateMessages,
w.w2n_client().get_version_info(),
version_info,
Some(slate),
)?;
}
@@ -406,8 +406,7 @@ where
dest_acct_name: &Option<String>,
message: Option<String>,
) -> Result<Slate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
if let Some(m) = self.middleware.as_ref() {
m(
ForeignCheckMiddlewareFn::ReceiveTx,
@@ -479,8 +478,7 @@ where
/// ```
pub fn finalize_invoice_tx(&self, slate: &Slate) -> Result<Slate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
if let Some(m) = self.middleware.as_ref() {
m(
ForeignCheckMiddlewareFn::FinalizeInvoiceTx,
@@ -520,8 +518,7 @@ where
&self,
encrypted_slate: VersionedSlate,
) -> Result<(Slate, SlatePurpose, Option<DalekPublicKey>), Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
let (slate, content, sender, _receiver) = foreign::decrypt_slate(
&mut **w,
(&self.keychain_mask).as_ref(),
@@ -541,8 +538,7 @@ where
address_index: Option<u32>,
use_test_rng: bool,
) -> Result<VersionedSlate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
let vslate = foreign::encrypt_slate(
&mut **w,
(&self.keychain_mask).as_ref(),
23 changes: 17 additions & 6 deletions api/src/foreign_rpc.rs
Original file line number Diff line number Diff line change
@@ -21,17 +21,20 @@ use crate::libwallet::{
Slate, SlateVersion, VersionInfo, VersionedCoinbase, VersionedSlate, WalletLCProvider,
};
use crate::{Foreign, ForeignCheckMiddlewareFn};
use easy_jsonrpc_mw;
use easy_jsonrpc_mwc;
use ed25519_dalek::PublicKey as DalekPublicKey;
use libwallet::slatepack::SlatePurpose;
use libwallet::wallet_lock_test;
use mwc_wallet_libwallet::proof::proofaddress::{self, ProvableAddress};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::secp::Secp256k1;
use std::ops::DerefMut;

/// Public definition used to generate Foreign jsonrpc api.
/// * When running `mwc-wallet listen` with defaults, the V2 api is available at
/// `localhost:3415/v2/foreign`
/// * The endpoint only supports POST operations, with the json-rpc request as the body
#[easy_jsonrpc_mw::rpc]
#[easy_jsonrpc_mwc::rpc]
pub trait ForeignRpc {
/**
Networked version of [Foreign::check_version](struct.Foreign.html#method.check_version).
@@ -1051,7 +1054,7 @@ pub fn run_doctest_foreign(
init_invoice_tx: bool,
compact_slate: bool,
) -> Result<Option<serde_json::Value>, String> {
use easy_jsonrpc_mw::Handler;
use easy_jsonrpc_mwc::Handler;
use mwc_wallet_impls::test_framework::{self, LocalWalletClient, WalletProxy};
use mwc_wallet_impls::{DefaultLCProvider, DefaultWalletImpl};
use mwc_wallet_libwallet::{api_impl, WalletInst};
@@ -1071,11 +1074,12 @@ pub fn run_doctest_foreign(
let _ = fs::remove_dir_all(test_dir);
global::set_local_chain_type(ChainTypes::AutomatedTesting);

let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy: WalletProxy<
DefaultLCProvider<LocalWalletClient, ExtKeychain>,
LocalWalletClient,
ExtKeychain,
> = WalletProxy::new(test_dir);
> = WalletProxy::new(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();

let rec_phrase_1 = util::ZeroingString::from(
@@ -1175,6 +1179,7 @@ pub fn run_doctest_foreign(
(&mask1).as_ref(),
1 as usize,
false,
tx_pool.lock().deref_mut(),
);
//update local outputs after each block, so transaction IDs stay consistent
let (wallet_refreshed, _) = api_impl::owner::retrieve_summary_info(
@@ -1227,7 +1232,10 @@ pub fn run_doctest_foreign(

api_impl::owner::issue_invoice_tx(&mut **w, (&mask2).as_ref(), &args, true, 1).unwrap()
};
api_impl::owner::update_wallet_state(wallet1.clone(), (&mask1).as_ref(), &None).unwrap();
{
wallet_lock_test!(wallet1.clone(), w1);
api_impl::owner::update_wallet_state(&mut **w1, (&mask1).as_ref(), &None).unwrap();
}
slate = {
let mut w_lock = wallet1.lock();
let w = w_lock.lc_provider().unwrap().wallet_inst().unwrap();
@@ -1273,7 +1281,10 @@ pub fn run_doctest_foreign(
}
}

api_impl::owner::update_wallet_state(wallet1.clone(), (&mask1).as_ref(), &None).unwrap();
{
wallet_lock_test!(wallet1.clone(), w1);
api_impl::owner::update_wallet_state(&mut **w1, (&mask1).as_ref(), &None).unwrap();
}
if init_tx {
let amount = 2_000_000_000;
let mut w_lock = wallet1.lock();
82 changes: 36 additions & 46 deletions api/src/owner.rs
Original file line number Diff line number Diff line change
@@ -42,7 +42,7 @@ use crate::libwallet::{
use crate::util::logger::LoggingConfig;
use crate::util::secp::key::SecretKey;
use crate::util::{from_hex, Mutex, ZeroingString};
use libwallet::{OwnershipProof, OwnershipProofValidation, RetrieveTxQueryArgs};
use libwallet::{wallet_lock, OwnershipProof, OwnershipProofValidation, RetrieveTxQueryArgs};
use mwc_wallet_util::mwc_util::secp::key::PublicKey;
use mwc_wallet_util::mwc_util::static_secp_instance;
use std::sync::atomic::{AtomicBool, Ordering};
@@ -295,8 +295,7 @@ where
&self,
keychain_mask: Option<&SecretKey>,
) -> Result<Vec<AcctPathMapping>, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
// Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?;
owner::accounts(&mut **w)
@@ -347,8 +346,7 @@ where
keychain_mask: Option<&SecretKey>,
label: &str,
) -> Result<Identifier, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
owner::create_account_path(&mut **w, keychain_mask, label)
}

@@ -395,8 +393,7 @@ where
keychain_mask: Option<&SecretKey>,
label: &str,
) -> Result<(), Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
// Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?;
owner::set_active_account(&mut **w, label)
@@ -513,7 +510,7 @@ where
/// let tx_slate_id = None;
///
/// // Return all TxLogEntries
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id, None);
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id, None, Some(true));
///
/// if let Ok((was_updated, tx_log_entries)) = result {
/// //...
@@ -527,6 +524,7 @@ where
tx_id: Option<u32>,
tx_slate_id: Option<Uuid>,
tx_query_args: Option<RetrieveTxQueryArgs>,
show_last_four_days: Option<bool>,
) -> Result<(bool, Vec<TxLogEntry>), Error> {
let tx = {
let t = self.status_tx.lock();
@@ -544,6 +542,7 @@ where
tx_id,
tx_slate_id,
tx_query_args,
show_last_four_days,
)?;
if self.doctest_mode {
res.1 = res
@@ -706,7 +705,8 @@ where
) -> Result<Slate, Error> {
let address = args.address.clone();

owner::update_wallet_state(self.wallet_inst.clone(), keychain_mask, &None)?;
wallet_lock!(self.wallet_inst, w);
owner::update_wallet_state(&mut **w, keychain_mask, &None)?;
let send_args = args.send_args.clone();
//minimum_confirmations cannot be zero.
let minimum_confirmations = args.minimum_confirmations.clone();
@@ -766,11 +766,8 @@ where
None
};

let mut slate = {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
owner::init_send_tx(&mut **w, keychain_mask, &args, self.doctest_mode, routputs)?
};
let mut slate =
{ owner::init_send_tx(&mut **w, keychain_mask, &args, self.doctest_mode, routputs)? };

match send_args {
Some(sa) => {
@@ -779,8 +776,6 @@ where
match sender_info {
Some((sender, other_wallet_info)) => {
let (slatepack_secret, height, secp) = {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
let keychain = w.keychain(keychain_mask)?;
let (height, _, _) = w.w2n_client().get_chain_tip()?;
let slatepack_secret =
@@ -891,8 +886,7 @@ where
keychain_mask: Option<&SecretKey>,
args: &IssueInvoiceTxArgs,
) -> Result<Slate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
owner::issue_invoice_tx(&mut **w, keychain_mask, args, self.doctest_mode, 1)
}

@@ -957,7 +951,9 @@ where
slate: &Slate,
args: &InitTxArgs,
) -> Result<Slate, Error> {
owner::update_wallet_state(self.wallet_inst.clone(), keychain_mask, &None)?;
wallet_lock!(self.wallet_inst, w);

owner::update_wallet_state(&mut **w, keychain_mask, &None)?;

//minimum_confirmations cannot be zero.
let minimum_confirmations = args.minimum_confirmations.clone();
@@ -966,8 +962,6 @@ where
"minimum_confirmations can not smaller than 1".to_owned(),
));
}
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
owner::process_invoice_tx(
&mut **w,
keychain_mask,
@@ -1041,8 +1035,7 @@ where
address: Option<String>,
participant_id: usize,
) -> Result<(), Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
owner::tx_lock_outputs(
&mut **w,
keychain_mask,
@@ -1118,8 +1111,7 @@ where
keychain_mask: Option<&SecretKey>,
slate: &Slate,
) -> Result<Slate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
let (slate_res, _context) =
owner::finalize_tx(&mut **w, keychain_mask, slate, true, self.doctest_mode)?;

@@ -1185,8 +1177,7 @@ where
fluff: bool,
) -> Result<(), Error> {
let client = {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
// Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?;
w.w2n_client().clone()
@@ -1294,7 +1285,7 @@ where
/// let tx_slate_id = None;
///
/// // Return all TxLogEntries
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id, None);
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id, None, None);
///
/// if let Ok((was_updated, tx_log_entries)) = result {
/// let stored_tx = api_owner.get_stored_tx(None, &tx_log_entries[0]).unwrap();
@@ -1308,17 +1299,15 @@ where
keychain_mask: Option<&SecretKey>,
tx_log_entry: &TxLogEntry,
) -> Result<Option<Transaction>, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
// Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?;
owner::get_stored_tx(&**w, tx_log_entry)
}

/// Loads a stored transaction from a file
pub fn load_stored_tx(&self, file: &String) -> Result<Transaction, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
owner::load_stored_tx(&**w, file)
}

@@ -1379,8 +1368,7 @@ where
slate: &Slate,
) -> Result<(), Error> {
{
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
// Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?;
}
@@ -1594,8 +1582,7 @@ where
keychain_mask: Option<&SecretKey>,
) -> Result<NodeHeightResult, Error> {
{
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
// Test keychain mask, to keep API consistent
let _ = w.keychain(keychain_mask)?;
}
@@ -2213,17 +2200,20 @@ where
///
/// let res = api_owner.start_updater(None, Duration::from_secs(60));
///
/// let messages = api_owner.get_updater_messages(10000);
/// let messages = api_owner.get_updater_messages(Some(10000));
///
/// if let Ok(_) = res {
/// // ...
/// }
///
/// ```
pub fn get_updater_messages(&self, count: usize) -> Result<Vec<StatusMessage>, Error> {
pub fn get_updater_messages(&self, count: Option<u32>) -> Result<Vec<StatusMessage>, Error> {
let mut q = self.updater_messages.lock();
let index = q.len().saturating_sub(count);
let index = match count {
Some(count) => q.len().saturating_sub(count as usize),
None => 0,
};
Ok(q.split_off(index))
}

@@ -2468,7 +2458,10 @@ where
params: &SwapStartArgs,
) -> Result<String, Error> {
// Updating wallet state first because we need to select outputs.
owner::update_wallet_state(self.wallet_inst.clone(), keychain_mask, &None)?;
{
wallet_lock!(self.wallet_inst, w);
owner::update_wallet_state(&mut **w, keychain_mask, &None)?;
}
owner_swap::swap_start(self.wallet_inst.clone(), keychain_mask, params)
.map_err(|e| e.into())
}
@@ -2715,8 +2708,7 @@ where
),
Error,
> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
foreign::decrypt_slate(&mut **w, keychain_mask, encrypted_slate, address_index)
}

@@ -2731,8 +2723,7 @@ where
address_index: Option<u32>,
use_test_rng: bool,
) -> Result<VersionedSlate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
foreign::encrypt_slate(
&mut **w,
keychain_mask,
@@ -2752,8 +2743,7 @@ where
features: OutputFeatures,
amount: u64,
) -> Result<BuiltOutput, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(self.wallet_inst, w);
owner::build_output(&mut **w, keychain_mask, features, amount)
}
}
463 changes: 412 additions & 51 deletions api/src/owner_rpc_v2.rs

Large diffs are not rendered by default.

871 changes: 804 additions & 67 deletions api/src/owner_rpc_v3.rs

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions api/src/types.rs
Original file line number Diff line number Diff line change
@@ -360,6 +360,7 @@ pub struct TxLogEntryAPI {
pub id: u32,
#[serde(default)]
pub tx_slate_id: Option<Uuid>,
#[serde(default = "TxLogEntryAPI::default_tx_type")]
pub tx_type: TxLogEntryType,
#[serde(default)]
pub address: Option<String>,
@@ -450,6 +451,10 @@ impl TxLogEntryAPI {
fn default_creation_ts() -> DateTime<Utc> {
Utc::now()
}

fn default_tx_type() -> TxLogEntryType {
TxLogEntryType::TxSent
}
}

/// Information about slatepack
4 changes: 2 additions & 2 deletions config/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mwc_wallet_config"
version = "5.3.4"
version = "5.3.5"
authors = ["Mwc Developers <info@mwc.mw>"]
description = "Configuration for mwc wallet , a simple, private and scalable cryptocurrency implementation based on the MimbleWimble chain format."
license = "Apache-2.0"
@@ -17,7 +17,7 @@ toml = "0.5"
serde_derive = "1"
thiserror = "1"

mwc_wallet_util = { path = "../util", version = "5.3.4" }
mwc_wallet_util = { path = "../util", version = "5.3.5" }

[dev-dependencies]
pretty_assertions = "0.6"
14 changes: 7 additions & 7 deletions controller/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mwc_wallet_controller"
version = "5.3.4"
version = "5.3.5"
authors = ["Mwc Developers <info@mwc.mw>"]
description = "Controllers for mwc wallet instantiation"
license = "Apache-2.0"
@@ -25,7 +25,6 @@ tokio = { version = "0.2", features = ["full"] }
uuid = { version = "0.8", features = ["serde", "v4"] }
url = "2.1"
chrono = { version = "0.4.11", features = ["serde"] }
easy-jsonrpc-mw = "0.5.4"
lazy_static = "1.4"
thiserror = "1"
qr_code = "1.1.0"
@@ -35,12 +34,13 @@ ed25519-dalek = "1.0.0-pre.4"
mwc-wagyu-ethereum = { git = "https://github.com/mwcproject/wagyu-ethereum", version = "0.6.3", branch = "master" }
mwc-libp2p = { git = "https://github.com/mwcproject/rust-libp2p", version="0.35.3", branch = "master", default-features = false, features = [ "noise", "yamux", "mplex", "dns", "tcp-tokio", "ping", "gossipsub"] }
#libp2p = { path = "../../rust-libp2p", default-features = false, features = [ "noise", "yamux", "mplex", "dns", "tcp-tokio", "ping", "gossipsub"] }
easy-jsonrpc-mwc = { git = "https://github.com/mwcproject/easy-jsonrpc-mwc", version = "0.5.5", branch = "master" }

mwc_wallet_util = { path = "../util", version = "5.3.4" }
mwc_wallet_api = { path = "../api", version = "5.3.4" }
mwc_wallet_impls = { path = "../impls", version = "5.3.4" }
mwc_wallet_libwallet = { path = "../libwallet", version = "5.3.4" }
mwc_wallet_config = { path = "../config", version = "5.3.4" }
mwc_wallet_util = { path = "../util", version = "5.3.5" }
mwc_wallet_api = { path = "../api", version = "5.3.5" }
mwc_wallet_impls = { path = "../impls", version = "5.3.5" }
mwc_wallet_libwallet = { path = "../libwallet", version = "5.3.5" }
mwc_wallet_config = { path = "../config", version = "5.3.5" }

[dev-dependencies]
remove_dir_all = "0.7"
77 changes: 45 additions & 32 deletions controller/src/command.rs
Original file line number Diff line number Diff line change
@@ -49,7 +49,9 @@ use mwc_wallet_libwallet::swap::fsm::state::StateId;
use mwc_wallet_libwallet::swap::trades;
use mwc_wallet_libwallet::swap::types::Action;
use mwc_wallet_libwallet::swap::{message, Swap};
use mwc_wallet_libwallet::{OwnershipProof, Slate, StatusMessage, TxLogEntry, WalletInst};
use mwc_wallet_libwallet::{
wallet_lock, OwnershipProof, Slate, StatusMessage, TxLogEntry, WalletInst,
};
use mwc_wallet_util::mwc_core::consensus::MWC_BASE;
use mwc_wallet_util::mwc_core::core::{amount_to_hr_string, Transaction};
use mwc_wallet_util::mwc_core::global::{FLOONET_DNS_SEEDS, MAINNET_DNS_SEEDS};
@@ -87,7 +89,6 @@ pub struct GlobalArgs {
pub account: Option<String>,
pub api_secret: Option<String>,
pub node_api_secret: Option<String>,
pub show_spent: bool,
pub password: Option<ZeroingString>,
pub tls_conf: Option<TLSConfig>,
}
@@ -549,8 +550,8 @@ pub struct SendArgs {
pub ttl_blocks: Option<u64>,
pub exclude_change_outputs: bool,
pub minimum_confirmations_change_outputs: u64,
pub address: Option<String>, //this is only for file proof.
pub outputs: Option<Vec<String>>, // Outputs to use. If None, all outputs can be used
pub address: Option<String>, //this is only for file proof.
pub outputs: Option<HashSet<String>>, // Outputs to use. If None, all outputs can be used
pub slatepack_recipient: Option<ProvableAddress>, // Destination for slatepack. The address will be the same as for payment_proof_address. The role is different.
pub late_lock: bool,
pub min_fee: Option<u64>,
@@ -717,8 +718,7 @@ where
}

let (slatepack_secret, slatepack_sender, height, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(keychain_mask)?;
let slatepack_secret =
proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
@@ -757,7 +757,10 @@ where
.map_err(|e| {
Error::IO(format!("Unable to store the file at {}, {}", args.dest, e))
})?;
api.tx_lock_outputs(m, &slate, Some(String::from("file")), 0)?;
// Late lock expected to do the lock at finalize step. Don't do that now
if !init_args.late_lock.unwrap_or(false) {
api.tx_lock_outputs(m, &slate, Some(String::from("file")), 0)?;
}

if !args.dest.is_empty() {
println!(
@@ -782,6 +785,7 @@ where
return Ok(());
}
"self" => {
debug_assert!(!slate.compact_slate);
api.tx_lock_outputs(m, &slate, Some(String::from("self")), 0)?;
let km = match keychain_mask.as_ref() {
None => None,
@@ -824,7 +828,10 @@ where
error!("Error validating participant messages: {}", e);
e
})?;
api.tx_lock_outputs(m, &slate, Some(args.dest.clone()), 0)?; //this step needs to be done before finalizing the slate
// Late lock expected to do the lock at finalize step. Don't do that now
if !init_args.late_lock.unwrap_or(false) {
api.tx_lock_outputs(m, &slate, Some(args.dest.clone()), 0)?; //this step needs to be done before finalizing the slate
}
}
}

@@ -955,8 +962,7 @@ where
};
controller::foreign_single_use(owner_api.wallet_inst.clone(), km, |api| {
let (slatepack_secret, height, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(keychain_mask)?;
let slatepack_secret =
proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
@@ -1063,8 +1069,7 @@ where
};
controller::foreign_single_use(owner_api.wallet_inst.clone(), km, |api| {
let (slatepack_secret, height, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(keychain_mask)?;
let slatepack_secret =
proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
@@ -1173,8 +1178,7 @@ where

controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let (slatepack_secret, height, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(m)?;
let slatepack_secret = proofaddress::payment_proof_address_secret(&keychain, None)?;
let slatepack_secret = DalekSecretKey::from_bytes(&slatepack_secret.0)
@@ -1282,8 +1286,7 @@ where
if args.dest.is_some() || slatepack_format {
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let (slatepack_secret, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(m)?;
let slatepack_secret = proofaddress::payment_proof_address_secret(&keychain, None)?;
let slatepack_secret = DalekSecretKey::from_bytes(&slatepack_secret.0)
@@ -1354,8 +1357,7 @@ where
let slate = api.issue_invoice_tx(m, &args.issue_args)?;

let (slatepack_secret, tor_address, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(keychain_mask)?;
let slatepack_secret =
proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
@@ -1420,8 +1422,7 @@ where
K: keychain::Keychain + 'static,
{
let (slatepack_secret, tor_address, height, secp) = {
let mut w_lock = owner_api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(owner_api.wallet_inst, w);
let keychain = w.keychain(keychain_mask)?;
let slatepack_secret = proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
let slatepack_pk = DalekPublicKey::from(&slatepack_secret);
@@ -1631,10 +1632,15 @@ where
Ok(())
}

pub struct OutputsArgs {
pub show_spent: bool,
}

pub fn outputs<L, C, K>(
owner_api: &mut Owner<L, C, K>,
keychain_mask: Option<&SecretKey>,
g_args: &GlobalArgs,
args: OutputsArgs,
dark_scheme: bool,
) -> Result<(), Error>
where
@@ -1645,7 +1651,7 @@ where
let updater_running = owner_api.updater_running.load(Ordering::Relaxed);
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let res = api.node_height(m)?;
let (validated, outputs) = api.retrieve_outputs(m, g_args.show_spent, true, None)?;
let (validated, outputs) = api.retrieve_outputs(m, args.show_spent, true, None)?;
display::outputs(
&g_args.account,
res.height,
@@ -1663,6 +1669,7 @@ pub struct TxsArgs {
pub id: Option<u32>,
pub tx_slate_id: Option<Uuid>,
pub count: Option<u32>,
pub show_last_four_days: Option<bool>,
}

pub fn txs<L, C, K>(
@@ -1681,7 +1688,14 @@ where
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let res = api.node_height(m)?;
// Note advanced query args not currently supported by command line client
let (validated, txs) = api.retrieve_txs(m, true, args.id, args.tx_slate_id, None)?;
let (validated, txs) = api.retrieve_txs(
m,
true,
args.id,
args.tx_slate_id,
None,
args.show_last_four_days,
)?;
let include_status = !args.id.is_some() && !args.tx_slate_id.is_some();
// If view count is specified, restrict the TX list to `txs.len() - count`
let first_tx = args
@@ -1769,8 +1783,7 @@ where

controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let (slatepack_secret, height, secp) = {
let mut w_lock = api.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(api.wallet_inst, w);
let keychain = w.keychain(keychain_mask)?;
let slatepack_secret =
proofaddress::payment_proof_address_dalek_secret(&keychain, None)?;
@@ -1861,7 +1874,7 @@ where
K: keychain::Keychain + 'static,
{
controller::owner_single_use(None, keychain_mask, Some(owner_api), |api, m| {
let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None, None)?;
let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None, None, None)?;
let stored_tx = api.get_stored_tx(m, &txs[0])?;
if stored_tx.is_none() {
error!(
@@ -3575,7 +3588,10 @@ where
K: keychain::Keychain + 'static,
{
// Let's do refresh first
let _ = owner::perform_refresh_from_node(wallet_inst.clone(), keychain_mask, &None)?;
{
wallet_lock!(wallet_inst, w);
let _ = owner::perform_refresh_from_node(&mut **w, keychain_mask, &None)?;
}

let mut json_res = JsonMap::new();

@@ -3799,8 +3815,7 @@ where
}
if peers.len() == 0 {
// let's add peer is possible
let mut w_lock = wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(wallet_inst, w);
match w.w2n_client().get_libp2p_peers() {
Ok(libp2p_peers) => {
for addr in libp2p_peers.libp2p_peers {
@@ -3849,8 +3864,7 @@ where
}

if peers.len() < 5 {
let mut w_lock = wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(wallet_inst, w);
if let Ok(messages) = w.w2n_client().get_libp2p_messages() {
let mut inject_msgs: Vec<ReceivedMessage> = vec![];

@@ -4153,8 +4167,7 @@ where

if args.check_integrity_expiration {
let tip_height = {
let mut w_lock = wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
wallet_lock!(wallet_inst, w);
w.w2n_client().get_chain_tip()?.0
};

2 changes: 1 addition & 1 deletion controller/src/controller.rs
Original file line number Diff line number Diff line change
@@ -52,7 +52,7 @@ use crate::impls::tor::process as tor_process;
use crate::impls::tor::{bridge as tor_bridge, proxy as tor_proxy};
use crate::keychain::Keychain;
use chrono::Utc;
use easy_jsonrpc_mw::{Handler, MaybeReply};
use easy_jsonrpc_mwc::{Handler, MaybeReply};
use ed25519_dalek::PublicKey as DalekPublicKey;
use log::Level;
use mwc_wallet_impls::tor;
51 changes: 40 additions & 11 deletions controller/tests/accounts.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_keychain as keychain;
use std::ops::DerefMut;
use std::sync::Arc;

use self::core::global;
use self::keychain::{ExtKeychain, Keychain};
@@ -33,12 +35,15 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// Various tests on accounts within the same wallet
fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn accounts_test_impl(test_dir: &str) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -121,14 +126,28 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
w.set_parent_key_id_by_name("account1")?;
assert_eq!(w.parent_key_id(), ExtKeychain::derive_key_id(2, 1, 0, 0, 0));
}
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 7, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
7,
false,
tx_pool.lock().deref_mut(),
);

{
wallet_inst!(wallet1, w);
w.set_parent_key_id_by_name("account2")?;
assert_eq!(w.parent_key_id(), ExtKeychain::derive_key_id(2, 2, 0, 0, 0));
}
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
5,
false,
tx_pool.lock().deref_mut(),
);

// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -140,7 +159,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 5);
Ok(())
})?;
@@ -164,7 +183,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 7);
Ok(())
})?;
@@ -183,7 +202,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 0);
Ok(())
})?;
@@ -211,13 +230,23 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
Ok(())
})?;

// apply post txs
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?;
assert_eq!(wallet1_info.last_confirmed_height, 12);
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 9);
Ok(())
})?;
@@ -232,7 +261,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
assert_eq!(wallet1_info.last_confirmed_height, 13); // mwc already updated that
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
println!("{:?}", txs);
assert_eq!(txs.len(), 5);
Ok(())
@@ -243,7 +272,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
Ok(())
})?;
@@ -261,7 +290,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 0);
Ok(())
})?;
183 changes: 183 additions & 0 deletions controller/tests/broken_change.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
// Copyright 2019 The Grin Developers
// Copyright 2024 The Mwc Developers
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Test sender transaction with no change output
#[macro_use]
extern crate log;
extern crate mwc_wallet_controller as wallet;
extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate};
use mwc_wallet_libwallet as libwallet;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;

#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

fn broken_change_test_impl(
test_dir: &str,
put_into_change: u64,
expected_outputs: usize,
test_send: bool,
) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

create_wallet_and_add!(
client1,
wallet1,
mask1_i,
test_dir,
"wallet1",
None,
&mut wallet_proxy,
false
);

let mask1 = (&mask1_i).as_ref();

create_wallet_and_add!(
client2,
wallet2,
mask2_i,
test_dir,
"wallet2",
None,
&mut wallet_proxy,
false
);

let mask2 = (&mask2_i).as_ref();

// Set the wallet proxy listener running
thread::spawn(move || {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
if let Err(e) = wallet_proxy.run() {
error!("Wallet Proxy error: {}", e);
}
});

// few values to keep things shorter
let reward = core::consensus::reward(0, 1);

let inputs_num = 4;
let output_num = 5;

// Mine into wallet 1
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
4 + 3,
false,
tx_pool.lock().deref_mut(),
);
let fee = core::libtx::tx_fee(inputs_num, output_num + 1, 1);

// send a single block's worth of transactions with minimal strategy
let mut slate = Slate::blank(2, false);
if test_send {
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let args = InitTxArgs {
src_acct_name: None,
amount: reward * inputs_num as u64 - fee - put_into_change,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: output_num as u32,
selection_strategy_is_use_all: false,
..Default::default()
};
slate = api.init_send_tx(m, &args, 1)?;
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
api.tx_lock_outputs(m, &slate, None, 0)?;
slate = api.finalize_tx(m, &slate)?;
assert!(slate.tx.clone().unwrap().body.inputs.len() == inputs_num);
assert!(slate.tx.clone().unwrap().body.outputs.len() == expected_outputs);
api.post_tx(m, slate.tx_or_err()?, false)?;
Ok(())
})?;
} else {
// testing invoice
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
// Wallet 2 inititates an invoice transaction, requesting payment
let args = IssueInvoiceTxArgs {
amount: reward * inputs_num as u64 - fee - put_into_change,
..Default::default()
};
slate = api.issue_invoice_tx(m, &args)?;
Ok(())
})?;

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |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: output_num as u32,
selection_strategy_is_use_all: false,
..Default::default()
};
slate = api.process_invoice_tx(m, &slate, &args)?;
api.tx_lock_outputs(m, &slate, None, 1)?;
assert!(slate.tx.clone().unwrap().body.inputs.len() == inputs_num);
assert!(slate.tx.clone().unwrap().body.outputs.len() == expected_outputs);
Ok(())
})?;
}

// let logging finish
stopper.store(false, Ordering::Relaxed);
thread::sleep(Duration::from_millis(200));
Ok(())
}

fn run_broken_change_test(
test_dir: &str,
put_into_change: u64,
expected_outputs: usize,
test_send: bool,
) {
setup(test_dir);
if let Err(e) = broken_change_test_impl(&test_dir, put_into_change, expected_outputs, test_send)
{
panic!("Libwallet Error: {}", e);
}
clean_output_dir(test_dir);
}

#[test]
fn broken_change() {
run_broken_change_test("test_output/broken_change1", 0, 1, true);
run_broken_change_test("test_output/broken_change2", 0, 1, false);
run_broken_change_test("test_output/broken_change3", 7, 2, true);
run_broken_change_test("test_output/broken_change4", 100, 2, false);
run_broken_change_test("test_output/broken_change5", 500_000_000, 6, true); // 0.5 MWC for 1 outputs is good
run_broken_change_test("test_output/broken_change6", 499_999_999, 2, false); // 0.4999999 MWC for 5 outputs is below the threshold, expected to use 1 output instead of 5.
}
33 changes: 26 additions & 7 deletions controller/tests/build_chain.rs
Original file line number Diff line number Diff line change
@@ -22,6 +22,8 @@ extern crate mwc_wallet_impls as impls;
extern crate mwc_wallet_libwallet as libwallet;

use mwc_wallet_util::mwc_core as core;
use std::ops::DerefMut;
use std::sync::Arc;

use self::libwallet::{InitTxArgs, Slate};
use impls::test_framework::{self, LocalWalletClient};
@@ -32,11 +34,14 @@ use std::time::Duration;

mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// Builds a chain with real transactions up to the given height
fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwallet::Error> {
fn build_chain(test_dir: &str, block_height: usize) -> Result<(), libwallet::Error> {
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -90,7 +95,14 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal
let mut rng = rand::thread_rng();

// Start off with a few blocks
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);

for height in 0..block_height {
let mut wallet_1_has_funds = false;
@@ -114,8 +126,14 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal
// 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;
if !transact || !wallet_1_has_funds {
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 1, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);
continue;
}

@@ -157,7 +175,7 @@ fn build_chain(test_dir: &'static str, block_height: usize) -> Result<(), libwal
}

#[test]
#[ignore]
//#[ignore]
fn build_chain_to_height() {
// ******************
// If letting this run for a while to build a chain, recommend also tweaking scan threshold around 1112 of owner.rs:
@@ -170,7 +188,8 @@ fn build_chain_to_height() {
let test_dir = "test_output/build_chain";
clean_output_dir(test_dir);
setup(test_dir);
if let Err(e) = build_chain(test_dir, 2048) {
// Originall had 2048 blocks and disabled test. Let's have small number of blocks but robust test
if let Err(e) = build_chain(test_dir, 100) {
panic!("Libwallet Error: {}", e);
}
// don't clean to get the result for testing
10 changes: 6 additions & 4 deletions controller/tests/build_output.rs
Original file line number Diff line number Diff line change
@@ -20,28 +20,30 @@ extern crate mwc_wallet_util;

use impls::test_framework::LocalWalletClient;
use mwc_wallet_libwallet as libwallet;
use mwc_wallet_util::mwc_core::core::OutputFeatures;
use mwc_wallet_util::mwc_core::core::{OutputFeatures, Transaction};
use mwc_wallet_util::mwc_keychain::{
mnemonic, BlindingFactor, ExtKeychain, ExtKeychainPath, Keychain, SwitchCommitmentType,
};
use mwc_wallet_util::mwc_util::{secp, ZeroingString};
use mwc_wallet_util::mwc_util::{secp, Mutex, ZeroingString};
use rand::{thread_rng, Rng};
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};

fn build_output_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
fn build_output_test_impl(test_dir: &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 mnemonic = mnemonic::from_entropy(&seed).unwrap();

// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let stopper = wallet_proxy.running.clone();

create_wallet_and_add!(
426 changes: 343 additions & 83 deletions controller/tests/check.rs

Large diffs are not rendered by default.

23 changes: 19 additions & 4 deletions controller/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ use self::keychain::ExtKeychain;
use self::libwallet::WalletInst;
use impls::test_framework::{LocalWalletClient, WalletProxy};
use impls::{DefaultLCProvider, DefaultWalletImpl};
use mwc_wallet_util::mwc_core::core::Transaction;
use std::sync::Arc;
use util::secp::key::SecretKey;
use util::{Mutex, ZeroingString};
@@ -39,6 +40,15 @@ macro_rules! wallet_inst {
};
}

#[macro_export]
macro_rules! wallet_inst_test {
($wallet:ident, $w: ident) => {
let mut w_lock = $wallet.lock();
let lc = w_lock.lc_provider().unwrap();
let $w = lc.wallet_inst().unwrap();
};
}

#[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) => {
@@ -102,10 +112,15 @@ pub fn setup_global_chain_type() {
}

pub fn create_wallet_proxy(
test_dir: &str,
) -> WalletProxy<DefaultLCProvider<LocalWalletClient, ExtKeychain>, LocalWalletClient, ExtKeychain>
{
WalletProxy::new(test_dir)
test_dir: String,
tx_pool: Arc<Mutex<Vec<Transaction>>>,
) -> WalletProxy<
'static,
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
LocalWalletClient,
ExtKeychain,
> {
WalletProxy::new(test_dir, tx_pool)
}

pub fn create_local_wallet(
33 changes: 25 additions & 8 deletions controller/tests/file.rs
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@ extern crate mwc_wallet_controller as wallet;
extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core as core;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use impls::{PathToSlateGetter, PathToSlatePutter, SlateGetter, SlatePutter};
@@ -35,13 +37,16 @@ use serde_json;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::secp::Secp256k1;
use mwc_wallet_util::mwc_util::Mutex;

/// self send impl
fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn file_exchange_test_impl(test_dir: &str) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();
let secp = Secp256k1::new();
@@ -102,8 +107,14 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>
w.set_parent_key_id_by_name("mining")?;
}
let mut bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

let send_file = format!("{}/part_tx_1.tx", test_dir);
let receive_file = format!("{}/part_tx_2.tx", test_dir);
@@ -182,11 +193,17 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>
api.verify_slate_messages(m, &slate)?;
slate = api.finalize_tx(m, &slate)?;
api.post_tx(m, slate.tx_or_err()?, false)?;
bh += 1;
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// Check total in mining account
@@ -209,7 +226,7 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>

// Check messages, all participants should have both
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
assert_eq!(
tx[0].clone().messages.unwrap().messages[0].message,
Some(message.to_owned())
@@ -225,7 +242,7 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>
})?;

wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
assert_eq!(
tx[0].clone().messages.unwrap().messages[0].message,
Some(message.to_owned())
95 changes: 80 additions & 15 deletions controller/tests/integrity_kernel.rs
Original file line number Diff line number Diff line change
@@ -35,22 +35,25 @@ mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_libp2p::identity::Keypair;
use mwc_wallet_libwallet::internal::updater;
use mwc_wallet_libwallet::{owner, TxLogEntryType};
use mwc_wallet_libwallet::{owner, wallet_lock_test, TxLogEntryType};
use mwc_wallet_util::mwc_core::core::hash::Hash;
use mwc_wallet_util::mwc_core::core::{KernelFeatures, TxKernel};
use mwc_wallet_util::mwc_core::core::{KernelFeatures, Transaction, TxKernel};
use mwc_wallet_util::mwc_core::libtx::aggsig;
use mwc_wallet_util::mwc_p2p::libp2p_connection;
use mwc_wallet_util::mwc_util::secp;
use mwc_wallet_util::mwc_util::secp::pedersen::Commitment;
use mwc_wallet_util::mwc_util::secp::Message;
use mwc_wallet_util::mwc_util::{secp, Mutex};
use std::collections::HashMap;
use std::convert::TryInto;
use std::ops::DerefMut;
use std::sync::Arc;

/// self send impl
fn integrity_kernel_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn integrity_kernel_impl(test_dir: &str) -> Result<(), wallet::Error> {
// Create a new proxy to simulate server and wallet responses
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();

// Create a new wallet test client, and set its queues to communicate with the
@@ -79,8 +82,18 @@ fn integrity_kernel_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
let reward = core::consensus::MWC_FIRST_GROUP_REWARD;

// 4 is a lock height for coinbase. We want 2 mining rewards to spend.
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
let _ = owner::perform_refresh_from_node(wallet1.clone(), mask1, &None)?;
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
5,
false,
tx_pool.lock().deref_mut(),
);
{
wallet_lock_test!(wallet1, w1);
let _ = owner::perform_refresh_from_node(&mut **w1, mask1, &None)?;
}

// Check wallet 1 contents are as expected
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -148,8 +161,18 @@ fn integrity_kernel_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
assert_eq!(integral_balance[0].1, false);

// Mine a block, the transaction should be confirmed
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 1, false);
let _ = owner::perform_refresh_from_node(wallet1.clone(), mask1, &None)?;
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);
{
wallet_lock_test!(wallet1, w1);
let _ = owner::perform_refresh_from_node(&mut **w1, mask1, &None)?;
}

let (account, outputs, _height, integral_balance) =
libwallet::owner_libp2p::get_integral_balance(wallet1.clone(), mask1)?;
@@ -160,8 +183,29 @@ fn integrity_kernel_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
assert_eq!(integral_balance[0].1, false); // Now should be confirmed...
assert_eq!(integral_balance[0].0.expiration_height, 1446 + 3);

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false);
let _ = owner::perform_refresh_from_node(wallet1.clone(), mask1, &None)?;
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
2,
false,
tx_pool.lock().deref_mut(),
);
{
wallet_lock_test!(wallet1, w1);
let _ = owner::perform_refresh_from_node(&mut **w1, mask1, &None)?;
}

// apply posted transaction
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

let (account, outputs, _height, integral_balance) =
libwallet::owner_libp2p::get_integral_balance(wallet1.clone(), mask1)?;
assert!(account.is_some());
@@ -193,8 +237,28 @@ fn integrity_kernel_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
);

// Mine a block, the second transaction should be confirmed
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = owner::perform_refresh_from_node(wallet1.clone(), mask1, &None)?;
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
{
wallet_lock_test!(wallet1, w1);
let _ = owner::perform_refresh_from_node(&mut **w1, mask1, &None)?;
}

// apply posted transaction
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

let (account, outputs, _height, integral_balance) =
libwallet::owner_libp2p::get_integral_balance(wallet1.clone(), mask1)?;
@@ -211,8 +275,9 @@ fn integrity_kernel_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
// Let's verify if Integrity context match the Tx Kernels.
let txs = {
wallet_inst!(wallet1, w);
let mut txs =
updater::retrieve_txs(&mut **w, mask1, None, None, None, None, false, None, None)?;
let mut txs = updater::retrieve_txs(
&mut **w, mask1, None, None, None, None, false, None, None, None,
)?;

txs.retain(|t| t.tx_type == TxLogEntryType::TxSent);
txs
42 changes: 33 additions & 9 deletions controller/tests/invoice.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@ extern crate mwc_wallet_impls as impls;
use mwc_wallet_libwallet as libwallet;
use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate};
@@ -31,12 +33,15 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// self send impl
fn invoice_tx_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn invoice_tx_impl(test_dir: &str) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -87,8 +92,14 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
w.set_parent_key_id_by_name("mining")?;
}
let mut bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

// Sanity check wallet 1 contents
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -139,15 +150,21 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
api.post_tx(m, slate.tx_or_err()?, false)?;
Ok(())
})?;
bh += 1;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// Check transaction log for wallet 2
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
let (_, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
assert!(txs.len() == 1);
println!(
@@ -163,7 +180,7 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
// exists
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
assert_eq!(txs.len() as u64, bh + 1);
println!(
@@ -204,7 +221,14 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
})?;

// test that payee can only cancel once
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
//bh += 3;

wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
27 changes: 23 additions & 4 deletions controller/tests/late_lock.rs
Original file line number Diff line number Diff line change
@@ -21,19 +21,24 @@ extern crate mwc_wallet_libwallet as libwallet;

use self::libwallet::{InitTxArgs, Slate};
use impls::test_framework::{self, LocalWalletClient};
use std::ops::DerefMut;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::consensus::calc_mwc_block_reward;
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// self send impl
fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
fn late_lock_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -93,7 +98,14 @@ fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
w.set_parent_key_id_by_name("account1")?;
}

test_framework::award_blocks_to_wallet(&chain, wallet_mining.clone(), mask1, 10, false)?;
test_framework::award_blocks_to_wallet(
&chain,
wallet_mining.clone(),
mask1,
10,
false,
tx_pool.lock().deref_mut(),
)?;

// update/test contents of both accounts
wallet::controller::owner_single_use(Some(wallet_mining.clone()), mask1, None, |api, m| {
@@ -182,7 +194,14 @@ fn late_lock_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
)
.unwrap();

test_framework::award_blocks_to_wallet(&chain, wallet_mining.clone(), mask1, 3, false)?;
test_framework::award_blocks_to_wallet(
&chain,
wallet_mining.clone(),
mask1,
4,
false,
tx_pool.lock().deref_mut(),
)?;

// update/test contents of both accounts
wallet::controller::owner_single_use(Some(wallet_mining.clone()), mask1, None, |api, m| {
77 changes: 60 additions & 17 deletions controller/tests/no_change.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use libwallet::{InitTxArgs, IssueInvoiceTxArgs, Slate};
@@ -31,10 +33,13 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn no_change_test_impl(test_dir: &str, inputs_num: usize) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -76,15 +81,22 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
let reward = core::consensus::reward(0, 1);

// Mine into wallet 1
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 4, false);
let fee = core::libtx::tx_fee(1, 1, 1);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
4,
false,
tx_pool.lock().deref_mut(),
);
let fee = core::libtx::tx_fee(inputs_num, 1, 1);

// send a single block's worth of transactions with minimal strategy
let mut slate = Slate::blank(2, false);
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let args = InitTxArgs {
src_acct_name: None,
amount: reward - fee,
amount: reward * inputs_num as u64 - fee,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
@@ -95,15 +107,30 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
api.tx_lock_outputs(m, &slate, None, 0)?;
slate = api.finalize_tx(m, &slate)?;
assert!(slate.tx.clone().unwrap().body.inputs.len() == inputs_num);
assert!(slate.tx.clone().unwrap().body.outputs.len() == 1); // only destination output is expected, no change outputs
api.post_tx(m, slate.tx_or_err()?, false)?;
Ok(())
})?;

// apply posted tx
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

// Refresh and check transaction log for wallet 1
wallet::controller::owner_single_use(Some(wallet1.clone()), mask2, None, |api, m| {
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
assert!(refreshed);
assert!(txs.len() == 1);
let tx = txs[0].clone();
assert!(tx.num_inputs == inputs_num);
assert!(tx.num_outputs == 0);
println!("{:?}", tx);
assert!(tx.confirmed);
Ok(())
@@ -113,7 +140,7 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
// Wallet 2 inititates an invoice transaction, requesting payment
let args = IssueInvoiceTxArgs {
amount: reward - fee,
amount: reward * inputs_num as u64 - fee,
..Default::default()
};
slate = api.issue_invoice_tx(m, &args)?;
@@ -133,6 +160,8 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
};
slate = api.process_invoice_tx(m, &slate, &args)?;
api.tx_lock_outputs(m, &slate, None, 1)?;
assert!(slate.tx.clone().unwrap().body.inputs.len() == inputs_num);
assert!(slate.tx.clone().unwrap().body.outputs.len() == 1); // only destination output is expected, no change outputs
Ok(())
})?;

@@ -147,14 +176,26 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
Ok(())
})?;

// apply posted tx
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

// Refresh and check transaction log for wallet 1
wallet::controller::owner_single_use(Some(wallet1.clone()), mask2, None, |api, m| {
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
assert!(refreshed);
for tx in txs {
println!("{:?}", tx);
assert!(tx.confirmed);
}
assert!(txs.len() == 1);
let tx = txs[0].clone();
assert!(tx.num_inputs == inputs_num);
assert!(tx.num_outputs == 0);
println!("{:?}", tx);
assert!(tx.confirmed);
Ok(())
})?;

@@ -166,10 +207,12 @@ fn no_change_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {

#[test]
fn no_change() {
let test_dir = "test_output/no_change";
setup(test_dir);
if let Err(e) = no_change_test_impl(test_dir) {
panic!("Libwallet Error: {}", e);
for inputs_num in 1..=3 {
let test_dir = format!("test_output/no_change{}", inputs_num);
setup(&test_dir);
if let Err(e) = no_change_test_impl(&test_dir, 1) {
panic!("Libwallet Error: {}", e);
}
clean_output_dir(&test_dir);
}
clean_output_dir(test_dir);
}
20 changes: 15 additions & 5 deletions controller/tests/ownership_proofs.rs
Original file line number Diff line number Diff line change
@@ -19,6 +19,8 @@ extern crate mwc_wallet_controller as wallet;
extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use std::sync::atomic::Ordering;
@@ -29,13 +31,15 @@ use std::time::Duration;
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_libwallet::PubKeySignature;
use mwc_wallet_util::mwc_util::ZeroingString;
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::{Mutex, ZeroingString};

/// self send impl
fn ownership_proof_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn ownership_proof_impl(test_dir: &str) -> Result<(), wallet::Error> {
// Create a new proxy to simulate server and wallet responses
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -63,8 +67,14 @@ fn ownership_proof_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
}
});

let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10 as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
10 as usize,
false,
tx_pool.lock().deref_mut(),
);

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
30 changes: 24 additions & 6 deletions controller/tests/payment_proofs.rs
Original file line number Diff line number Diff line change
@@ -22,21 +22,26 @@ extern crate mwc_wallet_util;
use impls::test_framework::{self, LocalWalletClient};
use libwallet::{InitTxArgs, Slate};
use mwc_wallet_libwallet as libwallet;
use std::ops::DerefMut;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_libwallet::proof::proofaddress::ProvableAddress;
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_core::global;
use mwc_wallet_util::mwc_util::Mutex;

/// Various tests on accounts within the same wallet
fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn payment_proofs_test_impl(test_dir: &str) -> Result<(), wallet::Error> {
// Create a new proxy to simulate server and wallet responses
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -78,8 +83,14 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>

// Do some mining
let bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

let mut address = None;
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
@@ -131,7 +142,7 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>
sender_api.tx_lock_outputs(m, &slate, None, 0)?;

// 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)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
assert!(txs[0].payment_proof.is_some());
let pp = txs[0].clone().payment_proof.unwrap();
assert_eq!(
@@ -156,7 +167,14 @@ fn payment_proofs_test_impl(test_dir: &'static str) -> Result<(), wallet::Error>
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
2,
false,
tx_pool.lock().deref_mut(),
);

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
// Check payment proof here
61 changes: 49 additions & 12 deletions controller/tests/repost.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@ extern crate mwc_wallet_libwallet as libwallet;

use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use self::libwallet::{InitTxArgs, Slate};
use impls::test_framework::{self, LocalWalletClient};
@@ -33,13 +35,16 @@ use std::time::Duration;
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use libwallet::NodeClient;
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::secp::Secp256k1;
use mwc_wallet_util::mwc_util::Mutex;

/// self send impl
fn file_repost_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn file_repost_test_impl(test_dir: &str) -> Result<(), wallet::Error> {
// Create a new proxy to simulate server and wallet responses
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();
let secp = Secp256k1::new();
@@ -100,8 +105,14 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
w.set_parent_key_id_by_name("mining")?;
}
let mut bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

let send_file = format!("{}/part_tx_1.tx", test_dir);
let receive_file = format!("{}/part_tx_2.tx", test_dir);
@@ -132,7 +143,14 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// wallet 1 receives file to different account, completes
@@ -176,14 +194,20 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {

// Now repost from cached
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
let stored_tx = api.get_stored_tx(m, &txs[0])?;
api.post_tx(m, &stored_tx.unwrap(), false)?;
bh += 1;
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// update/test contents of both accounts
@@ -239,19 +263,32 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// Now repost from cached
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
let stored_tx = api.get_stored_tx(m, &txs[0])?;
api.post_tx(m, &stored_tx.unwrap(), false)?;
bh += 1;
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;
//
// update/test contents of both accounts
33 changes: 21 additions & 12 deletions controller/tests/revert.rs
Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@ use mwc_wallet_util::mwc_keychain::ExtKeychain;
use mwc_wallet_util::mwc_util::secp::key::SecretKey;
use mwc_wallet_util::mwc_util::secp::Secp256k1;
use mwc_wallet_util::mwc_util::Mutex;
use std::ops::DerefMut;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
@@ -54,7 +55,7 @@ type Wallet = Arc<
>;

fn revert(
test_dir: &'static str,
test_dir: &str,
) -> Result<
(
Arc<chain::Chain>,
@@ -69,11 +70,12 @@ fn revert(
),
Error,
> {
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let stopper = wallet_proxy.running.clone();
let chain = wallet_proxy.chain.clone();
let test_dir2 = format!("{}/chain2", test_dir);
let wallet_proxy2 = create_wallet_proxy(&test_dir2);
let wallet_proxy2 = create_wallet_proxy(test_dir2, tx_pool.clone());
let chain2 = wallet_proxy2.chain.clone();
let stopper2 = wallet_proxy2.running.clone();
let secp = Secp256k1::new();
@@ -127,7 +129,14 @@ fn revert(

// Mine some blocks
let bh = 10u64;
award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false)?;
award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
)?;

// Sanity check contents
owner(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -138,7 +147,7 @@ fn revert(
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 (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs);
assert_eq!(info.total, c);
assert_eq!(txs.len(), bh as usize);
@@ -153,7 +162,7 @@ fn revert(
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 0);
Ok(())
})?;
@@ -194,7 +203,7 @@ fn revert(
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
let tx = &txs[0];
assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived);
@@ -236,7 +245,7 @@ fn revert(
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
let tx = &txs[0];
assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived);
@@ -272,7 +281,7 @@ fn revert(
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
let tx = &txs[0];
assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReverted);
@@ -306,7 +315,7 @@ fn revert_reconfirm_impl(test_dir: &'static str) -> Result<(), Error> {
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)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
let tx = &txs[0];
assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceived);
@@ -335,7 +344,7 @@ fn revert_cancel_impl(test_dir: &'static str) -> Result<(), Error> {
assert_eq!(info.amount_currently_spendable, 0);
assert_eq!(info.amount_reverted, sent);

let (_, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
let tx = &txs[0];

@@ -351,7 +360,7 @@ fn revert_cancel_impl(test_dir: &'static str) -> Result<(), Error> {
assert_eq!(info.amount_reverted, 0);

// Check updated tx log
let (_, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert_eq!(txs.len(), 1);
let tx = &txs[0];
assert_eq!(tx.tx_type, libwallet::TxLogEntryType::TxReceivedCancelled);
29 changes: 23 additions & 6 deletions controller/tests/self_send.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use libwallet::InitTxArgs;
@@ -31,12 +33,15 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// self send impl
fn self_send_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn self_send_test_impl(test_dir: &str) -> Result<(), wallet::Error> {
// Create a new proxy to simulate server and wallet responses
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -78,8 +83,14 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
w.set_parent_key_id_by_name("mining")?;
}
let mut bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -106,11 +117,17 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
})?;
slate = api.finalize_tx(m, &slate)?;
api.post_tx(m, slate.tx_or_err()?, false)?; // mines a block
bh += 1;
Ok(())
})?;

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// Check total in mining account
29 changes: 25 additions & 4 deletions controller/tests/self_spend.rs
Original file line number Diff line number Diff line change
@@ -21,6 +21,8 @@ extern crate mwc_wallet_impls as impls;

use mwc_wallet_util::mwc_core as core;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::Arc;

use self::libwallet::OutputStatus;
use impls::test_framework::{self, LocalWalletClient};
@@ -31,12 +33,15 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// self send impl
fn self_spend_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn self_spend_impl(test_dir: &str) -> Result<(), wallet::Error> {
// Create a new proxy to simulate server and wallet responses
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();

// Create a new wallet test client, and set its queues to communicate with the
@@ -76,8 +81,14 @@ fn self_spend_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
w.set_parent_key_id_by_name("mining1")?;
}
let mut bh = 4u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

// Check wallet 1 contents are as expected
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -126,6 +137,16 @@ fn self_spend_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
true,
)?;

// Apply transactions
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
2,
false,
tx_pool.lock().deref_mut(),
);

let _fee = core::libtx::tx_fee(1, 1, 1); //there is only one input and one output and one kernel

//after the self spend, make sure the scan is done to update the status.
38 changes: 31 additions & 7 deletions controller/tests/slatepack.rs
Original file line number Diff line number Diff line change
@@ -20,6 +20,8 @@ extern crate mwc_wallet_impls as impls;

use mwc_wallet_libwallet as libwallet;
use mwc_wallet_util::mwc_core as core;
use std::ops::DerefMut;
use std::sync::Arc;

use impls::test_framework::{self, LocalWalletClient};
use impls::{PathToSlateGetter, PathToSlatePutter, SlateGetter, SlatePutter};
@@ -38,7 +40,9 @@ use self::core::global;
use common::{clean_output_dir, create_wallet_proxy, setup};
use impls::adapters::SlateGetData;
use mwc_wallet_libwallet::slatepack::SlatePurpose;
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::secp::Secp256k1;
use mwc_wallet_util::mwc_util::Mutex;

fn output_slatepack(
slate: &Slate,
@@ -77,11 +81,12 @@ fn slate_from_packed(
}

/// self send impl
fn slatepack_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
fn slatepack_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);

// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();
let secp = Secp256k1::new();
@@ -144,8 +149,14 @@ fn slatepack_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet:
w.set_parent_key_id_by_name("mining")?;
}
let mut bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

let (_address1, recipients_1, secret_1, sender_1) = {
let mut pub_key = DalekPublicKey::from_bytes(&[0; 32]).unwrap();
@@ -283,14 +294,20 @@ fn slatepack_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet:
&secp,
)?;
api.post_tx(m, slate.tx_or_err()?, false)?;
bh += 1;
println!("finalize_tx read slate: {:?}", slate);

Ok(())
})
.unwrap();

let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
bh += 3;

// Check total in mining account
@@ -407,7 +424,14 @@ fn slatepack_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet:
.unwrap();

// Standard, with payment proof
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);
let (send_file, receive_file, final_file) = (
format!("{}/standard_pp_S1.slatepack", test_dir),
format!("{}/standard_pp_S2.slatepack", test_dir),
118 changes: 96 additions & 22 deletions controller/tests/transaction.rs
Original file line number Diff line number Diff line change
@@ -19,27 +19,31 @@ extern crate mwc_wallet_controller as wallet;
extern crate mwc_wallet_impls as impls;
extern crate mwc_wallet_libwallet as libwallet;

use mwc_wallet_util::mwc_core as core;
use std::convert::TryInto;

use self::core::core::transaction;
use self::core::global;
use self::libwallet::{InitTxArgs, OutputStatus, Slate};
use impls::test_framework::{self, LocalWalletClient};
use mwc_wallet_util::mwc_core as core;
use std::convert::TryInto;
use std::ops::DerefMut;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// Exercises the Transaction API fully with a test NodeClient operating
/// directly on a chain instance
/// Callable with any type of wallet
fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
fn basic_transaction_api(test_dir: &str) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -80,7 +84,14 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
let reward = core::consensus::MWC_FIRST_GROUP_REWARD;
let cm = global::coinbase_maturity();
// mine a few blocks
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
10,
false,
tx_pool.lock().deref_mut(),
);

// Check wallet 1 contents are as expected
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -148,7 +159,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
// Check transaction log for wallet 1
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
let fee = core::libtx::tx_fee(
wallet1_info.last_confirmed_height as usize - cm as usize,
@@ -169,7 +180,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {

// Check transaction log for wallet 2
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, 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));
@@ -189,6 +200,16 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
Ok(())
})?;

// apply posted tx
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

// Check wallet 1 contents are as expected
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
@@ -214,7 +235,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
assert!(tx.is_some());
@@ -226,7 +247,14 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
})?;

// mine a few more blocks
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
3,
false,
tx_pool.lock().deref_mut(),
);

// refresh wallets and retrieve info/tests for each wallet after maturity
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |api, m| {
@@ -250,7 +278,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
assert!(tx.is_some());
@@ -315,17 +343,41 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
Ok(())
})?;

// apply posted tx
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |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)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, None, None, None)?;
// find the transaction
let tx = txs
.iter()
.find(|t| t.tx_slate_id == Some(slate.id))
.unwrap();
let stored_tx = sender_api.get_stored_tx(m, &tx)?;
sender_api.post_tx(m, &stored_tx.unwrap(), false)?;
Ok(())
})?;

// apply posted tx
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
1,
false,
tx_pool.lock().deref_mut(),
);

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?;
// should be mined now
assert_eq!(
@@ -336,7 +388,14 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
})?;

// mine a few more blocks
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
4,
false,
tx_pool.lock().deref_mut(),
);

// check wallet2 has stored transaction
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
@@ -345,7 +404,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {
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)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
assert!(tx.is_some());
@@ -403,10 +462,11 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), wallet::Error> {

/// Test rolling back transactions and outputs when a transaction is never
/// posted to a chain
fn tx_rollback(test_dir: &'static str) -> Result<(), wallet::Error> {
fn tx_rollback(test_dir: &str) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -445,7 +505,14 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), wallet::Error> {
let reward = core::consensus::MWC_FIRST_GROUP_REWARD;
let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height
// mine a few blocks
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
5,
false,
tx_pool.lock().deref_mut(),
);

let amount = core::consensus::MWC_FIRST_GROUP_REWARD / 2;
let mut slate = Slate::blank(1, false);
@@ -476,7 +543,7 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), wallet::Error> {
wallet1_info.last_confirmed_height
);
assert!(refreshed);
let (_, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (_, txs) = api.retrieve_txs(m, true, None, 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());
@@ -501,7 +568,7 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), wallet::Error> {

// Check transaction log for wallet 2
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
assert!(refreshed);
let mut unconfirmed_count = 0;
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
@@ -524,14 +591,21 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), wallet::Error> {

// 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);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
5,
false,
tx_pool.lock().deref_mut(),
);

// Wallet 1 decides to roll back instead
wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |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 (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
let tx = txs
.iter()
.find(|t| t.tx_slate_id == Some(slate.id))
@@ -558,7 +632,7 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), wallet::Error> {

// Wallet 2 rolls back
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |api, m| {
let (_, txs) = api.retrieve_txs(m, true, None, None, None)?;
let (_, txs) = api.retrieve_txs(m, true, None, None, None, None)?;
let tx = txs
.iter()
.find(|t| t.tx_slate_id == Some(slate.id))
47 changes: 36 additions & 11 deletions controller/tests/ttl_cutoff.rs
Original file line number Diff line number Diff line change
@@ -23,19 +23,24 @@ use impls::test_framework::{self, LocalWalletClient};
use libwallet::{InitTxArgs, Slate, TxLogEntryType};
use mwc_wallet_libwallet as libwallet;
use mwc_wallet_util::mwc_core::global;
use std::ops::DerefMut;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

#[macro_use]
mod common;
use common::{clean_output_dir, create_wallet_proxy, setup};
use mwc_wallet_util::mwc_core::core::Transaction;
use mwc_wallet_util::mwc_util::Mutex;

/// Test cutoff block times
fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
fn ttl_cutoff_test_impl(test_dir: &str) -> Result<(), wallet::Error> {
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let tx_pool: Arc<Mutex<Vec<Transaction>>> = Arc::new(Mutex::new(Vec::new()));
let mut wallet_proxy = create_wallet_proxy(test_dir.into(), tx_pool.clone());
let chain = wallet_proxy.chain.clone();
let stopper = wallet_proxy.running.clone();

@@ -77,8 +82,14 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {

// Do some mining
let bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
tx_pool.lock().deref_mut(),
);

let amount = 2_000_000_000; // mwc had 60_000_000_000
let mut slate = Slate::blank(1, false);
@@ -99,18 +110,25 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
sender_api.tx_lock_outputs(m, &slate, None, 0)?;

let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
let tx = txs[0].clone();

assert_eq!(tx.ttl_cutoff_height, Some(12));
Ok(())
})?;

// 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);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
2,
false,
tx_pool.lock().deref_mut(),
);

wallet::controller::owner_single_use(Some(wallet1.clone()), mask1, None, |sender_api, m| {
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
let tx = txs[0].clone();

assert_eq!(tx.ttl_cutoff_height, Some(12));
@@ -120,7 +138,7 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {

// Should also be gone in wallet 2, and output gone
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |sender_api, m| {
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
let tx = txs[0].clone();
let outputs = sender_api.retrieve_outputs(m, false, true, None)?.1;
assert_eq!(outputs.len(), 0);
@@ -148,19 +166,26 @@ fn ttl_cutoff_test_impl(test_dir: &'static str) -> Result<(), wallet::Error> {
sender_api.tx_lock_outputs(m, &slate_i, None, 0)?;
slate = slate_i;

let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, txs) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
let tx = txs[0].clone();

assert_eq!(tx.ttl_cutoff_height, Some(14));
Ok(())
})?;

// Mine past the ttl block and try to send
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
2,
false,
tx_pool.lock().deref_mut(),
);

// Wallet 2 will need to have updated past the TTL
wallet::controller::owner_single_use(Some(wallet2.clone()), mask2, None, |sender_api, m| {
let (_, _) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None)?;
let (_, _) = sender_api.retrieve_txs(m, true, None, Some(slate.id), None, None)?;
Ok(())
})?;

Loading