mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-05-09 10:31:13 +03:00
Store XORed wallet seed in-mem (#200)
* experimental xor token work * rustfmt * test implementation of build_coinbase_t function * rustfmt * add separate foreign_rpc_s interface for secure functions * rustfmt * rustfmt * fix http scheme to allow https as well * add tokenized owner API, modify all functions to use token * rustfmt * fix for api doctests, tests passing up to api crate * rustfmt * controller crate compilation * rustfmt * controller tests passing and modified some to use masked keychains * rustfmt * fix wallet tests * rustfmt * build from github * rustfmt
This commit is contained in:
parent
5cdd412205
commit
f8c316a351
38 changed files with 3671 additions and 1250 deletions
808
Cargo.lock
generated
808
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,8 @@ failure = "0.1"
|
|||
failure_derive = "0.1"
|
||||
log = "0.4"
|
||||
uuid = { version = "0.7", features = ["serde", "v4"] }
|
||||
serde = "1"
|
||||
serde_derive = "1"
|
||||
serde_json = "1"
|
||||
easy-jsonrpc = "0.5.1"
|
||||
chrono = { version = "0.4.4", features = ["serde"] }
|
||||
|
|
|
@ -20,6 +20,7 @@ use crate::libwallet::{
|
|||
BlockFees, CbData, Error, NodeClient, NodeVersionInfo, Slate, VersionInfo, WalletInst,
|
||||
WalletLCProvider,
|
||||
};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -67,6 +68,8 @@ where
|
|||
pub doctest_mode: bool,
|
||||
/// foreign check middleware
|
||||
middleware: Option<ForeignCheckMiddleware>,
|
||||
/// Stored keychain mask (in case the stored wallet seed is tokenized)
|
||||
keychain_mask: Option<SecretKey>,
|
||||
}
|
||||
|
||||
impl<'a, L, C, K> Foreign<'a, L, C, K>
|
||||
|
@ -86,6 +89,9 @@ where
|
|||
/// # Arguments
|
||||
/// * `wallet_in` - A reference-counted mutex containing an implementation of the
|
||||
/// [`WalletBackend`](../grin_wallet_libwallet/types/trait.WalletBackend.html) trait.
|
||||
/// * `keychain_mask` - Mask value stored internally to use when calling a wallet
|
||||
/// whose seed has been XORed with a token value (such as when running the foreign
|
||||
/// and owner listeners in the same instance)
|
||||
/// * middleware - Option middleware which containts the NodeVersionInfo and can call
|
||||
/// a predefined function with the slate to check if the operation should continue
|
||||
///
|
||||
|
@ -142,24 +148,26 @@ where
|
|||
///
|
||||
/// // Wallet must be opened with the password (TBD)
|
||||
/// let pw = ZeroingString::from("wallet_password");
|
||||
/// lc.open_wallet(None, pw);
|
||||
/// lc.open_wallet(None, pw, false, false);
|
||||
///
|
||||
/// // All wallet functions operate on an Arc::Mutex to allow multithreading where needed
|
||||
/// let mut wallet = Arc::new(Mutex::new(wallet));
|
||||
///
|
||||
/// let api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// let api_foreign = Foreign::new(wallet.clone(), None, None);
|
||||
/// // .. perform wallet operations
|
||||
///
|
||||
/// ```
|
||||
|
||||
pub fn new(
|
||||
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
middleware: Option<ForeignCheckMiddleware>,
|
||||
) -> Self {
|
||||
Foreign {
|
||||
wallet_inst,
|
||||
doctest_mode: false,
|
||||
middleware,
|
||||
keychain_mask,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -173,7 +181,7 @@ where
|
|||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
|
||||
///
|
||||
/// let version_info = api_foreign.check_version();
|
||||
/// // check and proceed accordingly
|
||||
|
@ -225,7 +233,7 @@ where
|
|||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
|
||||
///
|
||||
/// let block_fees = BlockFees {
|
||||
/// fees: 800000,
|
||||
|
@ -252,7 +260,12 @@ where
|
|||
None,
|
||||
)?;
|
||||
}
|
||||
foreign::build_coinbase(&mut **w, block_fees, self.doctest_mode)
|
||||
foreign::build_coinbase(
|
||||
&mut **w,
|
||||
(&self.keychain_mask).as_ref(),
|
||||
block_fees,
|
||||
self.doctest_mode,
|
||||
)
|
||||
}
|
||||
|
||||
/// Verifies all messages in the slate match their public keys.
|
||||
|
@ -276,7 +289,7 @@ where
|
|||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
|
||||
///
|
||||
/// # let slate = Slate::blank(2);
|
||||
/// // Receive a slate via some means
|
||||
|
@ -349,7 +362,7 @@ where
|
|||
/// ```
|
||||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
|
||||
/// # let slate = Slate::blank(2);
|
||||
///
|
||||
/// // . . .
|
||||
|
@ -377,7 +390,14 @@ where
|
|||
Some(slate),
|
||||
)?;
|
||||
}
|
||||
foreign::receive_tx(&mut **w, slate, dest_acct_name, message, self.doctest_mode)
|
||||
foreign::receive_tx(
|
||||
&mut **w,
|
||||
(&self.keychain_mask).as_ref(),
|
||||
slate,
|
||||
dest_acct_name,
|
||||
message,
|
||||
self.doctest_mode,
|
||||
)
|
||||
}
|
||||
|
||||
/// Finalizes an invoice transaction initiated by this wallet's Owner api.
|
||||
|
@ -408,7 +428,7 @@ where
|
|||
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_owner = Owner::new(wallet.clone());
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
|
||||
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
|
||||
///
|
||||
/// // . . .
|
||||
/// // Issue the invoice tx via the owner API
|
||||
|
@ -416,7 +436,7 @@ where
|
|||
/// amount: 10_000_000_000,
|
||||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.issue_invoice_tx(args);
|
||||
/// let result = api_owner.issue_invoice_tx(None, args);
|
||||
///
|
||||
/// // If result okay, send to payer, who will apply the transaction via their
|
||||
/// // owner API, then send back the slate
|
||||
|
@ -437,7 +457,7 @@ where
|
|||
Some(slate),
|
||||
)?;
|
||||
}
|
||||
foreign::finalize_invoice_tx(&mut **w, slate)
|
||||
foreign::finalize_invoice_tx(&mut **w, (&self.keychain_mask).as_ref(), slate)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -487,7 +507,7 @@ macro_rules! doctest_helper_setup_doc_env_foreign {
|
|||
>;
|
||||
let lc = wallet.lc_provider().unwrap();
|
||||
lc.set_wallet_directory(&wallet_config.data_file_dir);
|
||||
lc.open_wallet(None, pw);
|
||||
lc.open_wallet(None, pw, false, false);
|
||||
let mut $wallet = Arc::new(Mutex::new(wallet));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -58,13 +58,13 @@ pub trait ForeignRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 0, false, false);
|
||||
# ,false, 0, false, false);
|
||||
```
|
||||
*/
|
||||
fn check_version(&self) -> Result<VersionInfo, ErrorKind>;
|
||||
|
||||
/**
|
||||
Networked version of [Foreign::build_coinbase](struct.Foreign.html#method.build_coinbase).
|
||||
Networked Legacy (non-secure token) version of [Foreign::build_coinbase](struct.Foreign.html#method.build_coinbase).
|
||||
|
||||
# Json rpc example
|
||||
|
||||
|
@ -108,9 +108,10 @@ pub trait ForeignRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 4, false, false);
|
||||
# ,false, 4, false, false);
|
||||
```
|
||||
*/
|
||||
|
||||
fn build_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, ErrorKind>;
|
||||
|
||||
/**
|
||||
|
@ -188,7 +189,7 @@ pub trait ForeignRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,1 ,false, false);
|
||||
# ,false, 1 ,false, false);
|
||||
```
|
||||
*/
|
||||
fn verify_slate_messages(&self, slate: &Slate) -> Result<(), ErrorKind>;
|
||||
|
@ -341,7 +342,7 @@ pub trait ForeignRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, true, false);
|
||||
# ,false, 5, true, false);
|
||||
```
|
||||
*/
|
||||
fn receive_tx(
|
||||
|
@ -509,7 +510,7 @@ pub trait ForeignRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, false, true);
|
||||
# ,false, 5, false, true);
|
||||
```
|
||||
*/
|
||||
fn finalize_invoice_tx(&self, slate: &Slate) -> Result<Slate, ErrorKind>;
|
||||
|
@ -571,6 +572,7 @@ fn test_check_middleware(
|
|||
pub fn run_doctest_foreign(
|
||||
request: serde_json::Value,
|
||||
test_dir: &str,
|
||||
use_token: bool,
|
||||
blocks_to_mine: u64,
|
||||
init_tx: bool,
|
||||
init_invoice_tx: bool,
|
||||
|
@ -622,10 +624,21 @@ pub fn run_doctest_foreign(
|
|||
lc.set_wallet_directory(&format!("{}/wallet1", test_dir));
|
||||
lc.create_wallet(None, Some(rec_phrase_1), 32, empty_string.clone())
|
||||
.unwrap();
|
||||
lc.open_wallet(None, empty_string.clone()).unwrap();
|
||||
let mask1 = lc
|
||||
.open_wallet(None, empty_string.clone(), use_token, true)
|
||||
.unwrap();
|
||||
let wallet1 = Arc::new(Mutex::new(wallet1));
|
||||
|
||||
wallet_proxy.add_wallet("wallet1", client1.get_send_instance(), wallet1.clone());
|
||||
if mask1.is_some() {
|
||||
println!("WALLET 1 MASK: {:?}", mask1.clone().unwrap());
|
||||
}
|
||||
|
||||
wallet_proxy.add_wallet(
|
||||
"wallet1",
|
||||
client1.get_send_instance(),
|
||||
wallet1.clone(),
|
||||
mask1.clone(),
|
||||
);
|
||||
|
||||
let rec_phrase_2 = util::ZeroingString::from(
|
||||
"hour kingdom ripple lunch razor inquiry coyote clay stamp mean \
|
||||
|
@ -646,10 +659,17 @@ pub fn run_doctest_foreign(
|
|||
lc.set_wallet_directory(&format!("{}/wallet2", test_dir));
|
||||
lc.create_wallet(None, Some(rec_phrase_2), 32, empty_string.clone())
|
||||
.unwrap();
|
||||
lc.open_wallet(None, empty_string.clone()).unwrap();
|
||||
let mask2 = lc
|
||||
.open_wallet(None, empty_string.clone(), use_token, true)
|
||||
.unwrap();
|
||||
let wallet2 = Arc::new(Mutex::new(wallet2));
|
||||
|
||||
wallet_proxy.add_wallet("wallet2", client2.get_send_instance(), wallet2.clone());
|
||||
wallet_proxy.add_wallet(
|
||||
"wallet2",
|
||||
client2.get_send_instance(),
|
||||
wallet2.clone(),
|
||||
mask2.clone(),
|
||||
);
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -660,12 +680,18 @@ pub fn run_doctest_foreign(
|
|||
|
||||
// Mine a few blocks to wallet 1 so there's something to send
|
||||
for _ in 0..blocks_to_mine {
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 1 as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
wallet1.clone(),
|
||||
(&mask1).as_ref(),
|
||||
1 as usize,
|
||||
false,
|
||||
);
|
||||
//update local outputs after each block, so transaction IDs stay consistent
|
||||
let mut w_lock = wallet1.lock();
|
||||
let w = w_lock.lc_provider().unwrap().wallet_inst().unwrap();
|
||||
let (wallet_refreshed, _) =
|
||||
api_impl::owner::retrieve_summary_info(&mut **w, true, 1).unwrap();
|
||||
api_impl::owner::retrieve_summary_info(&mut **w, (&mask1).as_ref(), true, 1).unwrap();
|
||||
assert!(wallet_refreshed);
|
||||
}
|
||||
|
||||
|
@ -678,7 +704,7 @@ pub fn run_doctest_foreign(
|
|||
amount,
|
||||
..Default::default()
|
||||
};
|
||||
api_impl::owner::issue_invoice_tx(&mut **w, args, true).unwrap()
|
||||
api_impl::owner::issue_invoice_tx(&mut **w, (&mask2).as_ref(), args, true).unwrap()
|
||||
};
|
||||
slate = {
|
||||
let mut w_lock = wallet1.lock();
|
||||
|
@ -692,7 +718,8 @@ pub fn run_doctest_foreign(
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
api_impl::owner::process_invoice_tx(&mut **w, &slate, args, true).unwrap()
|
||||
api_impl::owner::process_invoice_tx(&mut **w, (&mask1).as_ref(), &slate, args, true)
|
||||
.unwrap()
|
||||
};
|
||||
println!("INIT INVOICE SLATE");
|
||||
// Spit out slate for input to finalize_invoice_tx
|
||||
|
@ -712,15 +739,15 @@ pub fn run_doctest_foreign(
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api_impl::owner::init_send_tx(&mut **w, args, true).unwrap();
|
||||
let slate = api_impl::owner::init_send_tx(&mut **w, (&mask1).as_ref(), args, true).unwrap();
|
||||
println!("INIT SLATE");
|
||||
// Spit out slate for input to finalize_tx
|
||||
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
|
||||
}
|
||||
|
||||
let mut api_foreign = match init_invoice_tx {
|
||||
false => Foreign::new(wallet1, Some(test_check_middleware)),
|
||||
true => Foreign::new(wallet2, Some(test_check_middleware)),
|
||||
false => Foreign::new(wallet1, mask1, Some(test_check_middleware)),
|
||||
true => Foreign::new(wallet2, mask2, Some(test_check_middleware)),
|
||||
};
|
||||
api_foreign.doctest_mode = true;
|
||||
let foreign_api = &api_foreign as &dyn ForeignRpc;
|
||||
|
@ -730,7 +757,7 @@ pub fn run_doctest_foreign(
|
|||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! doctest_helper_json_rpc_foreign_assert_response {
|
||||
($request:expr, $expected_response:expr, $blocks_to_mine:expr, $init_tx:expr, $init_invoice_tx:expr) => {
|
||||
($request:expr, $expected_response:expr, $use_token:expr, $blocks_to_mine:expr, $init_tx:expr, $init_invoice_tx:expr) => {
|
||||
// create temporary wallet, run jsonrpc request on owner api of wallet, delete wallet, return
|
||||
// json response.
|
||||
// In order to prevent leaking tempdirs, This function should not panic.
|
||||
|
@ -752,6 +779,7 @@ macro_rules! doctest_helper_json_rpc_foreign_assert_response {
|
|||
let response = run_doctest_foreign(
|
||||
request_val,
|
||||
dir,
|
||||
$use_token,
|
||||
$blocks_to_mine,
|
||||
$init_tx,
|
||||
$init_invoice_tx,
|
||||
|
|
|
@ -29,6 +29,8 @@ extern crate grin_wallet_impls as impls;
|
|||
extern crate grin_wallet_libwallet as libwallet;
|
||||
|
||||
extern crate failure_derive;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
#[macro_use]
|
||||
|
@ -39,12 +41,25 @@ mod foreign_rpc;
|
|||
|
||||
mod owner;
|
||||
mod owner_rpc;
|
||||
mod owner_rpc_s;
|
||||
|
||||
pub use crate::foreign::{Foreign, ForeignCheckMiddleware, ForeignCheckMiddlewareFn};
|
||||
pub use crate::foreign_rpc::ForeignRpc;
|
||||
pub use crate::owner::Owner;
|
||||
pub use crate::owner_rpc::OwnerRpc;
|
||||
pub use crate::owner_rpc_s::OwnerRpcS;
|
||||
|
||||
pub use crate::foreign_rpc::foreign_rpc as foreign_rpc_client;
|
||||
pub use crate::foreign_rpc::run_doctest_foreign;
|
||||
pub use crate::owner_rpc::run_doctest_owner;
|
||||
|
||||
use grin_wallet_util::grin_core::libtx::secp_ser;
|
||||
use util::secp::key::SecretKey;
|
||||
|
||||
/// Wrapper for API Tokens
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(transparent)]
|
||||
pub struct Token {
|
||||
#[serde(with = "secp_ser::option_seckey_serde")]
|
||||
keychain_mask: Option<SecretKey>,
|
||||
}
|
||||
|
|
257
api/src/owner.rs
257
api/src/owner.rs
|
@ -26,6 +26,7 @@ use crate::libwallet::{
|
|||
NodeHeightResult, OutputCommitMapping, Slate, TxLogEntry, WalletInfo, WalletInst,
|
||||
WalletLCProvider,
|
||||
};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -126,7 +127,7 @@ where
|
|||
///
|
||||
/// // Wallet must be opened with the password (TBD)
|
||||
/// let pw = ZeroingString::from("wallet_password");
|
||||
/// lc.open_wallet(None, pw);
|
||||
/// lc.open_wallet(None, pw, false, false);
|
||||
///
|
||||
/// // All wallet functions operate on an Arc::Mutex to allow multithreading where needed
|
||||
/// let mut wallet = Arc::new(Mutex::new(wallet));
|
||||
|
@ -145,6 +146,9 @@ where
|
|||
|
||||
/// Returns a list of accounts stored in the wallet (i.e. mappings between
|
||||
/// user-specified labels and BIP32 derivation paths.
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
///
|
||||
/// # Returns
|
||||
/// * Result Containing:
|
||||
|
@ -164,16 +168,21 @@ where
|
|||
///
|
||||
/// let api_owner = Owner::new(wallet.clone());
|
||||
///
|
||||
/// let result = api_owner.accounts();
|
||||
/// let result = api_owner.accounts(None);
|
||||
///
|
||||
/// if let Ok(accts) = result {
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn accounts(&self) -> Result<Vec<AcctPathMapping>, Error> {
|
||||
pub fn accounts(
|
||||
&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()?;
|
||||
// Test keychain mask, to keep API consistent
|
||||
let _ = w.keychain(keychain_mask)?;
|
||||
owner::accounts(&mut **w)
|
||||
}
|
||||
|
||||
|
@ -181,6 +190,9 @@ where
|
|||
/// label to a BIP32 path
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `label` - A human readable label to which to map the new BIP32 Path
|
||||
///
|
||||
/// # Returns
|
||||
|
@ -207,23 +219,29 @@ where
|
|||
///
|
||||
/// let api_owner = Owner::new(wallet.clone());
|
||||
///
|
||||
/// let result = api_owner.create_account_path("account1");
|
||||
/// let result = api_owner.create_account_path(None, "account1");
|
||||
///
|
||||
/// if let Ok(identifier) = result {
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn create_account_path(&self, label: &str) -> Result<Identifier, Error> {
|
||||
pub fn create_account_path(
|
||||
&self,
|
||||
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()?;
|
||||
owner::create_account_path(&mut **w, label)
|
||||
owner::create_account_path(&mut **w, keychain_mask, label)
|
||||
}
|
||||
|
||||
/// Sets the wallet's currently active account. This sets the
|
||||
/// BIP32 parent path used for most key-derivation operations.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `label` - The human readable label for the account. Accounts can be retrieved via
|
||||
/// the [`account`](struct.Owner.html#method.accounts) method
|
||||
///
|
||||
|
@ -248,23 +266,31 @@ where
|
|||
///
|
||||
/// let api_owner = Owner::new(wallet.clone());
|
||||
///
|
||||
/// let result = api_owner.create_account_path("account1");
|
||||
/// let result = api_owner.create_account_path(None, "account1");
|
||||
///
|
||||
/// if let Ok(identifier) = result {
|
||||
/// // set the account active
|
||||
/// let result2 = api_owner.set_active_account("account1");
|
||||
/// let result2 = api_owner.set_active_account(None, "account1");
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn set_active_account(&self, label: &str) -> Result<(), Error> {
|
||||
pub fn set_active_account(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
label: &str,
|
||||
) -> Result<(), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
// Test keychain mask, to keep API consistent
|
||||
let _ = w.keychain(keychain_mask)?;
|
||||
owner::set_active_account(&mut **w, label)
|
||||
}
|
||||
|
||||
/// Returns a list of outputs from the active account in the wallet.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `include_spent` - If `true`, outputs that have been marked as 'spent'
|
||||
/// in the wallet will be returned. If `false`, spent outputs will omitted
|
||||
/// from the results.
|
||||
|
@ -297,7 +323,7 @@ where
|
|||
/// let update_from_node = true;
|
||||
/// let tx_id = None;
|
||||
///
|
||||
/// let result = api_owner.retrieve_outputs(show_spent, update_from_node, tx_id);
|
||||
/// let result = api_owner.retrieve_outputs(None, show_spent, update_from_node, tx_id);
|
||||
///
|
||||
/// if let Ok((was_updated, output_mappings)) = result {
|
||||
/// //...
|
||||
|
@ -306,19 +332,28 @@ where
|
|||
|
||||
pub fn retrieve_outputs(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
include_spent: bool,
|
||||
refresh_from_node: bool,
|
||||
tx_id: Option<u32>,
|
||||
) -> Result<(bool, Vec<OutputCommitMapping>), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::retrieve_outputs(&mut **w, include_spent, refresh_from_node, tx_id)
|
||||
owner::retrieve_outputs(
|
||||
&mut **w,
|
||||
keychain_mask,
|
||||
include_spent,
|
||||
refresh_from_node,
|
||||
tx_id,
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns a list of [Transaction Log Entries](../grin_wallet_libwallet/types/struct.TxLogEntry.html)
|
||||
/// from the active account in the wallet.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `refresh_from_node` - If true, the wallet will attempt to contact
|
||||
/// a node (via the [`NodeClient`](../grin_wallet_libwallet/types/trait.NodeClient.html)
|
||||
/// provided during wallet instantiation). If `false`, the results will
|
||||
|
@ -348,7 +383,7 @@ where
|
|||
/// let tx_slate_id = None;
|
||||
///
|
||||
/// // Return all TxLogEntries
|
||||
/// let result = api_owner.retrieve_txs(update_from_node, tx_id, tx_slate_id);
|
||||
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id);
|
||||
///
|
||||
/// if let Ok((was_updated, tx_log_entries)) = result {
|
||||
/// //...
|
||||
|
@ -357,13 +392,20 @@ where
|
|||
|
||||
pub fn retrieve_txs(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
refresh_from_node: bool,
|
||||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
) -> Result<(bool, Vec<TxLogEntry>), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
let mut res = owner::retrieve_txs(&mut **w, refresh_from_node, tx_id, tx_slate_id)?;
|
||||
let mut res = owner::retrieve_txs(
|
||||
&mut **w,
|
||||
keychain_mask,
|
||||
refresh_from_node,
|
||||
tx_id,
|
||||
tx_slate_id,
|
||||
)?;
|
||||
if self.doctest_mode {
|
||||
res.1 = res
|
||||
.1
|
||||
|
@ -381,6 +423,8 @@ where
|
|||
/// Returns summary information from the active account in the wallet.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `refresh_from_node` - If true, the wallet will attempt to contact
|
||||
/// a node (via the [`NodeClient`](../grin_wallet_libwallet/types/trait.NodeClient.html)
|
||||
/// provided during wallet instantiation). If `false`, the results will
|
||||
|
@ -406,7 +450,7 @@ where
|
|||
/// let minimum_confirmations=10;
|
||||
///
|
||||
/// // Return summary info for active account
|
||||
/// let result = api_owner.retrieve_summary_info(update_from_node, minimum_confirmations);
|
||||
/// let result = api_owner.retrieve_summary_info(None, update_from_node, minimum_confirmations);
|
||||
///
|
||||
/// if let Ok((was_updated, summary_info)) = result {
|
||||
/// //...
|
||||
|
@ -415,12 +459,18 @@ where
|
|||
|
||||
pub fn retrieve_summary_info(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
refresh_from_node: bool,
|
||||
minimum_confirmations: u64,
|
||||
) -> Result<(bool, WalletInfo), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::retrieve_summary_info(&mut **w, refresh_from_node, minimum_confirmations)
|
||||
owner::retrieve_summary_info(
|
||||
&mut **w,
|
||||
keychain_mask,
|
||||
refresh_from_node,
|
||||
minimum_confirmations,
|
||||
)
|
||||
}
|
||||
|
||||
/// Initiates a new transaction as the sender, creating a new
|
||||
|
@ -447,6 +497,8 @@ where
|
|||
/// the `finalize` field is set.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `args` - [`InitTxArgs`](../grin_wallet_libwallet/types/struct.InitTxArgs.html),
|
||||
/// transaction initialization arguments. See struct documentation for further detail.
|
||||
///
|
||||
|
@ -485,6 +537,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.init_send_tx(
|
||||
/// None,
|
||||
/// args,
|
||||
/// );
|
||||
///
|
||||
|
@ -492,16 +545,20 @@ where
|
|||
/// // Send slate somehow
|
||||
/// // ...
|
||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||
/// api_owner.tx_lock_outputs(&slate, 0);
|
||||
/// api_owner.tx_lock_outputs(None, &slate, 0);
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn init_send_tx(&self, args: InitTxArgs) -> Result<Slate, Error> {
|
||||
pub fn init_send_tx(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: InitTxArgs,
|
||||
) -> Result<Slate, Error> {
|
||||
let send_args = args.send_args.clone();
|
||||
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, args, self.doctest_mode)?
|
||||
owner::init_send_tx(&mut **w, keychain_mask, args, self.doctest_mode)?
|
||||
};
|
||||
// Helper functionality. If send arguments exist, attempt to send
|
||||
match send_args {
|
||||
|
@ -520,14 +577,14 @@ where
|
|||
let comm_adapter = create_sender(&sa.method, &sa.dest)
|
||||
.map_err(|e| ErrorKind::GenericError(format!("{}", e)))?;
|
||||
slate = comm_adapter.send_tx(&slate)?;
|
||||
self.tx_lock_outputs(&slate, 0)?;
|
||||
self.tx_lock_outputs(keychain_mask, &slate, 0)?;
|
||||
let slate = match sa.finalize {
|
||||
true => self.finalize_tx(&slate)?,
|
||||
true => self.finalize_tx(keychain_mask, &slate)?,
|
||||
false => slate,
|
||||
};
|
||||
|
||||
if sa.post_tx {
|
||||
self.post_tx(&slate.tx, sa.fluff)?;
|
||||
self.post_tx(keychain_mask, &slate.tx, sa.fluff)?;
|
||||
}
|
||||
Ok(slate)
|
||||
}
|
||||
|
@ -542,6 +599,8 @@ where
|
|||
/// via the [Foreign API's `finalize_invoice_tx`](struct.Foreign.html#method.finalize_invoice_tx) method.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `args` - [`IssueInvoiceTxArgs`](../grin_wallet_libwallet/types/struct.IssueInvoiceTxArgs.html),
|
||||
/// invoice transaction initialization arguments. See struct documentation for further detail.
|
||||
///
|
||||
|
@ -561,17 +620,21 @@ where
|
|||
/// amount: 60_000_000_000,
|
||||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.issue_invoice_tx(args);
|
||||
/// let result = api_owner.issue_invoice_tx(None, args);
|
||||
///
|
||||
/// if let Ok(slate) = result {
|
||||
/// // if okay, send to the payer to add their inputs
|
||||
/// // . . .
|
||||
/// }
|
||||
/// ```
|
||||
pub fn issue_invoice_tx(&self, args: IssueInvoiceTxArgs) -> Result<Slate, Error> {
|
||||
pub fn issue_invoice_tx(
|
||||
&self,
|
||||
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()?;
|
||||
owner::issue_invoice_tx(&mut **w, args, self.doctest_mode)
|
||||
owner::issue_invoice_tx(&mut **w, keychain_mask, args, self.doctest_mode)
|
||||
}
|
||||
|
||||
/// Processes an invoice tranaction created by another party, essentially
|
||||
|
@ -589,6 +652,8 @@ where
|
|||
/// via the [`get_stored_tx`](struct.Owner.html#method.get_stored_tx) function.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html). The
|
||||
/// payer should have filled in round 1 and 2.
|
||||
/// * `args` - [`InitTxArgs`](../grin_wallet_libwallet/types/struct.InitTxArgs.html),
|
||||
|
@ -619,7 +684,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
///
|
||||
/// let result = api_owner.process_invoice_tx(&slate, args);
|
||||
/// let result = api_owner.process_invoice_tx(None, &slate, args);
|
||||
///
|
||||
/// if let Ok(slate) = result {
|
||||
/// // If result okay, send back to the invoicer
|
||||
|
@ -627,10 +692,15 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn process_invoice_tx(&self, slate: &Slate, args: InitTxArgs) -> Result<Slate, Error> {
|
||||
pub fn process_invoice_tx(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
args: InitTxArgs,
|
||||
) -> Result<Slate, Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::process_invoice_tx(&mut **w, slate, args, self.doctest_mode)
|
||||
owner::process_invoice_tx(&mut **w, keychain_mask, slate, args, self.doctest_mode)
|
||||
}
|
||||
|
||||
/// Locks the outputs associated with the inputs to the transaction in the given
|
||||
|
@ -647,6 +717,8 @@ where
|
|||
/// and return them to the `Unspent` state.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html). All
|
||||
/// * `participant_id` - The participant id, generally 0 for the party putting in funds, 1 for the
|
||||
/// party receiving.
|
||||
|
@ -674,6 +746,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.init_send_tx(
|
||||
/// None,
|
||||
/// args,
|
||||
/// );
|
||||
///
|
||||
|
@ -681,14 +754,19 @@ where
|
|||
/// // Send slate somehow
|
||||
/// // ...
|
||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||
/// api_owner.tx_lock_outputs(&slate, 0);
|
||||
/// api_owner.tx_lock_outputs(None, &slate, 0);
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn tx_lock_outputs(&self, slate: &Slate, participant_id: usize) -> Result<(), Error> {
|
||||
pub fn tx_lock_outputs(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
participant_id: usize,
|
||||
) -> Result<(), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::tx_lock_outputs(&mut **w, slate, participant_id)
|
||||
owner::tx_lock_outputs(&mut **w, keychain_mask, slate, participant_id)
|
||||
}
|
||||
|
||||
/// Finalizes a transaction, after all parties
|
||||
|
@ -704,6 +782,8 @@ where
|
|||
/// via the [`get_stored_tx`](struct.Owner.html#method.get_stored_tx) function.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html). All
|
||||
/// participants must have filled in both rounds, and the sender should have locked their
|
||||
/// outputs (via the [`tx_lock_outputs`](struct.Owner.html#method.tx_lock_outputs) function).
|
||||
|
@ -730,6 +810,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.init_send_tx(
|
||||
/// None,
|
||||
/// args,
|
||||
/// );
|
||||
///
|
||||
|
@ -737,27 +818,32 @@ where
|
|||
/// // Send slate somehow
|
||||
/// // ...
|
||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||
/// let res = api_owner.tx_lock_outputs(&slate, 0);
|
||||
/// let res = api_owner.tx_lock_outputs(None, &slate, 0);
|
||||
/// //
|
||||
/// // Retrieve slate back from recipient
|
||||
/// //
|
||||
/// let res = api_owner.finalize_tx(&slate);
|
||||
/// let res = api_owner.finalize_tx(None, &slate);
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn finalize_tx(&self, slate: &Slate) -> Result<Slate, Error> {
|
||||
pub fn finalize_tx(
|
||||
&self,
|
||||
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()?;
|
||||
owner::finalize_tx(&mut **w, &slate)
|
||||
owner::finalize_tx(&mut **w, keychain_mask, &slate)
|
||||
}
|
||||
|
||||
/// Posts a completed transaction to the listening node for validation and inclusion in a block
|
||||
/// for mining.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `tx` - A completed [`Transaction`](../grin_core/core/transaction/struct.Transaction.html),
|
||||
/// typically the `tx` field in the transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html).
|
||||
///
|
||||
/// * `fluff` - Instruct the node whether to use the Dandelion protocol when posting the
|
||||
/// transaction. If `true`, the node should skip the Dandelion phase and broadcast the
|
||||
/// transaction to all peers immediately. If `false`, the node will follow dandelion logic and
|
||||
|
@ -784,6 +870,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.init_send_tx(
|
||||
/// None,
|
||||
/// args,
|
||||
/// );
|
||||
///
|
||||
|
@ -791,19 +878,26 @@ where
|
|||
/// // Send slate somehow
|
||||
/// // ...
|
||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||
/// let res = api_owner.tx_lock_outputs(&slate, 0);
|
||||
/// let res = api_owner.tx_lock_outputs(None, &slate, 0);
|
||||
/// //
|
||||
/// // Retrieve slate back from recipient
|
||||
/// //
|
||||
/// let res = api_owner.finalize_tx(&slate);
|
||||
/// let res = api_owner.post_tx(&slate.tx, true);
|
||||
/// let res = api_owner.finalize_tx(None, &slate);
|
||||
/// let res = api_owner.post_tx(None, &slate.tx, true);
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), Error> {
|
||||
pub fn post_tx(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
tx: &Transaction,
|
||||
fluff: bool,
|
||||
) -> Result<(), Error> {
|
||||
let client = {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
// Test keychain mask, to keep API consistent
|
||||
let _ = w.keychain(keychain_mask)?;
|
||||
w.w2n_client().clone()
|
||||
};
|
||||
owner::post_tx(&client, tx, fluff)
|
||||
|
@ -820,6 +914,8 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `tx_id` - If present, cancel by the [`TxLogEntry`](../grin_wallet_libwallet/types/struct.TxLogEntry.html) id
|
||||
/// for the transaction.
|
||||
///
|
||||
|
@ -846,6 +942,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.init_send_tx(
|
||||
/// None,
|
||||
/// args,
|
||||
/// );
|
||||
///
|
||||
|
@ -853,18 +950,23 @@ where
|
|||
/// // Send slate somehow
|
||||
/// // ...
|
||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||
/// let res = api_owner.tx_lock_outputs(&slate, 0);
|
||||
/// let res = api_owner.tx_lock_outputs(None, &slate, 0);
|
||||
/// //
|
||||
/// // We didn't get the slate back, or something else went wrong
|
||||
/// //
|
||||
/// let res = api_owner.cancel_tx(None, Some(slate.id.clone()));
|
||||
/// let res = api_owner.cancel_tx(None, None, Some(slate.id.clone()));
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn cancel_tx(&self, tx_id: Option<u32>, tx_slate_id: Option<Uuid>) -> Result<(), Error> {
|
||||
pub fn cancel_tx(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
) -> Result<(), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::cancel_tx(&mut **w, tx_id, tx_slate_id)
|
||||
owner::cancel_tx(&mut **w, keychain_mask, tx_id, tx_slate_id)
|
||||
}
|
||||
|
||||
/// Retrieves the stored transaction associated with a TxLogEntry. Can be used even after the
|
||||
|
@ -872,6 +974,8 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `tx_log_entry` - A [`TxLogEntry`](../grin_wallet_libwallet/types/struct.TxLogEntry.html)
|
||||
///
|
||||
/// # Returns
|
||||
|
@ -890,18 +994,24 @@ where
|
|||
/// let tx_slate_id = None;
|
||||
///
|
||||
/// // Return all TxLogEntries
|
||||
/// let result = api_owner.retrieve_txs(update_from_node, tx_id, tx_slate_id);
|
||||
/// let result = api_owner.retrieve_txs(None, update_from_node, tx_id, tx_slate_id);
|
||||
///
|
||||
/// if let Ok((was_updated, tx_log_entries)) = result {
|
||||
/// let stored_tx = api_owner.get_stored_tx(&tx_log_entries[0]).unwrap();
|
||||
/// let stored_tx = api_owner.get_stored_tx(None, &tx_log_entries[0]).unwrap();
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
// TODO: Should be accepting an id, not an entire entry struct
|
||||
pub fn get_stored_tx(&self, tx_log_entry: &TxLogEntry) -> Result<Option<Transaction>, Error> {
|
||||
pub fn get_stored_tx(
|
||||
&self,
|
||||
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()?;
|
||||
// Test keychain mask, to keep API consistent
|
||||
let _ = w.keychain(keychain_mask)?;
|
||||
owner::get_stored_tx(&**w, tx_log_entry)
|
||||
}
|
||||
|
||||
|
@ -915,6 +1025,8 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html).
|
||||
///
|
||||
/// # Returns
|
||||
|
@ -938,6 +1050,7 @@ where
|
|||
/// ..Default::default()
|
||||
/// };
|
||||
/// let result = api_owner.init_send_tx(
|
||||
/// None,
|
||||
/// args,
|
||||
/// );
|
||||
///
|
||||
|
@ -945,14 +1058,24 @@ where
|
|||
/// // Send slate somehow
|
||||
/// // ...
|
||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||
/// let res = api_owner.tx_lock_outputs(&slate, 0);
|
||||
/// let res = api_owner.tx_lock_outputs(None, &slate, 0);
|
||||
/// //
|
||||
/// // Retrieve slate back from recipient
|
||||
/// //
|
||||
/// let res = api_owner.verify_slate_messages(&slate);
|
||||
/// let res = api_owner.verify_slate_messages(None, &slate);
|
||||
/// }
|
||||
/// ```
|
||||
pub fn verify_slate_messages(&self, slate: &Slate) -> Result<(), Error> {
|
||||
pub fn verify_slate_messages(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
) -> Result<(), Error> {
|
||||
{
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
// Test keychain mask, to keep API consistent
|
||||
let _ = w.keychain(keychain_mask)?;
|
||||
}
|
||||
owner::verify_slate_messages(slate)
|
||||
}
|
||||
|
||||
|
@ -971,7 +1094,8 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * None
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Ok(())` if successful
|
||||
|
@ -983,17 +1107,17 @@ where
|
|||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||
///
|
||||
/// let mut api_owner = Owner::new(wallet.clone());
|
||||
/// let result = api_owner.restore();
|
||||
/// let result = api_owner.restore(None);
|
||||
///
|
||||
/// if let Ok(_) = result {
|
||||
/// // Wallet outputs should be consistent with what's on chain
|
||||
/// // ...
|
||||
/// }
|
||||
/// ```
|
||||
pub fn restore(&self) -> Result<(), Error> {
|
||||
pub fn restore(&self, keychain_mask: Option<&SecretKey>) -> Result<(), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
let res = owner::restore(&mut **w);
|
||||
let res = owner::restore(&mut **w, keychain_mask);
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -1013,6 +1137,8 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
/// * `delete_unconfirmed` - if `false`, the check_repair process will be non-destructive, and
|
||||
/// mostly limited to restoring missing outputs. It will leave unconfirmed transaction logs entries
|
||||
/// and unconfirmed outputs intact. If `true`, the process will unlock all locked outputs,
|
||||
|
@ -1034,6 +1160,7 @@ where
|
|||
///
|
||||
/// let mut api_owner = Owner::new(wallet.clone());
|
||||
/// let result = api_owner.check_repair(
|
||||
/// None,
|
||||
/// false,
|
||||
/// );
|
||||
///
|
||||
|
@ -1043,10 +1170,14 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), Error> {
|
||||
pub fn check_repair(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
delete_unconfirmed: bool,
|
||||
) -> Result<(), Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::check_repair(&mut **w, delete_unconfirmed)
|
||||
owner::check_repair(&mut **w, keychain_mask, delete_unconfirmed)
|
||||
}
|
||||
|
||||
/// Retrieves the last known height known by the wallet. This is determined as follows:
|
||||
|
@ -1061,7 +1192,8 @@ where
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * None
|
||||
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
|
||||
/// being used.
|
||||
///
|
||||
/// # Returns
|
||||
/// * Ok with a [`NodeHeightResult`](../grin_wallet_libwallet/types/struct.NodeHeightResult.html)
|
||||
|
@ -1075,7 +1207,7 @@ where
|
|||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||
///
|
||||
/// let api_owner = Owner::new(wallet.clone());
|
||||
/// let result = api_owner.node_height();
|
||||
/// let result = api_owner.node_height(None);
|
||||
///
|
||||
/// if let Ok(node_height_result) = result {
|
||||
/// if node_height_result.updated_from_node {
|
||||
|
@ -1086,10 +1218,15 @@ where
|
|||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn node_height(&self) -> Result<NodeHeightResult, Error> {
|
||||
pub fn node_height(
|
||||
&self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<NodeHeightResult, Error> {
|
||||
let mut w_lock = self.wallet_inst.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
owner::node_height(&mut **w)
|
||||
// Test keychain mask, to keep API consistent
|
||||
let _ = w.keychain(keychain_mask)?;
|
||||
owner::node_height(&mut **w, keychain_mask)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1139,7 +1276,7 @@ macro_rules! doctest_helper_setup_doc_env {
|
|||
>;
|
||||
let lc = wallet.lc_provider().unwrap();
|
||||
lc.set_wallet_directory(&wallet_config.data_file_dir);
|
||||
lc.open_wallet(None, pw);
|
||||
lc.open_wallet(None, pw, false, false);
|
||||
let mut $wallet = Arc::new(Mutex::new(wallet));
|
||||
};
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ use crate::libwallet::{
|
|||
WalletLCProvider,
|
||||
};
|
||||
use crate::util::Mutex;
|
||||
use crate::Owner;
|
||||
use crate::{Owner, OwnerRpcS};
|
||||
use easy_jsonrpc;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -63,7 +63,7 @@ pub trait OwnerRpc {
|
|||
"id": 1
|
||||
}
|
||||
# "#
|
||||
# , 4, false, false, false);
|
||||
# , false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn accounts(&self) -> Result<Vec<AcctPathMapping>, ErrorKind>;
|
||||
|
@ -93,7 +93,7 @@ pub trait OwnerRpc {
|
|||
"id": 1
|
||||
}
|
||||
# "#
|
||||
# ,4, false, false, false);
|
||||
# ,false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn create_account_path(&self, label: &String) -> Result<Identifier, ErrorKind>;
|
||||
|
@ -123,7 +123,7 @@ pub trait OwnerRpc {
|
|||
"id": 1
|
||||
}
|
||||
# "#
|
||||
# , 4, false, false, false);
|
||||
# , false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn set_active_account(&self, label: &String) -> Result<(), ErrorKind>;
|
||||
|
@ -189,7 +189,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 2, false, false, false);
|
||||
# , false, 2, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn retrieve_outputs(
|
||||
|
@ -260,7 +260,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 2, false, false, false);
|
||||
# , false, 2, false, false, false);
|
||||
```
|
||||
*/
|
||||
|
||||
|
@ -306,7 +306,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,4, false, false, false);
|
||||
# ,false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
|
||||
|
@ -400,7 +400,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,4, false, false, false);
|
||||
# ,false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
|
||||
|
@ -480,7 +480,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,4, false, false, false);
|
||||
# ,false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
|
||||
|
@ -628,7 +628,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,4, false, false, false);
|
||||
# ,false, 4, false, false, false);
|
||||
```
|
||||
*/
|
||||
|
||||
|
@ -712,7 +712,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,5 ,true, false, false);
|
||||
# ,false, 5 ,true, false, false);
|
||||
|
||||
```
|
||||
*/
|
||||
|
@ -879,7 +879,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, true, true, false);
|
||||
# , false, 5, true, true, false);
|
||||
```
|
||||
*/
|
||||
fn finalize_tx(&self, slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind>;
|
||||
|
@ -945,7 +945,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, true, true, true);
|
||||
# , false, 5, true, true, true);
|
||||
```
|
||||
*/
|
||||
|
||||
|
@ -975,7 +975,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, true, true, false);
|
||||
# , false, 5, true, true, false);
|
||||
```
|
||||
*/
|
||||
fn cancel_tx(&self, tx_id: Option<u32>, tx_slate_id: Option<Uuid>) -> Result<(), ErrorKind>;
|
||||
|
@ -1070,7 +1070,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, true, true, false);
|
||||
# , false, 5, true, true, false);
|
||||
```
|
||||
*/
|
||||
fn get_stored_tx(&self, tx: &TxLogEntry) -> Result<Option<Transaction>, ErrorKind>;
|
||||
|
@ -1148,7 +1148,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# ,5 ,true, false, false);
|
||||
# ,false, 5 ,true, false, false);
|
||||
```
|
||||
*/
|
||||
fn verify_slate_messages(&self, slate: VersionedSlate) -> Result<(), ErrorKind>;
|
||||
|
@ -1177,7 +1177,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 1, false, false, false);
|
||||
# , false, 1, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn restore(&self) -> Result<(), ErrorKind>;
|
||||
|
@ -1206,7 +1206,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 1, false, false, false);
|
||||
# , false, 1, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), ErrorKind>;
|
||||
|
@ -1238,7 +1238,7 @@ pub trait OwnerRpc {
|
|||
}
|
||||
}
|
||||
# "#
|
||||
# , 5, false, false, false);
|
||||
# , false, 5, false, false, false);
|
||||
```
|
||||
*/
|
||||
fn node_height(&self) -> Result<NodeHeightResult, ErrorKind>;
|
||||
|
@ -1251,15 +1251,15 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
fn accounts(&self) -> Result<Vec<AcctPathMapping>, ErrorKind> {
|
||||
Owner::accounts(self).map_err(|e| e.kind())
|
||||
Owner::accounts(self, None).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn create_account_path(&self, label: &String) -> Result<Identifier, ErrorKind> {
|
||||
Owner::create_account_path(self, label).map_err(|e| e.kind())
|
||||
Owner::create_account_path(self, None, label).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn set_active_account(&self, label: &String) -> Result<(), ErrorKind> {
|
||||
Owner::set_active_account(self, label).map_err(|e| e.kind())
|
||||
Owner::set_active_account(self, None, label).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn retrieve_outputs(
|
||||
|
@ -1268,7 +1268,8 @@ where
|
|||
refresh_from_node: bool,
|
||||
tx_id: Option<u32>,
|
||||
) -> Result<(bool, Vec<OutputCommitMapping>), ErrorKind> {
|
||||
Owner::retrieve_outputs(self, include_spent, refresh_from_node, tx_id).map_err(|e| e.kind())
|
||||
Owner::retrieve_outputs(self, None, include_spent, refresh_from_node, tx_id)
|
||||
.map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn retrieve_txs(
|
||||
|
@ -1277,7 +1278,7 @@ where
|
|||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
) -> Result<(bool, Vec<TxLogEntry>), ErrorKind> {
|
||||
Owner::retrieve_txs(self, refresh_from_node, tx_id, tx_slate_id).map_err(|e| e.kind())
|
||||
Owner::retrieve_txs(self, None, refresh_from_node, tx_id, tx_slate_id).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn retrieve_summary_info(
|
||||
|
@ -1285,18 +1286,18 @@ where
|
|||
refresh_from_node: bool,
|
||||
minimum_confirmations: u64,
|
||||
) -> Result<(bool, WalletInfo), ErrorKind> {
|
||||
Owner::retrieve_summary_info(self, refresh_from_node, minimum_confirmations)
|
||||
Owner::retrieve_summary_info(self, None, refresh_from_node, minimum_confirmations)
|
||||
.map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn init_send_tx(&self, args: InitTxArgs) -> Result<VersionedSlate, ErrorKind> {
|
||||
let slate = Owner::init_send_tx(self, args).map_err(|e| e.kind())?;
|
||||
let slate = Owner::init_send_tx(self, None, args).map_err(|e| e.kind())?;
|
||||
let version = SlateVersion::V2;
|
||||
Ok(VersionedSlate::into_version(slate, version))
|
||||
}
|
||||
|
||||
fn issue_invoice_tx(&self, args: IssueInvoiceTxArgs) -> Result<VersionedSlate, ErrorKind> {
|
||||
let slate = Owner::issue_invoice_tx(self, args).map_err(|e| e.kind())?;
|
||||
let slate = Owner::issue_invoice_tx(self, None, args).map_err(|e| e.kind())?;
|
||||
let version = SlateVersion::V2;
|
||||
Ok(VersionedSlate::into_version(slate, version))
|
||||
}
|
||||
|
@ -1307,14 +1308,15 @@ where
|
|||
args: InitTxArgs,
|
||||
) -> Result<VersionedSlate, ErrorKind> {
|
||||
let in_slate = Slate::from(slate);
|
||||
let out_slate = Owner::process_invoice_tx(self, &in_slate, args).map_err(|e| e.kind())?;
|
||||
let out_slate =
|
||||
Owner::process_invoice_tx(self, None, &in_slate, args).map_err(|e| e.kind())?;
|
||||
let version = SlateVersion::V2;
|
||||
Ok(VersionedSlate::into_version(out_slate, version))
|
||||
}
|
||||
|
||||
fn finalize_tx(&self, slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind> {
|
||||
let in_slate = Slate::from(slate);
|
||||
let out_slate = Owner::finalize_tx(self, &in_slate).map_err(|e| e.kind())?;
|
||||
let out_slate = Owner::finalize_tx(self, None, &in_slate).map_err(|e| e.kind())?;
|
||||
let version = SlateVersion::V2;
|
||||
Ok(VersionedSlate::into_version(out_slate, version))
|
||||
}
|
||||
|
@ -1325,36 +1327,36 @@ where
|
|||
participant_id: usize,
|
||||
) -> Result<(), ErrorKind> {
|
||||
let in_slate = Slate::from(slate);
|
||||
Owner::tx_lock_outputs(self, &in_slate, participant_id).map_err(|e| e.kind())
|
||||
Owner::tx_lock_outputs(self, None, &in_slate, participant_id).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn cancel_tx(&self, tx_id: Option<u32>, tx_slate_id: Option<Uuid>) -> Result<(), ErrorKind> {
|
||||
Owner::cancel_tx(self, tx_id, tx_slate_id).map_err(|e| e.kind())
|
||||
Owner::cancel_tx(self, None, tx_id, tx_slate_id).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn get_stored_tx(&self, tx: &TxLogEntry) -> Result<Option<Transaction>, ErrorKind> {
|
||||
Owner::get_stored_tx(self, tx).map_err(|e| e.kind())
|
||||
Owner::get_stored_tx(self, None, tx).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), ErrorKind> {
|
||||
Owner::post_tx(self, tx, fluff).map_err(|e| e.kind())
|
||||
Owner::post_tx(self, None, tx, fluff).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn verify_slate_messages(&self, slate: VersionedSlate) -> Result<(), ErrorKind> {
|
||||
let in_slate = Slate::from(slate);
|
||||
Owner::verify_slate_messages(self, &in_slate).map_err(|e| e.kind())
|
||||
Owner::verify_slate_messages(self, None, &in_slate).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn restore(&self) -> Result<(), ErrorKind> {
|
||||
Owner::restore(self).map_err(|e| e.kind())
|
||||
Owner::restore(self, None).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), ErrorKind> {
|
||||
Owner::check_repair(self, delete_unconfirmed).map_err(|e| e.kind())
|
||||
Owner::check_repair(self, None, delete_unconfirmed).map_err(|e| e.kind())
|
||||
}
|
||||
|
||||
fn node_height(&self) -> Result<NodeHeightResult, ErrorKind> {
|
||||
Owner::node_height(self).map_err(|e| e.kind())
|
||||
Owner::node_height(self, None).map_err(|e| e.kind())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1362,6 +1364,7 @@ where
|
|||
pub fn run_doctest_owner(
|
||||
request: serde_json::Value,
|
||||
test_dir: &str,
|
||||
use_token: bool,
|
||||
blocks_to_mine: u64,
|
||||
perform_tx: bool,
|
||||
lock_tx: bool,
|
||||
|
@ -1412,10 +1415,21 @@ pub fn run_doctest_owner(
|
|||
lc.set_wallet_directory(&format!("{}/wallet1", test_dir));
|
||||
lc.create_wallet(None, Some(rec_phrase_1), 32, empty_string.clone())
|
||||
.unwrap();
|
||||
lc.open_wallet(None, empty_string.clone()).unwrap();
|
||||
let mask1 = lc
|
||||
.open_wallet(None, empty_string.clone(), use_token, true)
|
||||
.unwrap();
|
||||
let wallet1 = Arc::new(Mutex::new(wallet1));
|
||||
|
||||
wallet_proxy.add_wallet("wallet1", client1.get_send_instance(), wallet1.clone());
|
||||
if mask1.is_some() {
|
||||
println!("WALLET 1 MASK: {:?}", mask1.clone().unwrap());
|
||||
}
|
||||
|
||||
wallet_proxy.add_wallet(
|
||||
"wallet1",
|
||||
client1.get_send_instance(),
|
||||
wallet1.clone(),
|
||||
mask1.clone(),
|
||||
);
|
||||
|
||||
let rec_phrase_2 = util::ZeroingString::from(
|
||||
"hour kingdom ripple lunch razor inquiry coyote clay stamp mean \
|
||||
|
@ -1436,10 +1450,21 @@ pub fn run_doctest_owner(
|
|||
lc.set_wallet_directory(&format!("{}/wallet2", test_dir));
|
||||
lc.create_wallet(None, Some(rec_phrase_2), 32, empty_string.clone())
|
||||
.unwrap();
|
||||
lc.open_wallet(None, empty_string.clone()).unwrap();
|
||||
let mask2 = lc
|
||||
.open_wallet(None, empty_string.clone(), use_token, true)
|
||||
.unwrap();
|
||||
let wallet2 = Arc::new(Mutex::new(wallet2));
|
||||
|
||||
wallet_proxy.add_wallet("wallet2", client2.get_send_instance(), wallet2.clone());
|
||||
if mask2.is_some() {
|
||||
println!("WALLET 2 MASK: {:?}", mask2.clone().unwrap());
|
||||
}
|
||||
|
||||
wallet_proxy.add_wallet(
|
||||
"wallet2",
|
||||
client2.get_send_instance(),
|
||||
wallet2.clone(),
|
||||
mask2.clone(),
|
||||
);
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -1450,12 +1475,18 @@ pub fn run_doctest_owner(
|
|||
|
||||
// Mine a few blocks to wallet 1 so there's something to send
|
||||
for _ in 0..blocks_to_mine {
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 1 as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
wallet1.clone(),
|
||||
(&mask1).as_ref(),
|
||||
1 as usize,
|
||||
false,
|
||||
);
|
||||
//update local outputs after each block, so transaction IDs stay consistent
|
||||
let mut w_lock = wallet1.lock();
|
||||
let w = w_lock.lc_provider().unwrap().wallet_inst().unwrap();
|
||||
let (wallet_refreshed, _) =
|
||||
api_impl::owner::retrieve_summary_info(&mut **w, true, 1).unwrap();
|
||||
api_impl::owner::retrieve_summary_info(&mut **w, (&mask1).as_ref(), true, 1).unwrap();
|
||||
assert!(wallet_refreshed);
|
||||
}
|
||||
|
||||
|
@ -1472,23 +1503,32 @@ pub fn run_doctest_owner(
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api_impl::owner::init_send_tx(&mut **w, args, true).unwrap();
|
||||
let mut slate =
|
||||
api_impl::owner::init_send_tx(&mut **w, (&mask1).as_ref(), args, true).unwrap();
|
||||
println!("INITIAL SLATE");
|
||||
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
|
||||
{
|
||||
let mut w_lock = wallet2.lock();
|
||||
let w2 = w_lock.lc_provider().unwrap().wallet_inst().unwrap();
|
||||
slate = api_impl::foreign::receive_tx(&mut **w2, &slate, None, None, true).unwrap();
|
||||
slate = api_impl::foreign::receive_tx(
|
||||
&mut **w2,
|
||||
(&mask2).as_ref(),
|
||||
&slate,
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
w2.close().unwrap();
|
||||
}
|
||||
// Spit out slate for input to finalize_tx
|
||||
if lock_tx {
|
||||
api_impl::owner::tx_lock_outputs(&mut **w, &slate, 0).unwrap();
|
||||
api_impl::owner::tx_lock_outputs(&mut **w, (&mask2).as_ref(), &slate, 0).unwrap();
|
||||
}
|
||||
println!("RECEIPIENT SLATE");
|
||||
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
|
||||
if finalize_tx {
|
||||
slate = api_impl::owner::finalize_tx(&mut **w, &slate).unwrap();
|
||||
slate = api_impl::owner::finalize_tx(&mut **w, (&mask2).as_ref(), &slate).unwrap();
|
||||
error!("FINALIZED TX SLATE");
|
||||
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
|
||||
}
|
||||
|
@ -1496,19 +1536,30 @@ pub fn run_doctest_owner(
|
|||
|
||||
if perform_tx && lock_tx && finalize_tx {
|
||||
// mine to move the chain on
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3 as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
wallet1.clone(),
|
||||
(&mask1).as_ref(),
|
||||
3 as usize,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
let mut api_owner = Owner::new(wallet1);
|
||||
api_owner.doctest_mode = true;
|
||||
let owner_api = &api_owner as &dyn OwnerRpc;
|
||||
Ok(owner_api.handle_request(request).as_option())
|
||||
if use_token {
|
||||
let owner_api = &api_owner as &dyn OwnerRpcS;
|
||||
Ok(owner_api.handle_request(request).as_option())
|
||||
} else {
|
||||
let owner_api = &api_owner as &dyn OwnerRpc;
|
||||
Ok(owner_api.handle_request(request).as_option())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! doctest_helper_json_rpc_owner_assert_response {
|
||||
($request:expr, $expected_response:expr, $blocks_to_mine:expr, $perform_tx:expr, $lock_tx:expr, $finalize_tx:expr) => {
|
||||
($request:expr, $expected_response:expr, $use_token:expr, $blocks_to_mine:expr, $perform_tx:expr, $lock_tx:expr, $finalize_tx:expr) => {
|
||||
// create temporary wallet, run jsonrpc request on owner api of wallet, delete wallet, return
|
||||
// json response.
|
||||
// In order to prevent leaking tempdirs, This function should not panic.
|
||||
|
@ -1530,6 +1581,7 @@ macro_rules! doctest_helper_json_rpc_owner_assert_response {
|
|||
let response = run_doctest_owner(
|
||||
request_val,
|
||||
dir,
|
||||
$use_token,
|
||||
$blocks_to_mine,
|
||||
$perform_tx,
|
||||
$lock_tx,
|
||||
|
|
1474
api/src/owner_rpc_s.rs
Normal file
1474
api/src/owner_rpc_s.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -52,7 +52,7 @@ fn _receive_versioned_slate() {
|
|||
let request_val: Value = serde_json::from_str(v1_req).unwrap();
|
||||
let expected_response: Value = serde_json::from_str(v1_resp).unwrap();
|
||||
|
||||
let response = run_doctest_foreign(request_val, dir, 5, true, false)
|
||||
let response = run_doctest_foreign(request_val, dir, false, 5, true, false)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::impls::{create_sender, KeybaseAllChannels, SlateGetter as _, SlateRec
|
|||
use crate::impls::{PathToSlate, SlatePutter};
|
||||
use crate::keychain;
|
||||
use crate::libwallet::{InitTxArgs, IssueInvoiceTxArgs, NodeClient, WalletInst, WalletLCProvider};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{Mutex, ZeroingString};
|
||||
use crate::{controller, display};
|
||||
use serde_json as json;
|
||||
|
@ -120,6 +121,7 @@ pub struct ListenArgs {
|
|||
|
||||
pub fn listen<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K>>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
config: &WalletConfig,
|
||||
args: &ListenArgs,
|
||||
g_args: &GlobalArgs,
|
||||
|
@ -132,6 +134,7 @@ where
|
|||
let res = match args.method.as_str() {
|
||||
"http" => controller::foreign_listener(
|
||||
wallet.clone(),
|
||||
keychain_mask,
|
||||
&config.api_listen_addr(),
|
||||
g_args.tls_conf.clone(),
|
||||
),
|
||||
|
@ -158,6 +161,7 @@ where
|
|||
|
||||
pub fn owner_api<L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K>>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
config: &WalletConfig,
|
||||
g_args: &GlobalArgs,
|
||||
) -> Result<(), Error>
|
||||
|
@ -168,6 +172,7 @@ where
|
|||
{
|
||||
let res = controller::owner_listener(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
config.owner_api_listen_addr().as_str(),
|
||||
g_args.node_api_secret.clone(),
|
||||
g_args.tls_conf.clone(),
|
||||
|
@ -186,6 +191,7 @@ pub struct AccountArgs {
|
|||
|
||||
pub fn account<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: AccountArgs,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -194,8 +200,8 @@ where
|
|||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
if args.create.is_none() {
|
||||
let res = controller::owner_single_use(wallet, |api| {
|
||||
let acct_mappings = api.accounts()?;
|
||||
let res = controller::owner_single_use(wallet, keychain_mask, |api, m| {
|
||||
let acct_mappings = api.accounts(m)?;
|
||||
// give logging thread a moment to catch up
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
display::accounts(acct_mappings);
|
||||
|
@ -207,8 +213,8 @@ where
|
|||
}
|
||||
} else {
|
||||
let label = args.create.unwrap();
|
||||
let res = controller::owner_single_use(wallet, |api| {
|
||||
api.create_account_path(&label)?;
|
||||
let res = controller::owner_single_use(wallet, keychain_mask, |api, m| {
|
||||
api.create_account_path(m, &label)?;
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
info!("Account: '{}' Created!", label);
|
||||
Ok(())
|
||||
|
@ -239,6 +245,7 @@ pub struct SendArgs {
|
|||
|
||||
pub fn send<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: SendArgs,
|
||||
dark_scheme: bool,
|
||||
) -> Result<(), Error>
|
||||
|
@ -247,7 +254,7 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
if args.estimate_selection_strategies {
|
||||
let strategies = vec!["smallest", "all"]
|
||||
.into_iter()
|
||||
|
@ -262,7 +269,7 @@ where
|
|||
estimate_only: Some(true),
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(init_args).unwrap();
|
||||
let slate = api.init_send_tx(m, init_args).unwrap();
|
||||
(strategy, slate.amount, slate.fee)
|
||||
})
|
||||
.collect();
|
||||
|
@ -280,7 +287,7 @@ where
|
|||
send_args: None,
|
||||
..Default::default()
|
||||
};
|
||||
let result = api.init_send_tx(init_args);
|
||||
let result = api.init_send_tx(m, init_args);
|
||||
let mut slate = match result {
|
||||
Ok(s) => {
|
||||
info!(
|
||||
|
@ -300,12 +307,16 @@ where
|
|||
match args.method.as_str() {
|
||||
"file" => {
|
||||
PathToSlate((&args.dest).into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
return Ok(());
|
||||
}
|
||||
"self" => {
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
controller::foreign_single_use(wallet, |api| {
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(wallet, km, |api| {
|
||||
slate = api.receive_tx(&slate, Some(&args.dest), None)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -313,16 +324,16 @@ where
|
|||
method => {
|
||||
let sender = create_sender(method, &args.dest)?;
|
||||
slate = sender.send_tx(&slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
}
|
||||
}
|
||||
|
||||
api.verify_slate_messages(&slate).map_err(|e| {
|
||||
api.verify_slate_messages(m, &slate).map_err(|e| {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
e
|
||||
})?;
|
||||
slate = api.finalize_tx(&slate)?;
|
||||
let result = api.post_tx(&slate.tx, args.fluff);
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
let result = api.post_tx(m, &slate.tx, args.fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Tx sent ok",);
|
||||
|
@ -347,6 +358,7 @@ pub struct ReceiveArgs {
|
|||
|
||||
pub fn receive<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
g_args: &GlobalArgs,
|
||||
args: ReceiveArgs,
|
||||
) -> Result<(), Error>
|
||||
|
@ -356,7 +368,11 @@ where
|
|||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
let mut slate = PathToSlate((&args.input).into()).get_tx()?;
|
||||
controller::foreign_single_use(wallet, |api| {
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(wallet, km, |api| {
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
|
@ -380,6 +396,7 @@ pub struct FinalizeArgs {
|
|||
|
||||
pub fn finalize<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: FinalizeArgs,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -408,7 +425,11 @@ where
|
|||
};
|
||||
|
||||
if is_invoice {
|
||||
controller::foreign_single_use(wallet.clone(), |api| {
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(wallet.clone(), km, |api| {
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
|
@ -417,18 +438,18 @@ where
|
|||
Ok(())
|
||||
})?;
|
||||
} else {
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
if let Err(e) = api.verify_slate_messages(m, &slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
slate = api.finalize_tx(&mut slate)?;
|
||||
slate = api.finalize_tx(m, &mut slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let result = api.post_tx(&slate.tx, args.fluff);
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let result = api.post_tx(m, &slate.tx, args.fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Transaction sent successfully, check the wallet again for confirmation.");
|
||||
|
@ -454,6 +475,7 @@ pub struct IssueInvoiceArgs {
|
|||
|
||||
pub fn issue_invoice_tx<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: IssueInvoiceArgs,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -461,8 +483,8 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let slate = api.issue_invoice_tx(args.issue_args)?;
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let slate = api.issue_invoice_tx(m, args.issue_args)?;
|
||||
let mut tx_file = File::create(args.dest.clone())?;
|
||||
tx_file.write_all(json::to_string(&slate).unwrap().as_bytes())?;
|
||||
tx_file.sync_all()?;
|
||||
|
@ -486,6 +508,7 @@ pub struct ProcessInvoiceArgs {
|
|||
/// Process invoice
|
||||
pub fn process_invoice<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: ProcessInvoiceArgs,
|
||||
dark_scheme: bool,
|
||||
) -> Result<(), Error>
|
||||
|
@ -495,7 +518,7 @@ where
|
|||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
let slate = PathToSlate((&args.input).into()).get_tx()?;
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
if args.estimate_selection_strategies {
|
||||
let strategies = vec!["smallest", "all"]
|
||||
.into_iter()
|
||||
|
@ -510,7 +533,7 @@ where
|
|||
estimate_only: Some(true),
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(init_args).unwrap();
|
||||
let slate = api.init_send_tx(m, init_args).unwrap();
|
||||
(strategy, slate.amount, slate.fee)
|
||||
})
|
||||
.collect();
|
||||
|
@ -527,11 +550,11 @@ where
|
|||
send_args: None,
|
||||
..Default::default()
|
||||
};
|
||||
if let Err(e) = api.verify_slate_messages(&slate) {
|
||||
if let Err(e) = api.verify_slate_messages(m, &slate) {
|
||||
error!("Error validating participant messages: {}", e);
|
||||
return Err(e);
|
||||
}
|
||||
let result = api.process_invoice_tx(&slate, init_args);
|
||||
let result = api.process_invoice_tx(m, &slate, init_args);
|
||||
let mut slate = match result {
|
||||
Ok(s) => {
|
||||
info!(
|
||||
|
@ -552,11 +575,15 @@ where
|
|||
"file" => {
|
||||
let slate_putter = PathToSlate((&args.dest).into());
|
||||
slate_putter.put_tx(&slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
}
|
||||
"self" => {
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
controller::foreign_single_use(wallet, |api| {
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
let km = match keychain_mask.as_ref() {
|
||||
None => None,
|
||||
Some(&m) => Some(m.to_owned()),
|
||||
};
|
||||
controller::foreign_single_use(wallet, km, |api| {
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -564,7 +591,7 @@ where
|
|||
method => {
|
||||
let sender = create_sender(method, &args.dest)?;
|
||||
slate = sender.send_tx(&slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -579,6 +606,7 @@ pub struct InfoArgs {
|
|||
|
||||
pub fn info<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
g_args: &GlobalArgs,
|
||||
args: InfoArgs,
|
||||
dark_scheme: bool,
|
||||
|
@ -588,9 +616,9 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let (validated, wallet_info) =
|
||||
api.retrieve_summary_info(true, args.minimum_confirmations)?;
|
||||
api.retrieve_summary_info(m, true, args.minimum_confirmations)?;
|
||||
display::info(&g_args.account, &wallet_info, validated, dark_scheme);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -599,6 +627,7 @@ where
|
|||
|
||||
pub fn outputs<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
g_args: &GlobalArgs,
|
||||
dark_scheme: bool,
|
||||
) -> Result<(), Error>
|
||||
|
@ -607,9 +636,9 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let res = api.node_height()?;
|
||||
let (validated, outputs) = api.retrieve_outputs(g_args.show_spent, true, None)?;
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let res = api.node_height(m)?;
|
||||
let (validated, outputs) = api.retrieve_outputs(m, g_args.show_spent, true, None)?;
|
||||
display::outputs(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -624,6 +653,7 @@ pub struct TxsArgs {
|
|||
|
||||
pub fn txs<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
g_args: &GlobalArgs,
|
||||
args: TxsArgs,
|
||||
dark_scheme: bool,
|
||||
|
@ -633,9 +663,9 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let res = api.node_height()?;
|
||||
let (validated, txs) = api.retrieve_txs(true, args.id, args.tx_slate_id)?;
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let res = api.node_height(m)?;
|
||||
let (validated, txs) = api.retrieve_txs(m, true, args.id, args.tx_slate_id)?;
|
||||
let include_status = !args.id.is_some() && !args.tx_slate_id.is_some();
|
||||
display::txs(
|
||||
&g_args.account,
|
||||
|
@ -662,7 +692,7 @@ where
|
|||
};
|
||||
|
||||
if id.is_some() {
|
||||
let (_, outputs) = api.retrieve_outputs(true, false, id)?;
|
||||
let (_, outputs) = api.retrieve_outputs(m, true, false, id)?;
|
||||
display::outputs(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
||||
// should only be one here, but just in case
|
||||
for tx in txs {
|
||||
|
@ -684,6 +714,7 @@ pub struct RepostArgs {
|
|||
|
||||
pub fn repost<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: RepostArgs,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -691,9 +722,9 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let (_, txs) = api.retrieve_txs(true, Some(args.id), None)?;
|
||||
let stored_tx = api.get_stored_tx(&txs[0])?;
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, Some(args.id), None)?;
|
||||
let stored_tx = api.get_stored_tx(m, &txs[0])?;
|
||||
if stored_tx.is_none() {
|
||||
error!(
|
||||
"Transaction with id {} does not have transaction data. Not reposting.",
|
||||
|
@ -710,7 +741,7 @@ where
|
|||
);
|
||||
return Ok(());
|
||||
}
|
||||
api.post_tx(&stored_tx.unwrap(), args.fluff)?;
|
||||
api.post_tx(m, &stored_tx.unwrap(), args.fluff)?;
|
||||
info!("Reposted transaction at {}", args.id);
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -735,6 +766,7 @@ pub struct CancelArgs {
|
|||
|
||||
pub fn cancel<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: CancelArgs,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -742,8 +774,8 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let result = api.cancel_tx(args.tx_id, args.tx_slate_id);
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let result = api.cancel_tx(m, args.tx_id, args.tx_slate_id);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Transaction {} Cancelled", args.tx_id_string);
|
||||
|
@ -760,14 +792,15 @@ where
|
|||
|
||||
pub fn restore<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
L: WalletLCProvider<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
let result = api.restore();
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
let result = api.restore(m);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
warn!("Wallet restore complete",);
|
||||
|
@ -790,6 +823,7 @@ pub struct CheckArgs {
|
|||
|
||||
pub fn check_repair<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: CheckArgs,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -797,10 +831,10 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
controller::owner_single_use(wallet.clone(), |api| {
|
||||
controller::owner_single_use(wallet.clone(), keychain_mask, |api, m| {
|
||||
warn!("Starting wallet check...",);
|
||||
warn!("Updating all wallet outputs, please wait ...",);
|
||||
let result = api.check_repair(args.delete_unconfirmed);
|
||||
let result = api.check_repair(m, args.delete_unconfirmed);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
warn!("Wallet check complete",);
|
||||
|
|
|
@ -20,6 +20,7 @@ use crate::libwallet::{
|
|||
Error, ErrorKind, NodeClient, NodeVersionInfo, Slate, WalletInst, WalletLCProvider,
|
||||
CURRENT_SLATE_VERSION, GRIN_BLOCK_HEADER_VERSION,
|
||||
};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{to_base64, Mutex};
|
||||
use failure::ResultExt;
|
||||
use futures::future::{err, ok};
|
||||
|
@ -73,23 +74,25 @@ fn check_middleware(
|
|||
/// Instantiate wallet Owner API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn owner_single_use<'a, L, F, C, K>(
|
||||
lc_provider: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
f: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
L: WalletLCProvider<'a, C, K>,
|
||||
F: FnOnce(&mut Owner<'a, L, C, K>) -> Result<(), Error>,
|
||||
F: FnOnce(&mut Owner<'a, L, C, K>, Option<&SecretKey>) -> Result<(), Error>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
f(&mut Owner::new(lc_provider))?;
|
||||
f(&mut Owner::new(wallet), keychain_mask)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Instantiate wallet Foreign API for a single-use (command line) call
|
||||
/// Return a function containing a loaded API context to call
|
||||
pub fn foreign_single_use<'a, L, F, C, K>(
|
||||
lc_provider: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
f: F,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
|
@ -98,14 +101,21 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
f(&mut Foreign::new(lc_provider, Some(check_middleware)))?;
|
||||
f(&mut Foreign::new(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
Some(check_middleware),
|
||||
))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Listener version, providing same API but listening for requests on a
|
||||
/// port and wrapping the calls
|
||||
/// Note keychain mask is only provided here in case the foreign listener is also being used
|
||||
/// in the same wallet instance
|
||||
pub fn owner_listener<L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
addr: &str,
|
||||
api_secret: Option<String>,
|
||||
tls_config: Option<TLSConfig>,
|
||||
|
@ -136,7 +146,7 @@ where
|
|||
// If so configured, add the foreign API to the same port
|
||||
if owner_api_include_foreign.unwrap_or(false) {
|
||||
warn!("Starting HTTP Foreign API on Owner server at {}.", addr);
|
||||
let foreign_api_handler_v2 = ForeignAPIHandlerV2::new(wallet);
|
||||
let foreign_api_handler_v2 = ForeignAPIHandlerV2::new(wallet, keychain_mask);
|
||||
router
|
||||
.add_route("/v2/foreign", Arc::new(foreign_api_handler_v2))
|
||||
.map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?;
|
||||
|
@ -160,6 +170,7 @@ where
|
|||
/// port and wrapping the calls
|
||||
pub fn foreign_listener<L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
addr: &str,
|
||||
tls_config: Option<TLSConfig>,
|
||||
) -> Result<(), Error>
|
||||
|
@ -168,7 +179,7 @@ where
|
|||
C: NodeClient + 'static,
|
||||
K: Keychain + 'static,
|
||||
{
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(wallet);
|
||||
let api_handler_v2 = ForeignAPIHandlerV2::new(wallet, keychain_mask);
|
||||
|
||||
let mut router = Router::new();
|
||||
|
||||
|
@ -275,6 +286,8 @@ where
|
|||
{
|
||||
/// Wallet instance
|
||||
pub wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
/// Keychain mask
|
||||
pub keychain_mask: Option<SecretKey>,
|
||||
}
|
||||
|
||||
impl<L, C, K> ForeignAPIHandlerV2<L, C, K>
|
||||
|
@ -286,8 +299,12 @@ where
|
|||
/// Create a new foreign API handler for GET methods
|
||||
pub fn new(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
) -> ForeignAPIHandlerV2<L, C, K> {
|
||||
ForeignAPIHandlerV2 { wallet }
|
||||
ForeignAPIHandlerV2 {
|
||||
wallet,
|
||||
keychain_mask,
|
||||
}
|
||||
}
|
||||
|
||||
fn call_api(
|
||||
|
@ -309,7 +326,11 @@ where
|
|||
}
|
||||
|
||||
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
|
||||
let api = Foreign::new(self.wallet.clone(), Some(check_middleware));
|
||||
let api = Foreign::new(
|
||||
self.wallet.clone(),
|
||||
self.keychain_mask.clone(),
|
||||
Some(check_middleware),
|
||||
);
|
||||
Box::new(
|
||||
self.call_api(req, api)
|
||||
.and_then(|resp| ok(json_response_pretty(&resp))),
|
||||
|
|
|
@ -43,20 +43,29 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&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
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
if let Err(e) = wallet_proxy.run() {
|
||||
|
@ -69,30 +78,30 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height
|
||||
|
||||
// test default accounts exist
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let accounts = api.accounts()?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let accounts = api.accounts(m)?;
|
||||
assert_eq!(accounts[0].label, "default");
|
||||
assert_eq!(accounts[0].path, ExtKeychain::derive_key_id(2, 0, 0, 0, 0));
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let new_path = api.create_account_path("account1").unwrap();
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let new_path = api.create_account_path(m, "account1").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0));
|
||||
let new_path = api.create_account_path("account2").unwrap();
|
||||
let new_path = api.create_account_path(m, "account2").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 2, 0, 0, 0));
|
||||
let new_path = api.create_account_path("account3").unwrap();
|
||||
let new_path = api.create_account_path(m, "account3").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 3, 0, 0, 0));
|
||||
// trying to add same label again should fail
|
||||
let res = api.create_account_path("account1");
|
||||
let res = api.create_account_path(m, "account1");
|
||||
assert!(res.is_err());
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add account to wallet 2
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let new_path = api.create_account_path("listener_account").unwrap();
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let new_path = api.create_account_path(m, "listener_account").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0));
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -109,24 +118,24 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::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(), 7, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 7, false);
|
||||
|
||||
{
|
||||
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(), 5, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
|
||||
|
||||
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 12);
|
||||
assert_eq!(wallet1_info.total, 5 * reward);
|
||||
assert_eq!(wallet1_info.amount_currently_spendable, (5 - cm) * reward);
|
||||
// check tx log as well
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert_eq!(txs.len(), 5);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -137,17 +146,17 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
let w = lc.wallet_inst()?;
|
||||
w.set_parent_key_id_by_name("account1")?;
|
||||
}
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
// check last confirmed height on this account is different from above (should be 0)
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(false, 1)?;
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?;
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 0);
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 12);
|
||||
assert_eq!(wallet1_info.total, 7 * reward);
|
||||
assert_eq!(wallet1_info.amount_currently_spendable, 7 * reward);
|
||||
// check tx log as well
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert_eq!(txs.len(), 7);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -157,16 +166,16 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
wallet_inst!(wallet1, w);
|
||||
w.set_parent_key_id_by_name("default")?;
|
||||
}
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(false, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?;
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 0);
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 12);
|
||||
assert_eq!(wallet1_info.total, 0,);
|
||||
assert_eq!(wallet1_info.amount_currently_spendable, 0,);
|
||||
// check tx log as well
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert_eq!(txs.len(), 0);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -177,7 +186,7 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
w.set_parent_key_id_by_name("account1")?;
|
||||
}
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: reward,
|
||||
|
@ -187,19 +196,19 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api.init_send_tx(args)?;
|
||||
let mut slate = api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = api.finalize_tx(&slate)?;
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 13);
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert_eq!(txs.len(), 9);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -209,23 +218,23 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
wallet_inst!(wallet1, w);
|
||||
w.set_parent_key_id_by_name("account2")?;
|
||||
}
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(false, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, false, 1)?;
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 12);
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert_eq!(wallet1_info.last_confirmed_height, 13);
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
println!("{:?}", txs);
|
||||
assert_eq!(txs.len(), 5);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 2 should only have this tx on the listener account
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, 13);
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert_eq!(txs.len(), 1);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -234,16 +243,16 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
wallet_inst!(wallet2, w);
|
||||
w.set_parent_key_id_by_name("default")?;
|
||||
}
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (_, wallet2_info) = api.retrieve_summary_info(false, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (_, wallet2_info) = api.retrieve_summary_info(m, false, 1)?;
|
||||
assert_eq!(wallet2_info.last_confirmed_height, 0);
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, 13);
|
||||
assert_eq!(wallet2_info.total, 0,);
|
||||
assert_eq!(wallet2_info.amount_currently_spendable, 0,);
|
||||
// check tx log as well
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert_eq!(txs.len(), 0);
|
||||
Ok(())
|
||||
})?;
|
||||
|
|
|
@ -35,14 +35,14 @@ mod common;
|
|||
use common::{create_wallet_proxy, setup};
|
||||
|
||||
macro_rules! send_to_dest {
|
||||
($a:expr, $b:expr, $c:expr, $d:expr) => {
|
||||
test_framework::send_to_dest($a, $b, $c, $d, false)
|
||||
($a:expr, $m: expr, $b:expr, $c:expr, $d:expr) => {
|
||||
test_framework::send_to_dest($a, $m, $b, $c, $d, false)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! wallet_info {
|
||||
($a:expr) => {
|
||||
test_framework::wallet_info($a)
|
||||
($a:expr, $m:expr) => {
|
||||
test_framework::wallet_info($a, $m)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -59,19 +59,25 @@ fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&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
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -85,34 +91,35 @@ fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
let cm = global::coinbase_maturity() as u64; // assume all testing precedes soft fork height
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.create_account_path("account_1")?;
|
||||
api.create_account_path("account_2")?;
|
||||
api.create_account_path("account_3")?;
|
||||
api.set_active_account("account_1")?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.create_account_path(m, "account_1")?;
|
||||
api.create_account_path(m, "account_2")?;
|
||||
api.create_account_path(m, "account_3")?;
|
||||
api.set_active_account(m, "account_1")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add account to wallet 2
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.create_account_path("account_1")?;
|
||||
api.set_active_account("account_1")?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
api.create_account_path(m, "account_1")?;
|
||||
api.set_active_account(m, "account_1")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Do some mining
|
||||
let bh = 20u64;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize, false);
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
// Sanity check contents
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
assert_eq!(wallet1_info.amount_currently_spendable, (bh - cm) * reward);
|
||||
// check tx log as well
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs);
|
||||
assert_eq!(wallet1_info.total, c);
|
||||
assert_eq!(txs.len(), bh as usize);
|
||||
|
@ -121,8 +128,8 @@ fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
|
||||
// Accidentally delete some outputs
|
||||
let mut w1_outputs_commits = vec![];
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
w1_outputs_commits = api.retrieve_outputs(false, true, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
w1_outputs_commits = api.retrieve_outputs(m, false, true, None)?.1;
|
||||
Ok(())
|
||||
})?;
|
||||
let w1_outputs: Vec<libwallet::OutputData> =
|
||||
|
@ -130,7 +137,7 @@ fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
{
|
||||
wallet_inst!(wallet1, w);
|
||||
{
|
||||
let mut batch = w.batch()?;
|
||||
let mut batch = w.batch(mask1)?;
|
||||
batch.delete(&w1_outputs[4].key_id, &None)?;
|
||||
batch.delete(&w1_outputs[10].key_id, &None)?;
|
||||
let mut accidental_spent = w1_outputs[13].clone();
|
||||
|
@ -141,30 +148,30 @@ fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
}
|
||||
|
||||
// check we have a problem now
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
let (c, _) = libwallet::TxLogEntry::sum_confirmed(&txs);
|
||||
assert!(wallet1_info.total != c);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// this should restore our missing outputs
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.check_repair(true)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.check_repair(m, true)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// check our outputs match again
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// perform a transaction, but don't let it finish
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
// send to send
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -175,30 +182,30 @@ fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(args)?;
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
// output tx file
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
PathToSlate(send_file.into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// check we're all locked
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_info.amount_currently_spendable == 0);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// unlock/restore
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.check_repair(true)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.check_repair(m, true)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// check spendable amount again
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert_eq!(wallet1_info.amount_currently_spendable, (bh - cm) * reward);
|
||||
Ok(())
|
||||
})?;
|
||||
|
@ -221,94 +228,134 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
|
||||
// Create a new wallet test client, and set its queues to communicate with the
|
||||
// proxy
|
||||
create_wallet_and_add!(m_client, miner, test_dir, "miner", None, &mut wallet_proxy);
|
||||
create_wallet_and_add!(
|
||||
m_client,
|
||||
miner,
|
||||
miner_mask_i,
|
||||
test_dir,
|
||||
"miner",
|
||||
None,
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let miner_mask = (&miner_mask_i).as_ref();
|
||||
|
||||
// non-mining recipient wallets
|
||||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client2,
|
||||
wallet2,
|
||||
mask2_i,
|
||||
test_dir,
|
||||
"wallet2",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
// we'll restore into here
|
||||
create_wallet_and_add!(
|
||||
client3,
|
||||
wallet3,
|
||||
mask3_i,
|
||||
test_dir,
|
||||
"wallet3",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask3 = (&mask3_i).as_ref();
|
||||
// also restore into here
|
||||
create_wallet_and_add!(
|
||||
client4,
|
||||
wallet4,
|
||||
mask4_i,
|
||||
test_dir,
|
||||
"wallet4",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask4 = (&mask4_i).as_ref();
|
||||
// Simulate a recover from seed without restore into here
|
||||
create_wallet_and_add!(
|
||||
client5,
|
||||
wallet5,
|
||||
mask5_i,
|
||||
test_dir,
|
||||
"wallet5",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
//simulate a recover from seed without restore into here
|
||||
let mask5 = (&mask5_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client6,
|
||||
wallet6,
|
||||
mask6_i,
|
||||
test_dir,
|
||||
"wallet6",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask6 = (&mask6_i).as_ref();
|
||||
|
||||
create_wallet_and_add!(
|
||||
client7,
|
||||
wallet7,
|
||||
mask7_i,
|
||||
test_dir,
|
||||
"wallet7",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask7 = (&mask7_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client8,
|
||||
wallet8,
|
||||
mask8_i,
|
||||
test_dir,
|
||||
"wallet8",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask8 = (&mask8_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client9,
|
||||
wallet9,
|
||||
mask9_i,
|
||||
test_dir,
|
||||
"wallet9",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask9 = (&mask9_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client10,
|
||||
wallet10,
|
||||
mask10_i,
|
||||
test_dir,
|
||||
"wallet10",
|
||||
seed_phrase,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask10 = (&mask10_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -324,38 +371,80 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
// Do some mining
|
||||
let mut bh = 20u64;
|
||||
let base_amount = consensus::GRIN_BASE;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), bh as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
bh as usize,
|
||||
false,
|
||||
);
|
||||
|
||||
// send some funds to wallets 1
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet1", base_amount * 1)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet1", base_amount * 2)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet1", base_amount * 3)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet1",
|
||||
base_amount * 1
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet1",
|
||||
base_amount * 2
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet1",
|
||||
base_amount * 3
|
||||
)?;
|
||||
bh += 3;
|
||||
|
||||
// 0) Check repair when all is okay should leave wallet contents alone
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.check_repair(true)?;
|
||||
let info = wallet_info!(wallet1.clone())?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.check_repair(m, true)?;
|
||||
let info = wallet_info!(wallet1.clone(), m)?;
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 6);
|
||||
assert_eq!(info.total, base_amount * 6);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// send some funds to wallet 2
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet2", base_amount * 4)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet2", base_amount * 5)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet2", base_amount * 6)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet2",
|
||||
base_amount * 4
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet2",
|
||||
base_amount * 5
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet2",
|
||||
base_amount * 6
|
||||
)?;
|
||||
bh += 3;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), cm, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false);
|
||||
bh += cm as u64;
|
||||
|
||||
// confirm balances
|
||||
let info = wallet_info!(wallet1.clone())?;
|
||||
let info = wallet_info!(wallet1.clone(), mask1)?;
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 6);
|
||||
assert_eq!(info.total, base_amount * 6);
|
||||
|
||||
let info = wallet_info!(wallet2.clone())?;
|
||||
let info = wallet_info!(wallet2.clone(), mask2)?;
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 15);
|
||||
assert_eq!(info.total, base_amount * 15);
|
||||
|
||||
|
@ -363,14 +452,14 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
// seed + BIP32 path.
|
||||
|
||||
// 1) a full restore should recover all of them:
|
||||
wallet::controller::owner_single_use(wallet3.clone(), |api| {
|
||||
api.restore()?;
|
||||
wallet::controller::owner_single_use(wallet3.clone(), mask3, |api, m| {
|
||||
api.restore(m)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet3.clone(), |api| {
|
||||
let info = wallet_info!(wallet3.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet3.clone(), mask3, |api, m| {
|
||||
let info = wallet_info!(wallet3.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 6);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 21);
|
||||
assert_eq!(info.total, base_amount * 21);
|
||||
|
@ -378,14 +467,14 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
})?;
|
||||
|
||||
// 2) check_repair should recover them into a single wallet
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.check_repair(true)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.check_repair(m, true)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let info = wallet_info!(wallet1.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let info = wallet_info!(wallet1.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 6);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 21);
|
||||
Ok(())
|
||||
|
@ -393,30 +482,48 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
|
||||
// 3) If I recover from seed and start using the wallet without restoring,
|
||||
// check_repair should restore the older outputs
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet4", base_amount * 7)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet4", base_amount * 8)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet4", base_amount * 9)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet4",
|
||||
base_amount * 7
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet4",
|
||||
base_amount * 8
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet4",
|
||||
base_amount * 9
|
||||
)?;
|
||||
bh += 3;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), cm, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false);
|
||||
bh += cm as u64;
|
||||
|
||||
wallet::controller::owner_single_use(wallet4.clone(), |api| {
|
||||
let info = wallet_info!(wallet4.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet4.clone(), mask4, |api, m| {
|
||||
let info = wallet_info!(wallet4.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 3);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 24);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet5.clone(), |api| {
|
||||
api.restore()?;
|
||||
wallet::controller::owner_single_use(wallet5.clone(), mask5, |api, m| {
|
||||
api.restore(m)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet5.clone(), |api| {
|
||||
let info = wallet_info!(wallet5.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet5.clone(), mask5, |api, m| {
|
||||
let info = wallet_info!(wallet5.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 9);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * (45));
|
||||
Ok(())
|
||||
|
@ -424,30 +531,54 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
|
||||
// 4) If I recover from seed and start using the wallet without restoring,
|
||||
// check_repair should restore the older outputs
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet6", base_amount * 10)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet6", base_amount * 11)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet6", base_amount * 12)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet6",
|
||||
base_amount * 10
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet6",
|
||||
base_amount * 11
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet6",
|
||||
base_amount * 12
|
||||
)?;
|
||||
bh += 3;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), cm as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
cm as usize,
|
||||
false,
|
||||
);
|
||||
bh += cm as u64;
|
||||
|
||||
wallet::controller::owner_single_use(wallet6.clone(), |api| {
|
||||
let info = wallet_info!(wallet6.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet6.clone(), mask6, |api, m| {
|
||||
let info = wallet_info!(wallet6.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 3);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 33);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet6.clone(), |api| {
|
||||
api.check_repair(true)?;
|
||||
wallet::controller::owner_single_use(wallet6.clone(), mask6, |api, m| {
|
||||
api.check_repair(m, true)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet6.clone(), |api| {
|
||||
let info = wallet_info!(wallet6.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet6.clone(), mask6, |api, m| {
|
||||
let info = wallet_info!(wallet6.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 12);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * (78));
|
||||
Ok(())
|
||||
|
@ -456,49 +587,85 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
// 5) Start using same seed with a different account, amounts should
|
||||
// be distinct and restore should return funds from other account
|
||||
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet7", base_amount * 13)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet7", base_amount * 14)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet7", base_amount * 15)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet7",
|
||||
base_amount * 13
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet7",
|
||||
base_amount * 14
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet7",
|
||||
base_amount * 15
|
||||
)?;
|
||||
bh += 3;
|
||||
|
||||
// mix it up a bit
|
||||
wallet::controller::owner_single_use(wallet7.clone(), |api| {
|
||||
api.create_account_path("account_1")?;
|
||||
api.set_active_account("account_1")?;
|
||||
wallet::controller::owner_single_use(wallet7.clone(), mask7, |api, m| {
|
||||
api.create_account_path(m, "account_1")?;
|
||||
api.set_active_account(m, "account_1")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet7", base_amount * 1)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet7", base_amount * 2)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet7", base_amount * 3)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet7",
|
||||
base_amount * 1
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet7",
|
||||
base_amount * 2
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet7",
|
||||
base_amount * 3
|
||||
)?;
|
||||
bh += 3;
|
||||
|
||||
// check balances
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), cm, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false);
|
||||
bh += cm as u64;
|
||||
|
||||
wallet::controller::owner_single_use(wallet7.clone(), |api| {
|
||||
let info = wallet_info!(wallet7.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet7.clone(), mask7, |api, m| {
|
||||
let info = wallet_info!(wallet7.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 3);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 6);
|
||||
api.set_active_account("default")?;
|
||||
let info = wallet_info!(wallet7.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
api.set_active_account(m, "default")?;
|
||||
let info = wallet_info!(wallet7.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 3);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 42);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet8.clone(), |api| {
|
||||
api.restore()?;
|
||||
let info = wallet_info!(wallet8.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet8.clone(), mask8, |api, m| {
|
||||
api.restore(m)?;
|
||||
let info = wallet_info!(wallet8.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 15);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 120);
|
||||
api.set_active_account("account_1")?;
|
||||
let info = wallet_info!(wallet8.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
api.set_active_account(m, "account_1")?;
|
||||
let info = wallet_info!(wallet8.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 3);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 6);
|
||||
Ok(())
|
||||
|
@ -508,51 +675,69 @@ fn two_wallets_one_seed_impl(test_dir: &'static str) -> Result<(), libwallet::Er
|
|||
// ids on account 2 as well, check_repair should get all outputs created
|
||||
// to now into 2 accounts
|
||||
|
||||
wallet::controller::owner_single_use(wallet9.clone(), |api| {
|
||||
api.create_account_path("account_1")?;
|
||||
api.set_active_account("account_1")?;
|
||||
wallet::controller::owner_single_use(wallet9.clone(), mask9, |api, m| {
|
||||
api.create_account_path(m, "account_1")?;
|
||||
api.set_active_account(m, "account_1")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet9", base_amount * 4)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet9", base_amount * 5)?;
|
||||
send_to_dest!(miner.clone(), m_client.clone(), "wallet9", base_amount * 6)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet9",
|
||||
base_amount * 4
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet9",
|
||||
base_amount * 5
|
||||
)?;
|
||||
send_to_dest!(
|
||||
miner.clone(),
|
||||
miner_mask,
|
||||
m_client.clone(),
|
||||
"wallet9",
|
||||
base_amount * 6
|
||||
)?;
|
||||
bh += 3;
|
||||
let _bh = bh;
|
||||
|
||||
wallet::controller::owner_single_use(wallet9.clone(), |api| {
|
||||
let info = wallet_info!(wallet9.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet9.clone(), mask9, |api, m| {
|
||||
let info = wallet_info!(wallet9.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 3);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 15);
|
||||
api.check_repair(true)?;
|
||||
let info = wallet_info!(wallet9.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
api.check_repair(m, true)?;
|
||||
let info = wallet_info!(wallet9.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 6);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 21);
|
||||
|
||||
api.set_active_account("default")?;
|
||||
let info = wallet_info!(wallet9.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
api.set_active_account(m, "default")?;
|
||||
let info = wallet_info!(wallet9.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 15);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 120);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), cm, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, miner.clone(), miner_mask, cm, false);
|
||||
|
||||
// 7) Ensure check_repair creates missing accounts
|
||||
wallet::controller::owner_single_use(wallet10.clone(), |api| {
|
||||
api.check_repair(true)?;
|
||||
api.set_active_account("account_1")?;
|
||||
let info = wallet_info!(wallet10.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
wallet::controller::owner_single_use(wallet10.clone(), mask10, |api, m| {
|
||||
api.check_repair(m, true)?;
|
||||
api.set_active_account(m, "account_1")?;
|
||||
let info = wallet_info!(wallet10.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 6);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 21);
|
||||
|
||||
api.set_active_account("default")?;
|
||||
let info = wallet_info!(wallet10.clone())?;
|
||||
let outputs = api.retrieve_outputs(true, false, None)?.1;
|
||||
api.set_active_account(m, "default")?;
|
||||
let info = wallet_info!(wallet10.clone(), m)?;
|
||||
let outputs = api.retrieve_outputs(m, true, false, None)?.1;
|
||||
assert_eq!(outputs.len(), 15);
|
||||
assert_eq!(info.amount_currently_spendable, base_amount * 120);
|
||||
Ok(())
|
||||
|
|
|
@ -28,6 +28,7 @@ use impls::test_framework::{LocalWalletClient, WalletProxy};
|
|||
use impls::{DefaultLCProvider, DefaultWalletImpl};
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
use util::secp::key::SecretKey;
|
||||
use util::{Mutex, ZeroingString};
|
||||
|
||||
#[macro_export]
|
||||
|
@ -41,20 +42,36 @@ macro_rules! wallet_inst {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! create_wallet_and_add {
|
||||
($client:ident, $wallet: ident, $test_dir: expr, $name: expr, $seed_phrase: expr, $proxy: expr) => {
|
||||
($client:ident, $wallet: ident, $mask: ident, $test_dir: expr, $name: expr, $seed_phrase: expr, $proxy: expr, $create_mask: expr) => {
|
||||
let $client = LocalWalletClient::new($name, $proxy.tx.clone());
|
||||
let $wallet =
|
||||
common::create_local_wallet($test_dir, $name, $seed_phrase.clone(), $client.clone());
|
||||
$proxy.add_wallet($name, $client.get_send_instance(), $wallet.clone());
|
||||
let ($wallet, $mask) = common::create_local_wallet(
|
||||
$test_dir,
|
||||
$name,
|
||||
$seed_phrase.clone(),
|
||||
$client.clone(),
|
||||
$create_mask,
|
||||
);
|
||||
$proxy.add_wallet(
|
||||
$name,
|
||||
$client.get_send_instance(),
|
||||
$wallet.clone(),
|
||||
$mask.clone(),
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! open_wallet_and_add {
|
||||
($client:ident, $wallet: ident, $test_dir: expr, $name: expr, $proxy: expr) => {
|
||||
($client:ident, $wallet: ident, $mask: ident, $test_dir: expr, $name: expr, $proxy: expr, $create_mask: expr) => {
|
||||
let $client = LocalWalletClient::new($name, $proxy.tx.clone());
|
||||
let $wallet = common::open_local_wallet($test_dir, $name, $client.clone());
|
||||
$proxy.add_wallet($name, $client.get_send_instance(), $wallet.clone());
|
||||
let ($wallet, $mask) =
|
||||
common::open_local_wallet($test_dir, $name, $client.clone(), $create_mask);
|
||||
$proxy.add_wallet(
|
||||
$name,
|
||||
$client.get_send_instance(),
|
||||
$wallet.clone(),
|
||||
$mask.clone(),
|
||||
);
|
||||
};
|
||||
}
|
||||
pub fn clean_output_dir(test_dir: &str) {
|
||||
|
@ -79,18 +96,22 @@ pub fn create_local_wallet(
|
|||
name: &str,
|
||||
mnemonic: Option<ZeroingString>,
|
||||
client: LocalWalletClient,
|
||||
) -> Arc<
|
||||
Mutex<
|
||||
Box<
|
||||
WalletInst<
|
||||
'static,
|
||||
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
create_mask: bool,
|
||||
) -> (
|
||||
Arc<
|
||||
Mutex<
|
||||
Box<
|
||||
WalletInst<
|
||||
'static,
|
||||
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
Option<SecretKey>,
|
||||
) {
|
||||
let mut wallet = Box::new(DefaultWalletImpl::<LocalWalletClient>::new(client).unwrap())
|
||||
as Box<
|
||||
WalletInst<
|
||||
|
@ -103,26 +124,32 @@ pub fn create_local_wallet(
|
|||
lc.set_wallet_directory(&format!("{}/{}", test_dir, name));
|
||||
lc.create_wallet(None, mnemonic, 32, ZeroingString::from(""))
|
||||
.unwrap();
|
||||
lc.open_wallet(None, ZeroingString::from("")).unwrap();
|
||||
Arc::new(Mutex::new(wallet))
|
||||
let mask = lc
|
||||
.open_wallet(None, ZeroingString::from(""), create_mask, false)
|
||||
.unwrap();
|
||||
(Arc::new(Mutex::new(wallet)), mask)
|
||||
}
|
||||
|
||||
pub fn open_local_wallet(
|
||||
test_dir: &str,
|
||||
name: &str,
|
||||
client: LocalWalletClient,
|
||||
) -> Arc<
|
||||
Mutex<
|
||||
Box<
|
||||
WalletInst<
|
||||
'static,
|
||||
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
create_mask: bool,
|
||||
) -> (
|
||||
Arc<
|
||||
Mutex<
|
||||
Box<
|
||||
WalletInst<
|
||||
'static,
|
||||
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
> {
|
||||
Option<SecretKey>,
|
||||
) {
|
||||
let mut wallet = Box::new(DefaultWalletImpl::<LocalWalletClient>::new(client).unwrap())
|
||||
as Box<
|
||||
WalletInst<
|
||||
|
@ -133,6 +160,8 @@ pub fn open_local_wallet(
|
|||
>;
|
||||
let lc = wallet.lc_provider().unwrap();
|
||||
lc.set_wallet_directory(&format!("{}/{}", test_dir, name));
|
||||
lc.open_wallet(None, ZeroingString::from("")).unwrap();
|
||||
Arc::new(Mutex::new(wallet))
|
||||
let mask = lc
|
||||
.open_wallet(None, ZeroingString::from(""), create_mask, false)
|
||||
.unwrap();
|
||||
(Arc::new(Mutex::new(wallet)), mask)
|
||||
}
|
||||
|
|
|
@ -46,19 +46,25 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&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
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -71,16 +77,16 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
let reward = core::consensus::REWARD;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.create_account_path(m, "mining")?;
|
||||
api.create_account_path(m, "listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.create_account_path("account1")?;
|
||||
api.create_account_path("account2")?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
api.create_account_path(m, "account1")?;
|
||||
api.create_account_path(m, "account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -90,7 +96,8 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
w.set_parent_key_id_by_name("mining")?;
|
||||
}
|
||||
let mut bh = 10u64;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize, false);
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
let receive_file = format!("{}/part_tx_2.tx", test_dir);
|
||||
|
@ -99,8 +106,8 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
let message = "sender test message, sender test message";
|
||||
|
||||
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
|
@ -115,10 +122,10 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
message: Some(message.to_owned()),
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api.init_send_tx(args)?;
|
||||
let mut slate = api.init_send_tx(m, args)?;
|
||||
// output tx file
|
||||
PathToSlate((&send_file).into()).put_tx(&mut slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -133,37 +140,37 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
naughty_slate.participant_data[0].message = Some("I changed the message".to_owned());
|
||||
|
||||
// verify messages on slate match
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.verify_slate_messages(&slate)?;
|
||||
assert!(api.verify_slate_messages(&naughty_slate).is_err());
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.verify_slate_messages(m, &slate)?;
|
||||
assert!(api.verify_slate_messages(m, &naughty_slate).is_err());
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let sender2_message = "And this is sender 2's message".to_owned();
|
||||
|
||||
// wallet 2 receives file, completes, sends file back
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), |api| {
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
slate = api.receive_tx(&slate, None, Some(sender2_message.clone()))?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 finalises and posts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let mut slate = PathToSlate(receive_file.into()).get_tx()?;
|
||||
api.verify_slate_messages(&slate)?;
|
||||
slate = api.finalize_tx(&slate)?;
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
api.verify_slate_messages(m, &slate)?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, &slate.tx, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// Check total in mining account
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
|
||||
|
@ -171,8 +178,8 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
})?;
|
||||
|
||||
// Check total in 'wallet 2' account
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet2_info.total, 2 * reward);
|
||||
|
@ -180,8 +187,8 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
})?;
|
||||
|
||||
// Check messages, all participants should have both
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, tx) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert_eq!(
|
||||
tx[0].clone().messages.unwrap().messages[0].message,
|
||||
Some(message.to_owned())
|
||||
|
@ -196,8 +203,8 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
|
|||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (_, tx) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (_, tx) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
assert_eq!(
|
||||
tx[0].clone().messages.unwrap().messages[0].message,
|
||||
Some(message.to_owned())
|
||||
|
|
|
@ -41,19 +41,25 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
true
|
||||
);
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
create_wallet_and_add!(
|
||||
client2,
|
||||
wallet2,
|
||||
mask2_i,
|
||||
test_dir,
|
||||
"wallet2",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
true
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -66,9 +72,9 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
let reward = core::consensus::REWARD;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.create_account_path(m, "mining")?;
|
||||
api.create_account_path(m, "listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -78,11 +84,17 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
w.set_parent_key_id_by_name("mining")?;
|
||||
}
|
||||
let mut bh = 10u64;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
wallet1.clone(),
|
||||
mask1,
|
||||
bh as usize,
|
||||
false,
|
||||
);
|
||||
|
||||
// Sanity check wallet 1 contents
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
|
@ -91,17 +103,17 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
|
||||
let mut slate = Slate::blank(2);
|
||||
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
// Wallet 2 inititates an invoice transaction, requesting payment
|
||||
let args = IssueInvoiceTxArgs {
|
||||
amount: reward * 2,
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.issue_invoice_tx(args)?;
|
||||
slate = api.issue_invoice_tx(m, args)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
// Wallet 1 receives the invoice transaction
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -112,32 +124,32 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.process_invoice_tx(&slate, args)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 2 finalizes and posts
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), |api| {
|
||||
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
|
||||
// Wallet 2 receives the invoice transaction
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 posts so wallet 2 doesn't get the mined amount
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
bh += 1;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// Check transaction log for wallet 2
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (_, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (_, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
assert!(txs.len() == 1);
|
||||
println!(
|
||||
|
@ -151,9 +163,9 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
|
||||
// Check transaction log for wallet 1, ensure only 1 entry
|
||||
// exists
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
assert_eq!(txs.len() as u64, bh + 1);
|
||||
println!(
|
||||
|
@ -164,13 +176,13 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
})?;
|
||||
|
||||
// Test self-sending
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
// Wallet 1 inititates an invoice transaction, requesting payment
|
||||
let args = IssueInvoiceTxArgs {
|
||||
amount: reward * 2,
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.issue_invoice_tx(args)?;
|
||||
slate = api.issue_invoice_tx(m, args)?;
|
||||
// Wallet 1 receives the invoice transaction
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -181,19 +193,19 @@ fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
slate = api.process_invoice_tx(&slate, args)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = api.process_invoice_tx(m, &slate, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// wallet 1 finalizes and posts
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
|
||||
// Wallet 2 receives the invoice transaction
|
||||
slate = api.finalize_invoice_tx(&slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
//bh += 3;
|
||||
|
||||
// let logging finish
|
||||
|
|
|
@ -43,19 +43,25 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&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
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -68,16 +74,16 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
let reward = core::consensus::REWARD;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.create_account_path(m, "mining")?;
|
||||
api.create_account_path(m, "listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.create_account_path("account1")?;
|
||||
api.create_account_path("account2")?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
api.create_account_path(m, "account1")?;
|
||||
api.create_account_path(m, "account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -87,7 +93,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
w.set_parent_key_id_by_name("mining")?;
|
||||
}
|
||||
let mut bh = 10u64;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize, false);
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||
let receive_file = format!("{}/part_tx_2.tx", test_dir);
|
||||
|
@ -95,8 +102,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
let mut slate = Slate::blank(2);
|
||||
|
||||
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
|
@ -110,13 +117,13 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate = api.init_send_tx(args)?;
|
||||
let slate = api.init_send_tx(m, args)?;
|
||||
PathToSlate((&send_file).into()).put_tx(&slate)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// wallet 1 receives file to different account, completes
|
||||
|
@ -125,7 +132,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
w.set_parent_key_id_by_name("listener")?;
|
||||
}
|
||||
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
|
||||
slate = PathToSlate((&send_file).into()).get_tx()?;
|
||||
slate = api.receive_tx(&slate, None, None)?;
|
||||
PathToSlate((&receive_file).into()).put_tx(&slate)?;
|
||||
|
@ -139,27 +146,27 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
}
|
||||
|
||||
// wallet 1 finalize
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
slate = PathToSlate((&receive_file).into()).get_tx()?;
|
||||
slate = api.finalize_tx(&slate)?;
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Now repost from cached
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||
let stored_tx = api.get_stored_tx(&txs[0])?;
|
||||
api.post_tx(&stored_tx.unwrap(), false)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
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(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// update/test contents of both accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
|
||||
|
@ -171,8 +178,8 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
w.set_parent_key_id_by_name("listener")?;
|
||||
}
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet2_info.total, 2 * reward);
|
||||
|
@ -192,7 +199,7 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
let mut slate = Slate::blank(2);
|
||||
let amount = 60_000_000_000;
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -203,39 +210,39 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&mut slate)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &mut slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// Now repost from cached
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||
let stored_tx = api.get_stored_tx(&txs[0])?;
|
||||
api.post_tx(&stored_tx.unwrap(), false)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, Some(slate.id))?;
|
||||
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(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
//
|
||||
// update/test contents of both accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward - reward * 4);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet2_info.total, 2 * amount);
|
||||
|
|
|
@ -41,10 +41,12 @@ fn restore_wallet(base_dir: &'static str, wallet_dir: &str) -> Result<(), libwal
|
|||
create_wallet_and_add!(
|
||||
client,
|
||||
wallet,
|
||||
mask,
|
||||
base_dir,
|
||||
&dest_wallet_name,
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
// close created wallet
|
||||
let mut w_lock = wallet.lock();
|
||||
|
@ -59,10 +61,13 @@ fn restore_wallet(base_dir: &'static str, wallet_dir: &str) -> Result<(), libwal
|
|||
open_wallet_and_add!(
|
||||
client,
|
||||
wallet,
|
||||
mask_i,
|
||||
&base_dir,
|
||||
&dest_wallet_name,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask = (&mask_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
let wp_running = wallet_proxy.running.clone();
|
||||
|
@ -73,9 +78,9 @@ fn restore_wallet(base_dir: &'static str, wallet_dir: &str) -> Result<(), libwal
|
|||
});
|
||||
|
||||
// perform the restore and update wallet info
|
||||
wallet::controller::owner_single_use(wallet.clone(), |api| {
|
||||
let _ = api.restore()?;
|
||||
let _ = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet.clone(), mask, |api, m| {
|
||||
let _ = api.restore(m)?;
|
||||
let _ = api.retrieve_summary_info(m, true, 1)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -96,17 +101,23 @@ fn compare_wallet_restore(
|
|||
open_wallet_and_add!(
|
||||
client,
|
||||
wallet_source,
|
||||
source_mask_i,
|
||||
&base_dir,
|
||||
&wallet_dir,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let source_mask = (&source_mask_i).as_ref();
|
||||
open_wallet_and_add!(
|
||||
client,
|
||||
wallet_dest,
|
||||
dest_mask_i,
|
||||
&base_dir,
|
||||
&restore_name,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let dest_mask = (&dest_mask_i).as_ref();
|
||||
|
||||
{
|
||||
wallet_inst!(wallet_source, w);
|
||||
|
@ -136,17 +147,17 @@ fn compare_wallet_restore(
|
|||
let mut dest_accts: Option<Vec<AcctPathMapping>> = None;
|
||||
|
||||
// Overall wallet info should be the same
|
||||
wallet::controller::owner_single_use(wallet_source.clone(), |api| {
|
||||
src_info = Some(api.retrieve_summary_info(true, 1)?.1);
|
||||
src_txs = Some(api.retrieve_txs(true, None, None)?.1);
|
||||
src_accts = Some(api.accounts()?);
|
||||
wallet::controller::owner_single_use(wallet_source.clone(), source_mask, |api, m| {
|
||||
src_info = Some(api.retrieve_summary_info(m, true, 1)?.1);
|
||||
src_txs = Some(api.retrieve_txs(m, true, None, None)?.1);
|
||||
src_accts = Some(api.accounts(m)?);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet_dest.clone(), |api| {
|
||||
dest_info = Some(api.retrieve_summary_info(true, 1)?.1);
|
||||
dest_txs = Some(api.retrieve_txs(true, None, None)?.1);
|
||||
dest_accts = Some(api.accounts()?);
|
||||
wallet::controller::owner_single_use(wallet_dest.clone(), dest_mask, |api, m| {
|
||||
dest_info = Some(api.retrieve_summary_info(m, true, 1)?.1);
|
||||
dest_txs = Some(api.retrieve_txs(m, true, None, None)?.1);
|
||||
dest_accts = Some(api.accounts(m)?);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -194,24 +205,30 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&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
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// wallet 2 will use another account
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.create_account_path("account1")?;
|
||||
api.create_account_path("account2")?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
api.create_account_path(m, "account1")?;
|
||||
api.create_account_path(m, "account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -225,11 +242,14 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client3,
|
||||
wallet3,
|
||||
mask3_i,
|
||||
test_dir,
|
||||
"wallet3",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask3 = (&mask3_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
let wp_running = wallet_proxy.running.clone();
|
||||
|
@ -240,13 +260,13 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
});
|
||||
|
||||
// mine a few blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 10, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false);
|
||||
|
||||
// assert wallet contents
|
||||
// and a single use api for a send command
|
||||
let amount = 60_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -257,19 +277,19 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
sender_api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// mine a few more blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
|
||||
// Send some to wallet 3
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -280,19 +300,19 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
sender_api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// mine a few more blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet3.clone(), 10, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet3.clone(), mask3, 10, false);
|
||||
|
||||
// Wallet3 to wallet 2
|
||||
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet3.clone(), mask3, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -303,11 +323,11 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
sender_api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -318,10 +338,10 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
}
|
||||
|
||||
// mine a few more blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 2, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 2, false);
|
||||
|
||||
// Wallet3 to wallet 2 again (to another account)
|
||||
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet3.clone(), mask3, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -332,28 +352,28 @@ fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
sender_api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// mine a few more blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 5, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
|
||||
|
||||
// update everyone
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let _ = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let _ = api.retrieve_summary_info(m, true, 1)?;
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let _ = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let _ = api.retrieve_summary_info(m, true, 1)?;
|
||||
Ok(())
|
||||
})?;
|
||||
wallet::controller::owner_single_use(wallet3.clone(), |api| {
|
||||
let _ = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet3.clone(), mask3, |api, m| {
|
||||
let _ = api.retrieve_summary_info(m, true, 1)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
|
|
@ -41,11 +41,14 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
true
|
||||
);
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -58,9 +61,9 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
let reward = core::consensus::REWARD;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.create_account_path(m, "mining")?;
|
||||
api.create_account_path(m, "listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
@ -70,11 +73,12 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
w.set_parent_key_id_by_name("mining")?;
|
||||
}
|
||||
let mut bh = 10u64;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize, false);
|
||||
let _ =
|
||||
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
|
||||
|
||||
// Should have 5 in account1 (5 spendable), 5 in account (2 spendable)
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward);
|
||||
|
@ -88,25 +92,25 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let mut slate = api.init_send_tx(args)?;
|
||||
api.tx_lock_outputs(&slate, 0)?;
|
||||
let mut slate = api.init_send_tx(m, args)?;
|
||||
api.tx_lock_outputs(m, &slate, 0)?;
|
||||
// Send directly to self
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
|
||||
slate = api.receive_tx(&slate, Some("listener"), None)?;
|
||||
Ok(())
|
||||
})?;
|
||||
slate = api.finalize_tx(&slate)?;
|
||||
api.post_tx(&slate.tx, false)?; // mines a block
|
||||
slate = api.finalize_tx(m, &slate)?;
|
||||
api.post_tx(m, &slate.tx, false)?; // mines a block
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
bh += 3;
|
||||
|
||||
// Check total in mining account
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, bh * reward - reward * 2);
|
||||
|
@ -118,8 +122,8 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
wallet_inst!(wallet1, w);
|
||||
w.set_parent_key_id_by_name("listener")?;
|
||||
}
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.total, 2 * reward);
|
||||
|
|
|
@ -42,19 +42,27 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
true
|
||||
);
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
println!("Mask1: {:?}", mask1);
|
||||
create_wallet_and_add!(
|
||||
client2,
|
||||
wallet2,
|
||||
mask2_i,
|
||||
test_dir,
|
||||
"wallet2",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
println!("Mask2: {:?}", mask2);
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -67,11 +75,11 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
let reward = core::consensus::REWARD;
|
||||
let cm = global::coinbase_maturity();
|
||||
// mine a few blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 10, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false);
|
||||
|
||||
// Check wallet 1 contents are as expected
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
debug!(
|
||||
"Wallet 1 Info Pre-Transaction, after {} blocks: {:?}",
|
||||
wallet1_info.last_confirmed_height, wallet1_info
|
||||
|
@ -89,7 +97,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
// and a single use api for a send command
|
||||
let amount = 60_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -100,15 +108,15 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
|
||||
// Check we are creating a tx with the expected lock_height of 0.
|
||||
// We will check this produces a Plain kernel later.
|
||||
assert_eq!(0, slate.lock_height);
|
||||
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
|
||||
// Check we have a single kernel and that it is a Plain kernel (no lock_height).
|
||||
assert_eq!(slate.tx.kernels().len(), 1);
|
||||
|
@ -125,9 +133,9 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
})?;
|
||||
|
||||
// Check transaction log for wallet 1
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
let fee = core::libtx::tx_fee(
|
||||
wallet1_info.last_confirmed_height as usize - cm as usize,
|
||||
|
@ -148,8 +156,8 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
})?;
|
||||
|
||||
// Check transaction log for wallet 2
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, 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));
|
||||
|
@ -164,14 +172,14 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
})?;
|
||||
|
||||
// post transaction
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.post_tx(m, &slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Check wallet 1 contents are as expected
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
debug!(
|
||||
"Wallet 1 Info Post Transaction, after {} blocks: {:?}",
|
||||
wallet1_info.last_confirmed_height, wallet1_info
|
||||
|
@ -195,7 +203,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
assert_eq!(wallet1_info.amount_immature, cm * reward + fee);
|
||||
|
||||
// check tx log entry is confirmed
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
|
||||
assert!(tx.is_some());
|
||||
|
@ -207,11 +215,11 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
})?;
|
||||
|
||||
// mine a few more blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
|
||||
// refresh wallets and retrieve info/tests for each wallet after maturity
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
debug!("Wallet 1 Info: {:?}", wallet1_info);
|
||||
assert!(wallet1_refreshed);
|
||||
assert_eq!(
|
||||
|
@ -225,13 +233,13 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.amount_currently_spendable, amount);
|
||||
|
||||
// check tx log entry is confirmed
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
|
||||
assert!(tx.is_some());
|
||||
|
@ -242,7 +250,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
})?;
|
||||
|
||||
// Estimate fee and locked amount for a transaction
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
let init_args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
amount: amount * 2,
|
||||
|
@ -253,7 +261,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
estimate_only: Some(true),
|
||||
..Default::default()
|
||||
};
|
||||
let est = sender_api.init_send_tx(init_args)?;
|
||||
let est = sender_api.init_send_tx(m, init_args)?;
|
||||
assert_eq!(est.amount, 600_000_000_000);
|
||||
assert_eq!(est.fee, 4_000_000);
|
||||
|
||||
|
@ -267,7 +275,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
estimate_only: Some(true),
|
||||
..Default::default()
|
||||
};
|
||||
let est = sender_api.init_send_tx(init_args)?;
|
||||
let est = sender_api.init_send_tx(m, init_args)?;
|
||||
assert_eq!(est.amount, 180_000_000_000);
|
||||
assert_eq!(est.fee, 6_000_000);
|
||||
|
||||
|
@ -276,7 +284,7 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
|
||||
// Send another transaction, but don't post to chain immediately and use
|
||||
// the stored transaction instead
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -287,25 +295,25 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
let (refreshed, _wallet1_info) = sender_api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
let (refreshed, _wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(refreshed);
|
||||
let (_, txs) = sender_api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = sender_api.retrieve_txs(m, true, 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(&tx)?;
|
||||
sender_api.post_tx(&stored_tx.unwrap(), false)?;
|
||||
let (_, wallet1_info) = sender_api.retrieve_summary_info(true, 1)?;
|
||||
let stored_tx = sender_api.get_stored_tx(m, &tx)?;
|
||||
sender_api.post_tx(m, &stored_tx.unwrap(), false)?;
|
||||
let (_, wallet1_info) = sender_api.retrieve_summary_info(m, true, 1)?;
|
||||
// should be mined now
|
||||
assert_eq!(
|
||||
wallet1_info.total,
|
||||
|
@ -315,16 +323,16 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
|
|||
})?;
|
||||
|
||||
// mine a few more blocks
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 3, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
|
||||
|
||||
// check wallet2 has stored transaction
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (wallet2_refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(wallet2_refreshed);
|
||||
assert_eq!(wallet2_info.amount_currently_spendable, amount * 3);
|
||||
|
||||
// check tx log entry is confirmed
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
|
||||
assert!(tx.is_some());
|
||||
|
@ -350,19 +358,25 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
create_wallet_and_add!(
|
||||
client1,
|
||||
wallet1,
|
||||
mask1_i,
|
||||
test_dir,
|
||||
"wallet1",
|
||||
None,
|
||||
&mut wallet_proxy
|
||||
&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
|
||||
&mut wallet_proxy,
|
||||
false
|
||||
);
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -375,11 +389,11 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
let reward = core::consensus::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(), 5, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
|
||||
|
||||
let amount = 30_000_000_000;
|
||||
let mut slate = Slate::blank(1);
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |sender_api, m| {
|
||||
// note this will increment the block count as part of the transaction "Posting"
|
||||
let args = InitTxArgs {
|
||||
src_acct_name: None,
|
||||
|
@ -391,29 +405,29 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
..Default::default()
|
||||
};
|
||||
|
||||
let slate_i = sender_api.init_send_tx(args)?;
|
||||
let slate_i = sender_api.init_send_tx(m, args)?;
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, 0)?;
|
||||
slate = sender_api.finalize_tx(&slate)?;
|
||||
sender_api.tx_lock_outputs(m, &slate, 0)?;
|
||||
slate = sender_api.finalize_tx(m, &slate)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Check transaction log for wallet 1
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
let (refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
println!(
|
||||
"last confirmed height: {}",
|
||||
wallet1_info.last_confirmed_height
|
||||
);
|
||||
assert!(refreshed);
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
// we should have a transaction entry for this slate
|
||||
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
|
||||
assert!(tx.is_some());
|
||||
let mut locked_count = 0;
|
||||
let mut unconfirmed_count = 0;
|
||||
// get the tx entry, check outputs are as expected
|
||||
let (_, output_mappings) = api.retrieve_outputs(true, false, Some(tx.unwrap().id))?;
|
||||
let (_, output_mappings) = api.retrieve_outputs(m, true, false, Some(tx.unwrap().id))?;
|
||||
for m in output_mappings.clone() {
|
||||
if m.output.status == OutputStatus::Locked {
|
||||
locked_count = locked_count + 1;
|
||||
|
@ -430,14 +444,14 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
})?;
|
||||
|
||||
// Check transaction log for wallet 2
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
let mut unconfirmed_count = 0;
|
||||
let tx = txs.iter().find(|t| t.tx_slate_id == Some(slate.id));
|
||||
assert!(tx.is_some());
|
||||
// get the tx entry, check outputs are as expected
|
||||
let (_, outputs) = api.retrieve_outputs(true, false, Some(tx.unwrap().id))?;
|
||||
let (_, outputs) = api.retrieve_outputs(m, true, false, Some(tx.unwrap().id))?;
|
||||
for m in outputs.clone() {
|
||||
if m.output.status == OutputStatus::Unconfirmed {
|
||||
unconfirmed_count = unconfirmed_count + 1;
|
||||
|
@ -445,7 +459,7 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
}
|
||||
assert_eq!(outputs.len(), 1);
|
||||
assert_eq!(unconfirmed_count, 1);
|
||||
let (refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(refreshed);
|
||||
assert_eq!(wallet2_info.amount_currently_spendable, 0,);
|
||||
assert_eq!(wallet2_info.amount_awaiting_finalization, amount);
|
||||
|
@ -454,20 +468,20 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::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(), 5, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
|
||||
|
||||
// Wallet 1 decides to roll back instead
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
// can't roll back coinbase
|
||||
let res = api.cancel_tx(Some(1), None);
|
||||
let res = api.cancel_tx(m, Some(1), None);
|
||||
assert!(res.is_err());
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
let tx = txs
|
||||
.iter()
|
||||
.find(|t| t.tx_slate_id == Some(slate.id))
|
||||
.unwrap();
|
||||
api.cancel_tx(Some(tx.id), None)?;
|
||||
let (refreshed, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
api.cancel_tx(m, Some(tx.id), None)?;
|
||||
let (refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(refreshed);
|
||||
println!(
|
||||
"last confirmed height: {}",
|
||||
|
@ -480,27 +494,27 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
|
|||
(wallet1_info.last_confirmed_height - cm) * reward
|
||||
);
|
||||
// can't roll back again
|
||||
let res = api.cancel_tx(Some(tx.id), None);
|
||||
let res = api.cancel_tx(m, Some(tx.id), None);
|
||||
assert!(res.is_err());
|
||||
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// Wallet 2 rolls back
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
let tx = txs
|
||||
.iter()
|
||||
.find(|t| t.tx_slate_id == Some(slate.id))
|
||||
.unwrap();
|
||||
api.cancel_tx(Some(tx.id), None)?;
|
||||
let (refreshed, wallet2_info) = api.retrieve_summary_info(true, 1)?;
|
||||
api.cancel_tx(m, Some(tx.id), None)?;
|
||||
let (refreshed, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert!(refreshed);
|
||||
// check all eligible inputs should be now be spendable
|
||||
assert_eq!(wallet2_info.amount_currently_spendable, 0,);
|
||||
assert_eq!(wallet2_info.total, 0,);
|
||||
// can't roll back again
|
||||
let res = api.cancel_tx(Some(tx.id), None);
|
||||
let res = api.cancel_tx(m, Some(tx.id), None);
|
||||
assert!(res.is_err());
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -28,7 +28,7 @@ pub struct HttpSlateSender {
|
|||
impl HttpSlateSender {
|
||||
/// Create, return Err if scheme is not "http"
|
||||
pub fn new(base_url: Url) -> Result<HttpSlateSender, SchemeNotHttp> {
|
||||
if base_url.scheme() != "http" {
|
||||
if base_url.scheme() != "http" && base_url.scheme() != "https" {
|
||||
Err(SchemeNotHttp)
|
||||
} else {
|
||||
Ok(HttpSlateSender { base_url })
|
||||
|
|
|
@ -368,7 +368,7 @@ impl SlateReceiver for KeybaseAllChannels {
|
|||
>;
|
||||
let lc = wallet.lc_provider().unwrap();
|
||||
lc.set_wallet_directory(&config.data_file_dir);
|
||||
lc.open_wallet(None, passphrase)?;
|
||||
let mask = lc.open_wallet(None, passphrase, true, false)?;
|
||||
let wallet_inst = lc.wallet_inst()?;
|
||||
wallet_inst.set_parent_key_id_by_name(account)?;
|
||||
|
||||
|
@ -411,8 +411,14 @@ impl SlateReceiver for KeybaseAllChannels {
|
|||
return Err(e);
|
||||
}
|
||||
let res = {
|
||||
let r =
|
||||
foreign::receive_tx(&mut **wallet_inst, &slate, None, None, false);
|
||||
let r = foreign::receive_tx(
|
||||
&mut **wallet_inst,
|
||||
Some(mask.as_ref().unwrap()),
|
||||
&slate,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
);
|
||||
r
|
||||
};
|
||||
match res {
|
||||
|
|
|
@ -24,7 +24,7 @@ use std::path::Path;
|
|||
use failure::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::blake2::blake2b::Blake2b;
|
||||
use crate::blake2::blake2b::{Blake2b, Blake2bResult};
|
||||
|
||||
use crate::keychain::{ChildNumber, ExtKeychain, Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::store::{self, option_to_not_found, to_key, to_key_u64};
|
||||
|
@ -36,8 +36,12 @@ use crate::libwallet::{
|
|||
AcctPathMapping, Context, Error, ErrorKind, NodeClient, OutputData, TxLogEntry, WalletBackend,
|
||||
WalletOutputBatch,
|
||||
};
|
||||
use crate::util;
|
||||
use crate::util::secp::constants::SECRET_KEY_SIZE;
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{self, secp};
|
||||
|
||||
use rand::rngs::mock::StepRng;
|
||||
use rand::thread_rng;
|
||||
|
||||
pub const DB_DIR: &'static str = "db";
|
||||
pub const TX_SAVE_DIR: &'static str = "saved_txs";
|
||||
|
@ -99,6 +103,8 @@ where
|
|||
data_file_dir: String,
|
||||
/// Keychain
|
||||
pub keychain: Option<K>,
|
||||
/// Check value for XORed keychain seed
|
||||
pub master_checksum: Box<Option<Blake2bResult>>,
|
||||
/// Parent path to use by default for output operations
|
||||
parent_key_id: Identifier,
|
||||
/// wallet to node client
|
||||
|
@ -144,6 +150,7 @@ where
|
|||
db: store,
|
||||
data_file_dir: data_file_dir.to_owned(),
|
||||
keychain: None,
|
||||
master_checksum: Box::new(None),
|
||||
parent_key_id: LMDBBackend::<C, K>::default_path(),
|
||||
w2n_client: n_client,
|
||||
_phantom: &PhantomData,
|
||||
|
@ -172,23 +179,68 @@ where
|
|||
K: Keychain + 'ck,
|
||||
{
|
||||
/// Set the keychain, which should already have been opened
|
||||
fn set_keychain(&mut self, k: Box<K>) {
|
||||
fn set_keychain(
|
||||
&mut self,
|
||||
mut k: Box<K>,
|
||||
mask: bool,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Option<SecretKey>, Error> {
|
||||
// store hash of master key, so it can be verified later after unmasking
|
||||
let root_key = k.derive_key(0, &K::root_key_id(), &SwitchCommitmentType::Regular)?;
|
||||
let mut hasher = Blake2b::new(SECRET_KEY_SIZE);
|
||||
hasher.update(&root_key.0[..]);
|
||||
self.master_checksum = Box::new(Some(hasher.finalize()));
|
||||
|
||||
let mask_value = {
|
||||
match mask {
|
||||
true => {
|
||||
// Random value that must be XORed against the stored wallet seed
|
||||
// before it is used
|
||||
let mask_value = match use_test_rng {
|
||||
true => {
|
||||
let mut test_rng = StepRng::new(1234567890u64, 1);
|
||||
secp::key::SecretKey::new(&k.secp(), &mut test_rng)
|
||||
}
|
||||
false => secp::key::SecretKey::new(&k.secp(), &mut thread_rng()),
|
||||
};
|
||||
k.mask_master_key(&mask_value)?;
|
||||
Some(mask_value)
|
||||
}
|
||||
false => None,
|
||||
}
|
||||
};
|
||||
|
||||
self.keychain = Some(*k);
|
||||
Ok(mask_value)
|
||||
}
|
||||
|
||||
/// Close wallet
|
||||
fn close(&mut self) -> Result<(), Error> {
|
||||
//TODO: Ensure this is zeroed?
|
||||
self.keychain = None;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the keychain being used
|
||||
fn keychain(&mut self) -> Result<&mut K, Error> {
|
||||
if self.keychain.is_some() {
|
||||
Ok(self.keychain.as_mut().unwrap())
|
||||
} else {
|
||||
Err(ErrorKind::KeychainDoesntExist.into())
|
||||
/// Return the keychain being used, cloned with XORed token value
|
||||
/// for temporary use
|
||||
fn keychain(&self, mask: Option<&SecretKey>) -> Result<K, Error> {
|
||||
match self.keychain.as_ref() {
|
||||
Some(k) => {
|
||||
let mut k_masked = k.clone();
|
||||
if let Some(m) = mask {
|
||||
k_masked.mask_master_key(m)?;
|
||||
}
|
||||
// Check if master seed is what is expected (especially if it's been xored)
|
||||
let root_key =
|
||||
k_masked.derive_key(0, &K::root_key_id(), &SwitchCommitmentType::Regular)?;
|
||||
let mut hasher = Blake2b::new(SECRET_KEY_SIZE);
|
||||
hasher.update(&root_key.0[..]);
|
||||
if *self.master_checksum != Some(hasher.finalize()) {
|
||||
error!("Supplied keychain mask is invalid");
|
||||
return Err(ErrorKind::InvalidKeychainMask.into());
|
||||
}
|
||||
Ok(k_masked)
|
||||
}
|
||||
None => Err(ErrorKind::KeychainDoesntExist.into()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,6 +252,7 @@ where
|
|||
/// return the version of the commit for caching
|
||||
fn calc_commit_for_cache(
|
||||
&mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
amount: u64,
|
||||
id: &Identifier,
|
||||
) -> Result<Option<String>, Error> {
|
||||
|
@ -209,7 +262,7 @@ where
|
|||
Ok(None)
|
||||
} else {*/
|
||||
Ok(Some(util::to_hex(
|
||||
self.keychain()?
|
||||
self.keychain(keychain_mask)?
|
||||
.commit(amount, &id, &SwitchCommitmentType::Regular)?
|
||||
.0
|
||||
.to_vec(), // TODO: proper support for different switch commitment schemes
|
||||
|
@ -261,6 +314,7 @@ where
|
|||
|
||||
fn get_private_context(
|
||||
&mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate_id: &[u8],
|
||||
participant_id: usize,
|
||||
) -> Result<Context, Error> {
|
||||
|
@ -269,7 +323,8 @@ where
|
|||
&mut slate_id.to_vec(),
|
||||
participant_id as u64,
|
||||
);
|
||||
let (blind_xor_key, nonce_xor_key) = private_ctx_xor_keys(self.keychain()?, slate_id)?;
|
||||
let (blind_xor_key, nonce_xor_key) =
|
||||
private_ctx_xor_keys(&self.keychain(keychain_mask)?, slate_id)?;
|
||||
|
||||
let mut ctx: Context = option_to_not_found(
|
||||
self.db.get_ser(&ctx_key),
|
||||
|
@ -305,7 +360,7 @@ where
|
|||
.join(filename);
|
||||
let path_buf = Path::new(&path).to_path_buf();
|
||||
let mut stored_tx = File::create(path_buf)?;
|
||||
let tx_hex = util::to_hex(ser::ser_vec(tx).unwrap());;
|
||||
let tx_hex = util::to_hex(ser::ser_vec(tx, ser::ProtocolVersion::local()).unwrap());;
|
||||
stored_tx.write_all(&tx_hex.as_bytes())?;
|
||||
stored_tx.sync_all()?;
|
||||
Ok(())
|
||||
|
@ -325,19 +380,23 @@ where
|
|||
tx_f.read_to_string(&mut content)?;
|
||||
let tx_bin = util::from_hex(content).unwrap();
|
||||
Ok(Some(
|
||||
ser::deserialize::<Transaction>(&mut &tx_bin[..]).unwrap(),
|
||||
ser::deserialize::<Transaction>(&mut &tx_bin[..], ser::ProtocolVersion::local())
|
||||
.unwrap(),
|
||||
))
|
||||
}
|
||||
|
||||
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error> {
|
||||
fn batch<'a>(
|
||||
&'a mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error> {
|
||||
Ok(Box::new(Batch {
|
||||
_store: self,
|
||||
db: RefCell::new(Some(self.db.batch()?)),
|
||||
keychain: self.keychain.clone(),
|
||||
keychain: Some(self.keychain(keychain_mask)?),
|
||||
}))
|
||||
}
|
||||
|
||||
fn next_child<'a>(&mut self) -> Result<Identifier, Error> {
|
||||
fn next_child<'a>(&mut self, keychain_mask: Option<&SecretKey>) -> Result<Identifier, Error> {
|
||||
let parent_key_id = self.parent_key_id.clone();
|
||||
let mut deriv_idx = {
|
||||
let batch = self.db.batch()?;
|
||||
|
@ -351,7 +410,7 @@ where
|
|||
return_path.depth = return_path.depth + 1;
|
||||
return_path.path[return_path.depth as usize - 1] = ChildNumber::from(deriv_idx);
|
||||
deriv_idx = deriv_idx + 1;
|
||||
let mut batch = self.batch()?;
|
||||
let mut batch = self.batch(keychain_mask)?;
|
||||
batch.save_child_index(&parent_key_id, deriv_idx)?;
|
||||
batch.commit()?;
|
||||
Ok(Identifier::from_path(&return_path))
|
||||
|
@ -370,13 +429,17 @@ where
|
|||
Ok(last_confirmed_height)
|
||||
}
|
||||
|
||||
fn restore(&mut self) -> Result<(), Error> {
|
||||
restore(self).context(ErrorKind::Restore)?;
|
||||
fn restore(&mut self, keychain_mask: Option<&SecretKey>) -> Result<(), Error> {
|
||||
restore(self, keychain_mask).context(ErrorKind::Restore)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check_repair(&mut self, delete_unconfirmed: bool) -> Result<(), Error> {
|
||||
check_repair(self, delete_unconfirmed).context(ErrorKind::Restore)?;
|
||||
fn check_repair(
|
||||
&mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
delete_unconfirmed: bool,
|
||||
) -> Result<(), Error> {
|
||||
check_repair(self, keychain_mask, delete_unconfirmed).context(ErrorKind::Restore)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use crate::core::global;
|
|||
use crate::keychain::Keychain;
|
||||
use crate::libwallet::{Error, ErrorKind, NodeClient, WalletBackend, WalletLCProvider};
|
||||
use crate::lifecycle::seed::WalletSeed;
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::ZeroingString;
|
||||
use crate::LMDBBackend;
|
||||
use failure::ResultExt;
|
||||
|
@ -131,7 +132,13 @@ where
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn open_wallet(&mut self, _name: Option<&str>, password: ZeroingString) -> Result<(), Error> {
|
||||
fn open_wallet(
|
||||
&mut self,
|
||||
_name: Option<&str>,
|
||||
password: ZeroingString,
|
||||
create_mask: bool,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Option<SecretKey>, Error> {
|
||||
let mut data_dir_name = PathBuf::from(self.data_dir.clone());
|
||||
data_dir_name.push(GRIN_WALLET_DIR);
|
||||
let data_dir_name = data_dir_name.to_str().unwrap();
|
||||
|
@ -148,9 +155,10 @@ where
|
|||
let keychain = wallet_seed
|
||||
.derive_keychain(global::is_floonet())
|
||||
.context(ErrorKind::Lifecycle("Error deriving keychain".into()))?;
|
||||
wallet.set_keychain(Box::new(keychain));
|
||||
|
||||
let mask = wallet.set_keychain(Box::new(keychain), create_mask, use_test_rng)?;
|
||||
self.backend = Some(Box::new(wallet));
|
||||
Ok(())
|
||||
Ok(mask)
|
||||
}
|
||||
|
||||
fn close_wallet(&mut self, _name: Option<&str>) -> Result<(), Error> {
|
||||
|
|
|
@ -24,6 +24,7 @@ use crate::libwallet::api_impl::{foreign, owner};
|
|||
use crate::libwallet::{
|
||||
BlockFees, CbData, InitTxArgs, NodeClient, WalletInfo, WalletInst, WalletLCProvider,
|
||||
};
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::secp::pedersen;
|
||||
use crate::util::Mutex;
|
||||
use chrono::Duration;
|
||||
|
@ -105,6 +106,7 @@ pub fn award_block_to_wallet<'a, L, C, K>(
|
|||
chain: &Chain,
|
||||
txs: Vec<&Transaction>,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K> + 'a>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<(), libwallet::Error>
|
||||
where
|
||||
L: WalletLCProvider<'a, C, K>,
|
||||
|
@ -123,7 +125,7 @@ where
|
|||
let coinbase_tx = {
|
||||
let mut w_lock = wallet.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
let res = foreign::build_coinbase(&mut **w, &block_fees, false)?;
|
||||
let res = foreign::build_coinbase(&mut **w, keychain_mask, &block_fees, false)?;
|
||||
res
|
||||
};
|
||||
add_block_with_reward(chain, txs, coinbase_tx.clone());
|
||||
|
@ -134,6 +136,7 @@ where
|
|||
pub fn award_blocks_to_wallet<'a, L, C, K>(
|
||||
chain: &Chain,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K> + 'a>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
number: usize,
|
||||
pause_between: bool,
|
||||
) -> Result<(), libwallet::Error>
|
||||
|
@ -143,7 +146,7 @@ where
|
|||
K: keychain::Keychain + 'a,
|
||||
{
|
||||
for _ in 0..number {
|
||||
award_block_to_wallet(chain, vec![], wallet.clone())?;
|
||||
award_block_to_wallet(chain, vec![], wallet.clone(), keychain_mask)?;
|
||||
if pause_between {
|
||||
thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
|
@ -154,6 +157,7 @@ where
|
|||
/// send an amount to a destination
|
||||
pub fn send_to_dest<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
client: LocalWalletClient,
|
||||
dest: &str,
|
||||
amount: u64,
|
||||
|
@ -176,10 +180,10 @@ where
|
|||
selection_strategy_is_use_all: true,
|
||||
..Default::default()
|
||||
};
|
||||
let slate_i = owner::init_send_tx(&mut **w, args, test_mode)?;
|
||||
let slate_i = owner::init_send_tx(&mut **w, keychain_mask, args, test_mode)?;
|
||||
let slate = client.send_tx_slate_direct(dest, &slate_i)?;
|
||||
owner::tx_lock_outputs(&mut **w, &slate, 0)?;
|
||||
let slate = owner::finalize_tx(&mut **w, &slate)?;
|
||||
owner::tx_lock_outputs(&mut **w, keychain_mask, &slate, 0)?;
|
||||
let slate = owner::finalize_tx(&mut **w, keychain_mask, &slate)?;
|
||||
slate
|
||||
};
|
||||
let client = {
|
||||
|
@ -194,6 +198,7 @@ where
|
|||
/// get wallet info totals
|
||||
pub fn wallet_info<'a, L, C, K>(
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<WalletInfo, libwallet::Error>
|
||||
where
|
||||
L: WalletLCProvider<'a, C, K>,
|
||||
|
@ -202,7 +207,8 @@ where
|
|||
{
|
||||
let mut w_lock = wallet.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
let (wallet_refreshed, wallet_info) = owner::retrieve_summary_info(&mut **w, true, 1)?;
|
||||
let (wallet_refreshed, wallet_info) =
|
||||
owner::retrieve_summary_info(&mut **w, keychain_mask, true, 1)?;
|
||||
assert!(wallet_refreshed);
|
||||
Ok(wallet_info)
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ use crate::libwallet::{
|
|||
NodeClient, NodeVersionInfo, Slate, TxWrapper, WalletInst, WalletLCProvider,
|
||||
};
|
||||
use crate::util;
|
||||
use crate::util::secp::key::SecretKey;
|
||||
use crate::util::secp::pedersen;
|
||||
use crate::util::secp::pedersen::Commitment;
|
||||
use crate::util::{Mutex, RwLock};
|
||||
|
@ -73,6 +74,7 @@ where
|
|||
(
|
||||
Sender<WalletProxyMessage>,
|
||||
Arc<Mutex<Box<dyn WalletInst<'a, L, C, K> + 'a>>>,
|
||||
Option<SecretKey>,
|
||||
),
|
||||
>,
|
||||
/// simulate json send to another client
|
||||
|
@ -123,8 +125,10 @@ where
|
|||
addr: &str,
|
||||
tx: Sender<WalletProxyMessage>,
|
||||
wallet: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K> + 'a>>>,
|
||||
keychain_mask: Option<SecretKey>,
|
||||
) {
|
||||
self.wallets.insert(addr.to_owned(), (tx, wallet));
|
||||
self.wallets
|
||||
.insert(addr.to_owned(), (tx, wallet, keychain_mask));
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
|
@ -170,6 +174,7 @@ where
|
|||
/// post transaction to the chain (and mine it, taking the reward)
|
||||
fn post_tx(&mut self, m: WalletProxyMessage) -> Result<WalletProxyMessage, libwallet::Error> {
|
||||
let dest_wallet = self.wallets.get_mut(&m.sender_id).unwrap().1.clone();
|
||||
let dest_wallet_mask = self.wallets.get_mut(&m.sender_id).unwrap().2.clone();
|
||||
let wrapper: TxWrapper = serde_json::from_str(&m.body).context(
|
||||
libwallet::ErrorKind::ClientCallback("Error parsing TxWrapper".to_owned()),
|
||||
)?;
|
||||
|
@ -178,11 +183,17 @@ where
|
|||
libwallet::ErrorKind::ClientCallback("Error parsing TxWrapper: tx_bin".to_owned()),
|
||||
)?;
|
||||
|
||||
let tx: Transaction = ser::deserialize(&mut &tx_bin[..]).context(
|
||||
libwallet::ErrorKind::ClientCallback("Error parsing TxWrapper: tx".to_owned()),
|
||||
)?;
|
||||
let tx: Transaction = ser::deserialize(&mut &tx_bin[..], ser::ProtocolVersion::local())
|
||||
.context(libwallet::ErrorKind::ClientCallback(
|
||||
"Error parsing TxWrapper: tx".to_owned(),
|
||||
))?;
|
||||
|
||||
super::award_block_to_wallet(&self.chain, vec![&tx], dest_wallet)?;
|
||||
super::award_block_to_wallet(
|
||||
&self.chain,
|
||||
vec![&tx],
|
||||
dest_wallet,
|
||||
(&dest_wallet_mask).as_ref(),
|
||||
)?;
|
||||
|
||||
Ok(WalletProxyMessage {
|
||||
sender_id: "node".to_owned(),
|
||||
|
@ -210,8 +221,9 @@ where
|
|||
{
|
||||
let mut w_lock = wallet.1.lock();
|
||||
let w = w_lock.lc_provider()?.wallet_inst()?;
|
||||
let mask = wallet.2.clone();
|
||||
// receive tx
|
||||
slate = foreign::receive_tx(&mut **w, &slate, None, None, false)?;
|
||||
slate = foreign::receive_tx(&mut **w, (&mask).as_ref(), &slate, None, None, false)?;
|
||||
}
|
||||
|
||||
Ok(WalletProxyMessage {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::grin_keychain::Keychain;
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::internal::{tx, updater};
|
||||
use crate::slate_versions::SlateVersion;
|
||||
use crate::{
|
||||
|
@ -37,6 +38,7 @@ pub fn check_version() -> VersionInfo {
|
|||
/// Build a coinbase transaction
|
||||
pub fn build_coinbase<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
block_fees: &BlockFees,
|
||||
test_mode: bool,
|
||||
) -> Result<CbData, Error>
|
||||
|
@ -45,7 +47,7 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
updater::build_coinbase(&mut *w, block_fees, test_mode)
|
||||
updater::build_coinbase(&mut *w, keychain_mask, block_fees, test_mode)
|
||||
}
|
||||
|
||||
/// verify slate messages
|
||||
|
@ -56,6 +58,7 @@ pub fn verify_slate_messages(slate: &Slate) -> Result<(), Error> {
|
|||
/// Receive a tx as recipient
|
||||
pub fn receive_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
dest_acct_name: Option<&str>,
|
||||
message: Option<String>,
|
||||
|
@ -101,6 +104,7 @@ where
|
|||
|
||||
tx::add_output_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut ret_slate,
|
||||
&parent_key_id,
|
||||
1,
|
||||
|
@ -108,24 +112,28 @@ where
|
|||
false,
|
||||
use_test_rng,
|
||||
)?;
|
||||
tx::update_message(&mut *w, &mut ret_slate)?;
|
||||
tx::update_message(&mut *w, keychain_mask, &mut ret_slate)?;
|
||||
Ok(ret_slate)
|
||||
}
|
||||
|
||||
/// Receive an tx that this wallet has issued
|
||||
pub fn finalize_invoice_tx<'a, T: ?Sized, C, K>(w: &mut T, slate: &Slate) -> Result<Slate, Error>
|
||||
pub fn finalize_invoice_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
) -> Result<Slate, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let mut sl = slate.clone();
|
||||
let context = w.get_private_context(sl.id.as_bytes(), 1)?;
|
||||
tx::complete_tx(&mut *w, &mut sl, 1, &context)?;
|
||||
let context = w.get_private_context(keychain_mask, sl.id.as_bytes(), 1)?;
|
||||
tx::complete_tx(&mut *w, keychain_mask, &mut sl, 1, &context)?;
|
||||
tx::update_stored_tx(&mut *w, &mut sl, true)?;
|
||||
tx::update_message(&mut *w, &mut sl)?;
|
||||
tx::update_message(&mut *w, keychain_mask, &mut sl)?;
|
||||
{
|
||||
let mut batch = w.batch()?;
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.delete_private_context(sl.id.as_bytes(), 1)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ use crate::grin_core::core::hash::Hashed;
|
|||
use crate::grin_core::core::Transaction;
|
||||
use crate::grin_core::ser;
|
||||
use crate::grin_util;
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::internal::{keys, selection, tx, updater};
|
||||
|
@ -43,13 +44,17 @@ where
|
|||
}
|
||||
|
||||
/// new account path
|
||||
pub fn create_account_path<'a, T: ?Sized, C, K>(w: &mut T, label: &str) -> Result<Identifier, Error>
|
||||
pub fn create_account_path<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
label: &str,
|
||||
) -> Result<Identifier, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
keys::new_acct_path(&mut *w, label)
|
||||
keys::new_acct_path(&mut *w, keychain_mask, label)
|
||||
}
|
||||
|
||||
/// set active account
|
||||
|
@ -65,6 +70,7 @@ where
|
|||
/// retrieve outputs
|
||||
pub fn retrieve_outputs<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
include_spent: bool,
|
||||
refresh_from_node: bool,
|
||||
tx_id: Option<u32>,
|
||||
|
@ -78,18 +84,25 @@ where
|
|||
|
||||
let mut validated = false;
|
||||
if refresh_from_node {
|
||||
validated = update_outputs(w, false);
|
||||
validated = update_outputs(w, keychain_mask, false);
|
||||
}
|
||||
|
||||
Ok((
|
||||
validated,
|
||||
updater::retrieve_outputs(&mut *w, include_spent, tx_id, Some(&parent_key_id))?,
|
||||
updater::retrieve_outputs(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
include_spent,
|
||||
tx_id,
|
||||
Some(&parent_key_id),
|
||||
)?,
|
||||
))
|
||||
}
|
||||
|
||||
/// Retrieve txs
|
||||
pub fn retrieve_txs<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
refresh_from_node: bool,
|
||||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
|
@ -103,7 +116,7 @@ where
|
|||
|
||||
let mut validated = false;
|
||||
if refresh_from_node {
|
||||
validated = update_outputs(w, false);
|
||||
validated = update_outputs(w, keychain_mask, false);
|
||||
}
|
||||
|
||||
Ok((
|
||||
|
@ -115,6 +128,7 @@ where
|
|||
/// Retrieve summary info
|
||||
pub fn retrieve_summary_info<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
refresh_from_node: bool,
|
||||
minimum_confirmations: u64,
|
||||
) -> Result<(bool, WalletInfo), Error>
|
||||
|
@ -127,7 +141,7 @@ where
|
|||
|
||||
let mut validated = false;
|
||||
if refresh_from_node {
|
||||
validated = update_outputs(w, false);
|
||||
validated = update_outputs(w, keychain_mask, false);
|
||||
}
|
||||
|
||||
let wallet_info = updater::retrieve_info(&mut *w, &parent_key_id, minimum_confirmations)?;
|
||||
|
@ -137,6 +151,7 @@ where
|
|||
/// Initiate tx as sender
|
||||
pub fn init_send_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: InitTxArgs,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Slate, Error>
|
||||
|
@ -171,6 +186,7 @@ where
|
|||
if let Some(true) = args.estimate_only {
|
||||
let (total, fee) = tx::estimate_send_tx(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
args.amount,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
|
@ -185,6 +201,7 @@ where
|
|||
|
||||
let context = tx::add_inputs_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
|
@ -200,7 +217,7 @@ where
|
|||
// Save the aggsig context in our DB for when we
|
||||
// recieve the transaction back
|
||||
{
|
||||
let mut batch = w.batch()?;
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.save_private_context(slate.id.as_bytes(), 0, &context)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -213,6 +230,7 @@ where
|
|||
/// Initiate a transaction as the recipient (invoicing)
|
||||
pub fn issue_invoice_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
args: IssueInvoiceTxArgs,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Slate, Error>
|
||||
|
@ -243,6 +261,7 @@ where
|
|||
let mut slate = tx::new_tx_slate(&mut *w, args.amount, 2, use_test_rng)?;
|
||||
let context = tx::add_output_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut slate,
|
||||
&parent_key_id,
|
||||
1,
|
||||
|
@ -254,7 +273,7 @@ where
|
|||
// Save the aggsig context in our DB for when we
|
||||
// recieve the transaction back
|
||||
{
|
||||
let mut batch = w.batch()?;
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.save_private_context(slate.id.as_bytes(), 1, &context)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -270,6 +289,7 @@ where
|
|||
/// output was specified
|
||||
pub fn process_invoice_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
args: InitTxArgs,
|
||||
use_test_rng: bool,
|
||||
|
@ -317,6 +337,7 @@ where
|
|||
|
||||
let context = tx::add_inputs_to_slate(
|
||||
&mut *w,
|
||||
keychain_mask,
|
||||
&mut ret_slate,
|
||||
args.minimum_confirmations,
|
||||
args.max_outputs as usize,
|
||||
|
@ -332,7 +353,7 @@ where
|
|||
// Save the aggsig context in our DB for when we
|
||||
// recieve the transaction back
|
||||
{
|
||||
let mut batch = w.batch()?;
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.save_private_context(slate.id.as_bytes(), 0, &context)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -347,6 +368,7 @@ where
|
|||
/// Lock sender outputs
|
||||
pub fn tx_lock_outputs<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
participant_id: usize,
|
||||
) -> Result<(), Error>
|
||||
|
@ -355,24 +377,28 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let context = w.get_private_context(slate.id.as_bytes(), participant_id)?;
|
||||
selection::lock_tx_context(&mut *w, slate, &context)
|
||||
let context = w.get_private_context(keychain_mask, slate.id.as_bytes(), participant_id)?;
|
||||
selection::lock_tx_context(&mut *w, keychain_mask, slate, &context)
|
||||
}
|
||||
|
||||
/// Finalize slate
|
||||
pub fn finalize_tx<'a, T: ?Sized, C, K>(w: &mut T, slate: &Slate) -> Result<Slate, Error>
|
||||
pub fn finalize_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
) -> Result<Slate, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let mut sl = slate.clone();
|
||||
let context = w.get_private_context(sl.id.as_bytes(), 0)?;
|
||||
tx::complete_tx(&mut *w, &mut sl, 0, &context)?;
|
||||
let context = w.get_private_context(keychain_mask, sl.id.as_bytes(), 0)?;
|
||||
tx::complete_tx(&mut *w, keychain_mask, &mut sl, 0, &context)?;
|
||||
tx::update_stored_tx(&mut *w, &mut sl, false)?;
|
||||
tx::update_message(&mut *w, &mut sl)?;
|
||||
tx::update_message(&mut *w, keychain_mask, &mut sl)?;
|
||||
{
|
||||
let mut batch = w.batch()?;
|
||||
let mut batch = w.batch(keychain_mask)?;
|
||||
batch.delete_private_context(sl.id.as_bytes(), 0)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -382,6 +408,7 @@ where
|
|||
/// cancel tx
|
||||
pub fn cancel_tx<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
) -> Result<(), Error>
|
||||
|
@ -391,12 +418,12 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
let parent_key_id = w.parent_key_id();
|
||||
if !update_outputs(w, false) {
|
||||
if !update_outputs(w, keychain_mask, false) {
|
||||
return Err(ErrorKind::TransactionCancellationError(
|
||||
"Can't contact running Grin node. Not Cancelling.",
|
||||
))?;
|
||||
}
|
||||
tx::cancel_tx(&mut *w, &parent_key_id, tx_id, tx_slate_id)
|
||||
tx::cancel_tx(&mut *w, keychain_mask, &parent_key_id, tx_id, tx_slate_id)
|
||||
}
|
||||
|
||||
/// get stored tx
|
||||
|
@ -418,7 +445,7 @@ pub fn post_tx<'a, C>(client: &C, tx: &Transaction, fluff: bool) -> Result<(), E
|
|||
where
|
||||
C: NodeClient + 'a,
|
||||
{
|
||||
let tx_hex = grin_util::to_hex(ser::ser_vec(tx).unwrap());
|
||||
let tx_hex = grin_util::to_hex(ser::ser_vec(tx, ser::ProtocolVersion::local()).unwrap());
|
||||
let res = client.post_tx(&TxWrapper { tx_hex: tx_hex }, fluff);
|
||||
if let Err(e) = res {
|
||||
error!("api: post_tx: failed with error: {}", e);
|
||||
|
@ -439,28 +466,38 @@ pub fn verify_slate_messages(slate: &Slate) -> Result<(), Error> {
|
|||
}
|
||||
|
||||
/// Attempt to restore contents of wallet
|
||||
pub fn restore<'a, T: ?Sized, C, K>(w: &mut T) -> Result<(), Error>
|
||||
pub fn restore<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
w.restore()
|
||||
w.restore(keychain_mask)
|
||||
}
|
||||
|
||||
/// check repair
|
||||
pub fn check_repair<'a, T: ?Sized, C, K>(w: &mut T, delete_unconfirmed: bool) -> Result<(), Error>
|
||||
pub fn check_repair<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
delete_unconfirmed: bool,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
update_outputs(w, true);
|
||||
w.check_repair(delete_unconfirmed)
|
||||
update_outputs(w, keychain_mask, true);
|
||||
w.check_repair(keychain_mask, delete_unconfirmed)
|
||||
}
|
||||
|
||||
/// node height
|
||||
pub fn node_height<'a, T: ?Sized, C, K>(w: &mut T) -> Result<NodeHeightResult, Error>
|
||||
pub fn node_height<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<NodeHeightResult, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -473,7 +510,7 @@ where
|
|||
updated_from_node: true,
|
||||
}),
|
||||
Err(_) => {
|
||||
let outputs = retrieve_outputs(w, true, false, None)?;
|
||||
let outputs = retrieve_outputs(w, keychain_mask, true, false, None)?;
|
||||
let height = match outputs.1.iter().map(|m| m.output.height).max() {
|
||||
Some(height) => height,
|
||||
None => 0,
|
||||
|
@ -487,14 +524,18 @@ where
|
|||
}
|
||||
|
||||
/// Attempt to update outputs in wallet, return whether it was successful
|
||||
fn update_outputs<'a, T: ?Sized, C, K>(w: &mut T, update_all: bool) -> bool
|
||||
fn update_outputs<'a, T: ?Sized, C, K>(
|
||||
w: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
update_all: bool,
|
||||
) -> bool
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let parent_key_id = w.parent_key_id();
|
||||
match updater::refresh_outputs(&mut *w, &parent_key_id, update_all) {
|
||||
match updater::refresh_outputs(&mut *w, keychain_mask, &parent_key_id, update_all) {
|
||||
Ok(_) => true,
|
||||
Err(_) => false,
|
||||
}
|
||||
|
|
|
@ -205,6 +205,10 @@ pub enum ErrorKind {
|
|||
#[fail(display = "Lifecycle Error: {}", _0)]
|
||||
Lifecycle(String),
|
||||
|
||||
/// Invalid Keychain Mask Error
|
||||
#[fail(display = "Supplied Keychain Mask Token is incorrect")]
|
||||
InvalidKeychainMask,
|
||||
|
||||
/// Other
|
||||
#[fail(display = "Generic error: {}", _0)]
|
||||
GenericError(String),
|
||||
|
|
|
@ -15,16 +15,20 @@
|
|||
//! Wallet key management functions
|
||||
use crate::error::{Error, ErrorKind};
|
||||
use crate::grin_keychain::{ChildNumber, ExtKeychain, Identifier, Keychain};
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::types::{AcctPathMapping, NodeClient, WalletBackend};
|
||||
|
||||
/// Get next available key in the wallet for a given parent
|
||||
pub fn next_available_key<'a, T: ?Sized, C, K>(wallet: &mut T) -> Result<Identifier, Error>
|
||||
pub fn next_available_key<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<Identifier, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let child = wallet.next_child()?;
|
||||
let child = wallet.next_child(keychain_mask)?;
|
||||
Ok(child)
|
||||
}
|
||||
|
||||
|
@ -56,7 +60,11 @@ where
|
|||
}
|
||||
|
||||
/// Adds an new parent account path with a given label
|
||||
pub fn new_acct_path<'a, T: ?Sized, C, K>(wallet: &mut T, label: &str) -> Result<Identifier, Error>
|
||||
pub fn new_acct_path<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
label: &str,
|
||||
) -> Result<Identifier, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -90,7 +98,7 @@ where
|
|||
path: return_id.clone(),
|
||||
};
|
||||
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.save_acct_path(save_path)?;
|
||||
batch.commit()?;
|
||||
Ok(return_id)
|
||||
|
@ -99,6 +107,7 @@ where
|
|||
/// Adds/sets a particular account path with a given label
|
||||
pub fn set_acct_path<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
label: &str,
|
||||
path: &Identifier,
|
||||
) -> Result<(), Error>
|
||||
|
@ -113,7 +122,7 @@ where
|
|||
path: path.clone(),
|
||||
};
|
||||
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.save_acct_path(save_path)?;
|
||||
batch.commit()?;
|
||||
Ok(())
|
||||
|
|
|
@ -18,6 +18,7 @@ use crate::grin_core::core::HeaderVersion;
|
|||
use crate::grin_core::global;
|
||||
use crate::grin_core::libtx::proof;
|
||||
use crate::grin_keychain::{ExtKeychain, Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::grin_util::secp::pedersen;
|
||||
use crate::internal::{keys, updater};
|
||||
use crate::types::*;
|
||||
|
@ -60,6 +61,7 @@ struct RestoredTxStats {
|
|||
|
||||
fn identify_utxo_outputs<'a, T, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
outputs: Vec<(pedersen::Commitment, pedersen::RangeProof, bool, u64, u64)>,
|
||||
) -> Result<Vec<OutputResult>, Error>
|
||||
where
|
||||
|
@ -74,9 +76,9 @@ where
|
|||
outputs.len(),
|
||||
);
|
||||
|
||||
let keychain = wallet.keychain()?;
|
||||
let legacy_builder = proof::LegacyProofBuilder::new(keychain);
|
||||
let builder = proof::ProofBuilder::new(keychain);
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
let legacy_builder = proof::LegacyProofBuilder::new(&keychain);
|
||||
let builder = proof::ProofBuilder::new(&keychain);
|
||||
let legacy_version = HeaderVersion(1);
|
||||
|
||||
for output in outputs.iter() {
|
||||
|
@ -136,7 +138,10 @@ where
|
|||
Ok(wallet_outputs)
|
||||
}
|
||||
|
||||
fn collect_chain_outputs<'a, T, C, K>(wallet: &mut T) -> Result<Vec<OutputResult>, Error>
|
||||
fn collect_chain_outputs<'a, T, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<Vec<OutputResult>, Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -156,7 +161,11 @@ where
|
|||
last_retrieved_index,
|
||||
);
|
||||
|
||||
result_vec.append(&mut identify_utxo_outputs(wallet, outputs.clone())?);
|
||||
result_vec.append(&mut identify_utxo_outputs(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
outputs.clone(),
|
||||
)?);
|
||||
|
||||
if highest_index == last_retrieved_index {
|
||||
break;
|
||||
|
@ -169,6 +178,7 @@ where
|
|||
///
|
||||
fn restore_missing_output<'a, T, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
output: OutputResult,
|
||||
found_parents: &mut HashMap<Identifier, u32>,
|
||||
tx_stats: &mut Option<&mut HashMap<Identifier, RestoredTxStats>>,
|
||||
|
@ -178,8 +188,8 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let commit = wallet.calc_commit_for_cache(output.value, &output.key_id)?;
|
||||
let mut batch = wallet.batch()?;
|
||||
let commit = wallet.calc_commit_for_cache(keychain_mask, output.value, &output.key_id)?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
|
||||
let parent_key_id = output.key_id.parent_path();
|
||||
if !found_parents.contains_key(&parent_key_id) {
|
||||
|
@ -250,7 +260,11 @@ where
|
|||
}
|
||||
|
||||
///
|
||||
fn cancel_tx_log_entry<'a, T, C, K>(wallet: &mut T, output: &OutputData) -> Result<(), Error>
|
||||
fn cancel_tx_log_entry<'a, T, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
output: &OutputData,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -279,7 +293,7 @@ where
|
|||
} else {
|
||||
None
|
||||
};
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
if let Some(t) = updated_tx_entry {
|
||||
batch.save_tx_log_entry(t, &parent_key_id)?;
|
||||
}
|
||||
|
@ -290,7 +304,11 @@ where
|
|||
/// Check / repair wallet contents
|
||||
/// assume wallet contents have been freshly updated with contents
|
||||
/// of latest block
|
||||
pub fn check_repair<'a, T, C, K>(wallet: &mut T, delete_unconfirmed: bool) -> Result<(), Error>
|
||||
pub fn check_repair<'a, T, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
delete_unconfirmed: bool,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -298,7 +316,7 @@ where
|
|||
{
|
||||
// First, get a definitive list of outputs we own from the chain
|
||||
warn!("Starting wallet check.");
|
||||
let chain_outs = collect_chain_outputs(wallet)?;
|
||||
let chain_outs = collect_chain_outputs(wallet, keychain_mask)?;
|
||||
warn!(
|
||||
"Identified {} wallet_outputs as belonging to this wallet",
|
||||
chain_outs.len(),
|
||||
|
@ -306,7 +324,7 @@ where
|
|||
|
||||
// Now, get all outputs owned by this wallet (regardless of account)
|
||||
let wallet_outputs = {
|
||||
let res = updater::retrieve_outputs(&mut *wallet, true, None, None)?;
|
||||
let res = updater::retrieve_outputs(&mut *wallet, keychain_mask, true, None, None)?;
|
||||
res
|
||||
};
|
||||
|
||||
|
@ -340,8 +358,8 @@ where
|
|||
);
|
||||
o.status = OutputStatus::Unspent;
|
||||
// any transactions associated with this should be cancelled
|
||||
cancel_tx_log_entry(wallet, &o)?;
|
||||
let mut batch = wallet.batch()?;
|
||||
cancel_tx_log_entry(wallet, keychain_mask, &o)?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.save(o)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -355,7 +373,7 @@ where
|
|||
Restoring.",
|
||||
m.value, m.key_id, m.commit,
|
||||
);
|
||||
restore_missing_output(wallet, m, &mut found_parents, &mut None)?;
|
||||
restore_missing_output(wallet, keychain_mask, m, &mut found_parents, &mut None)?;
|
||||
}
|
||||
|
||||
if delete_unconfirmed {
|
||||
|
@ -368,8 +386,8 @@ where
|
|||
o.value, o.key_id, m.1.commit,
|
||||
);
|
||||
o.status = OutputStatus::Unspent;
|
||||
cancel_tx_log_entry(wallet, &o)?;
|
||||
let mut batch = wallet.batch()?;
|
||||
cancel_tx_log_entry(wallet, keychain_mask, &o)?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.save(o)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -386,8 +404,8 @@ where
|
|||
Deleting and cancelling associated transaction log entries.",
|
||||
o.value, o.key_id, m.commit,
|
||||
);
|
||||
cancel_tx_log_entry(wallet, &o)?;
|
||||
let mut batch = wallet.batch()?;
|
||||
cancel_tx_log_entry(wallet, keychain_mask, &o)?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.delete(&o.key_id, &o.mmr_index)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
|
@ -400,10 +418,10 @@ where
|
|||
// default path already exists
|
||||
if *path != ExtKeychain::derive_key_id(2, 0, 0, 0, 0) {
|
||||
let label = format!("{}_{}", label_base, acct_index);
|
||||
keys::set_acct_path(wallet, &label, path)?;
|
||||
keys::set_acct_path(wallet, keychain_mask, &label, path)?;
|
||||
acct_index += 1;
|
||||
}
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
debug!("Next child for account {} is {}", path, max_child_index + 1);
|
||||
batch.save_child_index(path, max_child_index + 1)?;
|
||||
batch.commit()?;
|
||||
|
@ -412,7 +430,7 @@ where
|
|||
}
|
||||
|
||||
/// Restore a wallet
|
||||
pub fn restore<'a, T, C, K>(wallet: &mut T) -> Result<(), Error>
|
||||
pub fn restore<'a, T, C, K>(wallet: &mut T, keychain_mask: Option<&SecretKey>) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -428,7 +446,7 @@ where
|
|||
let now = Instant::now();
|
||||
warn!("Starting restore.");
|
||||
|
||||
let result_vec = collect_chain_outputs(wallet)?;
|
||||
let result_vec = collect_chain_outputs(wallet, keychain_mask)?;
|
||||
|
||||
warn!(
|
||||
"Identified {} wallet_outputs as belonging to this wallet",
|
||||
|
@ -442,6 +460,7 @@ where
|
|||
for output in result_vec {
|
||||
restore_missing_output(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
output,
|
||||
&mut found_parents,
|
||||
&mut Some(&mut restore_stats),
|
||||
|
@ -455,12 +474,12 @@ where
|
|||
// default path already exists
|
||||
if *path != ExtKeychain::derive_key_id(2, 0, 0, 0, 0) {
|
||||
let label = format!("{}_{}", label_base, acct_index);
|
||||
keys::set_acct_path(wallet, &label, path)?;
|
||||
keys::set_acct_path(wallet, keychain_mask, &label, path)?;
|
||||
acct_index += 1;
|
||||
}
|
||||
// restore tx log entry for non-coinbase outputs
|
||||
if let Some(s) = restore_stats.get(path) {
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
let mut t = TxLogEntry::new(path.clone(), TxLogEntryType::TxReceived, s.log_id);
|
||||
t.confirmed = true;
|
||||
t.amount_credited = s.amount_credited;
|
||||
|
@ -469,7 +488,7 @@ where
|
|||
batch.save_tx_log_entry(t, &path)?;
|
||||
batch.commit()?;
|
||||
}
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.save_child_index(path, max_child_index + 1)?;
|
||||
debug!("Next child for account {} is {}", path, max_child_index + 1);
|
||||
batch.commit()?;
|
||||
|
|
|
@ -22,6 +22,7 @@ use crate::grin_core::libtx::{
|
|||
tx_fee,
|
||||
};
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::internal::keys;
|
||||
use crate::slate::Slate;
|
||||
use crate::types::*;
|
||||
|
@ -34,6 +35,8 @@ use std::collections::HashMap;
|
|||
|
||||
pub fn build_send_tx<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain: &K,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &mut Slate,
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
|
@ -49,6 +52,7 @@ where
|
|||
{
|
||||
let (elems, inputs, change_amounts_derivations, fee) = select_send_tx(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
slate.amount,
|
||||
slate.height,
|
||||
minimum_confirmations,
|
||||
|
@ -58,7 +62,6 @@ where
|
|||
selection_strategy_is_use_all,
|
||||
&parent_key_id,
|
||||
)?;
|
||||
let keychain = wallet.keychain()?;
|
||||
let blinding = slate.add_transaction_elements(keychain, &ProofBuilder::new(keychain), elems)?;
|
||||
|
||||
slate.fee = fee;
|
||||
|
@ -86,7 +89,7 @@ where
|
|||
context.add_output(&id, &mmr_index, *change_amount);
|
||||
commits.insert(
|
||||
id.clone(),
|
||||
wallet.calc_commit_for_cache(*change_amount, &id)?,
|
||||
wallet.calc_commit_for_cache(keychain_mask, *change_amount, &id)?,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -97,6 +100,7 @@ where
|
|||
/// change outputs and tx log entry
|
||||
pub fn lock_tx_context<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
context: &Context,
|
||||
) -> Result<(), Error>
|
||||
|
@ -111,7 +115,7 @@ where
|
|||
output_commits.insert(
|
||||
id.clone(),
|
||||
(
|
||||
wallet.calc_commit_for_cache(*change_amount, &id)?,
|
||||
wallet.calc_commit_for_cache(keychain_mask, *change_amount, &id)?,
|
||||
*change_amount,
|
||||
),
|
||||
);
|
||||
|
@ -123,7 +127,7 @@ where
|
|||
let slate_id = slate.id;
|
||||
let height = slate.height;
|
||||
let parent_key_id = context.parent_key_id.clone();
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
let log_id = batch.next_tx_log_id(&parent_key_id)?;
|
||||
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxSent, log_id);
|
||||
t.tx_slate_id = Some(slate_id.clone());
|
||||
|
@ -174,6 +178,7 @@ where
|
|||
/// Also creates a new transaction containing the output
|
||||
pub fn build_recipient_output<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &mut Slate,
|
||||
parent_key_id: Identifier,
|
||||
use_test_rng: bool,
|
||||
|
@ -184,8 +189,8 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
// Create a potential output for this transaction
|
||||
let key_id = keys::next_available_key(wallet).unwrap();
|
||||
let keychain = wallet.keychain()?.clone();
|
||||
let key_id = keys::next_available_key(wallet, keychain_mask).unwrap();
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
let key_id_inner = key_id.clone();
|
||||
let amount = slate.amount;
|
||||
let height = slate.height;
|
||||
|
@ -201,7 +206,7 @@ where
|
|||
let mut context = Context::new(
|
||||
keychain.secp(),
|
||||
blinding
|
||||
.secret_key(wallet.keychain()?.clone().secp())
|
||||
.secret_key(wallet.keychain(keychain_mask)?.secp())
|
||||
.unwrap(),
|
||||
&parent_key_id,
|
||||
use_test_rng,
|
||||
|
@ -210,8 +215,8 @@ where
|
|||
|
||||
context.add_output(&key_id, &None, amount);
|
||||
let messages = Some(slate.participant_messages());
|
||||
let commit = wallet.calc_commit_for_cache(amount, &key_id_inner)?;
|
||||
let mut batch = wallet.batch()?;
|
||||
let commit = wallet.calc_commit_for_cache(keychain_mask, amount, &key_id_inner)?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
let log_id = batch.next_tx_log_id(&parent_key_id)?;
|
||||
let mut t = TxLogEntry::new(parent_key_id.clone(), TxLogEntryType::TxReceived, log_id);
|
||||
t.tx_slate_id = Some(slate_id);
|
||||
|
@ -242,6 +247,7 @@ where
|
|||
/// selecting outputs to spend and building the change.
|
||||
pub fn select_send_tx<'a, T: ?Sized, C, K, B>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
amount: u64,
|
||||
current_height: u64,
|
||||
minimum_confirmations: u64,
|
||||
|
@ -278,7 +284,7 @@ where
|
|||
|
||||
// build transaction skeleton with inputs and change
|
||||
let (mut parts, change_amounts_derivations) =
|
||||
inputs_and_change(&coins, wallet, amount, fee, change_outputs)?;
|
||||
inputs_and_change(&coins, wallet, keychain_mask, amount, fee, change_outputs)?;
|
||||
|
||||
// This is more proof of concept than anything but here we set lock_height
|
||||
// on tx being sent (based on current chain height via api).
|
||||
|
@ -396,6 +402,7 @@ where
|
|||
pub fn inputs_and_change<'a, T: ?Sized, C, K, B>(
|
||||
coins: &Vec<OutputData>,
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
amount: u64,
|
||||
fee: u64,
|
||||
num_change_outputs: usize,
|
||||
|
@ -454,7 +461,7 @@ where
|
|||
part_change
|
||||
};
|
||||
|
||||
let change_key = wallet.next_child().unwrap();
|
||||
let change_key = wallet.next_child(keychain_mask).unwrap();
|
||||
|
||||
change_amounts_derivations.push((change_amount, change_key.clone(), None));
|
||||
parts.push(build::output(change_amount, change_key));
|
||||
|
|
|
@ -19,6 +19,7 @@ use uuid::Uuid;
|
|||
use crate::grin_core::consensus::valid_header_version;
|
||||
use crate::grin_core::core::HeaderVersion;
|
||||
use crate::grin_keychain::{Identifier, Keychain};
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::grin_util::Mutex;
|
||||
use crate::internal::{selection, updater};
|
||||
use crate::slate::Slate;
|
||||
|
@ -70,6 +71,7 @@ where
|
|||
/// Estimates locked amount and fee for the transaction without creating one
|
||||
pub fn estimate_send_tx<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
amount: u64,
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
|
@ -91,7 +93,7 @@ where
|
|||
// Get lock height
|
||||
let current_height = wallet.w2n_client().get_chain_height()?;
|
||||
// ensure outputs we're selecting are up to date
|
||||
updater::refresh_outputs(wallet, parent_key_id, false)?;
|
||||
updater::refresh_outputs(wallet, keychain_mask, parent_key_id, false)?;
|
||||
|
||||
// Sender selects outputs into a new slate and save our corresponding keys in
|
||||
// a transaction context. The secret key in our transaction context will be
|
||||
|
@ -116,6 +118,7 @@ where
|
|||
/// Add inputs to the slate (effectively becoming the sender)
|
||||
pub fn add_inputs_to_slate<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &mut Slate,
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
|
@ -133,7 +136,7 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
// sender should always refresh outputs
|
||||
updater::refresh_outputs(wallet, parent_key_id, false)?;
|
||||
updater::refresh_outputs(wallet, keychain_mask, parent_key_id, false)?;
|
||||
|
||||
// Sender selects outputs into a new slate and save our corresponding keys in
|
||||
// a transaction context. The secret key in our transaction context will be
|
||||
|
@ -144,6 +147,8 @@ where
|
|||
// this process can be split up in any way
|
||||
let mut context = selection::build_send_tx(
|
||||
wallet,
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
keychain_mask,
|
||||
slate,
|
||||
minimum_confirmations,
|
||||
max_outputs,
|
||||
|
@ -157,7 +162,7 @@ where
|
|||
// the offset in the slate's transaction kernel, and adds our public key
|
||||
// information to the slate
|
||||
let _ = slate.fill_round_1(
|
||||
wallet.keychain()?,
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
&mut context.sec_key,
|
||||
&context.sec_nonce,
|
||||
participant_id,
|
||||
|
@ -168,7 +173,7 @@ where
|
|||
if !is_initator {
|
||||
// perform partial sig
|
||||
let _ = slate.fill_round_2(
|
||||
wallet.keychain()?,
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
&context.sec_key,
|
||||
&context.sec_nonce,
|
||||
participant_id,
|
||||
|
@ -181,6 +186,7 @@ where
|
|||
/// Add receiver output to the slate
|
||||
pub fn add_output_to_slate<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &mut Slate,
|
||||
parent_key_id: &Identifier,
|
||||
participant_id: usize,
|
||||
|
@ -194,12 +200,17 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
// create an output using the amount in the slate
|
||||
let (_, mut context) =
|
||||
selection::build_recipient_output(wallet, slate, parent_key_id.clone(), use_test_rng)?;
|
||||
let (_, mut context) = selection::build_recipient_output(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
slate,
|
||||
parent_key_id.clone(),
|
||||
use_test_rng,
|
||||
)?;
|
||||
|
||||
// fill public keys
|
||||
let _ = slate.fill_round_1(
|
||||
wallet.keychain()?,
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
&mut context.sec_key,
|
||||
&context.sec_nonce,
|
||||
1,
|
||||
|
@ -210,7 +221,7 @@ where
|
|||
if !is_initiator {
|
||||
// perform partial sig
|
||||
let _ = slate.fill_round_2(
|
||||
wallet.keychain()?,
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
&context.sec_key,
|
||||
&context.sec_nonce,
|
||||
participant_id,
|
||||
|
@ -223,6 +234,7 @@ where
|
|||
/// Complete a transaction
|
||||
pub fn complete_tx<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &mut Slate,
|
||||
participant_id: usize,
|
||||
context: &Context,
|
||||
|
@ -233,20 +245,21 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
let _ = slate.fill_round_2(
|
||||
wallet.keychain()?,
|
||||
&wallet.keychain(keychain_mask)?,
|
||||
&context.sec_key,
|
||||
&context.sec_nonce,
|
||||
participant_id,
|
||||
)?;
|
||||
|
||||
// Final transaction can be built by anyone at this stage
|
||||
slate.finalize(wallet.keychain()?)?;
|
||||
slate.finalize(&wallet.keychain(keychain_mask)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Rollback outputs associated with a transaction in the wallet
|
||||
pub fn cancel_tx<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
parent_key_id: &Identifier,
|
||||
tx_id: Option<u32>,
|
||||
tx_slate_id: Option<Uuid>,
|
||||
|
@ -274,9 +287,15 @@ where
|
|||
return Err(ErrorKind::TransactionNotCancellable(tx_id_string))?;
|
||||
}
|
||||
// get outputs associated with tx
|
||||
let res = updater::retrieve_outputs(wallet, false, Some(tx.id), Some(&parent_key_id))?;
|
||||
let res = updater::retrieve_outputs(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
false,
|
||||
Some(tx.id),
|
||||
Some(&parent_key_id),
|
||||
)?;
|
||||
let outputs = res.iter().map(|m| m.output.clone()).collect();
|
||||
updater::cancel_tx_and_outputs(wallet, tx, outputs, parent_key_id)?;
|
||||
updater::cancel_tx_and_outputs(wallet, keychain_mask, tx, outputs, parent_key_id)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -314,7 +333,11 @@ where
|
|||
}
|
||||
|
||||
/// Update the transaction participant messages
|
||||
pub fn update_message<'a, T: ?Sized, C, K>(wallet: &mut T, slate: &Slate) -> Result<(), Error>
|
||||
pub fn update_message<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate: &Slate,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -324,7 +347,7 @@ where
|
|||
if tx_vec.is_empty() {
|
||||
return Err(ErrorKind::TransactionDoesntExist(slate.id.to_string()))?;
|
||||
}
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
for mut tx in tx_vec.into_iter() {
|
||||
tx.messages = Some(slate.participant_messages());
|
||||
let parent_key = tx.parent_key_id.clone();
|
||||
|
|
|
@ -26,6 +26,7 @@ use crate::grin_core::libtx::proof::ProofBuilder;
|
|||
use crate::grin_core::libtx::reward;
|
||||
use crate::grin_keychain::{Identifier, Keychain, SwitchCommitmentType};
|
||||
use crate::grin_util as util;
|
||||
use crate::grin_util::secp::key::SecretKey;
|
||||
use crate::grin_util::secp::pedersen;
|
||||
use crate::internal::keys;
|
||||
use crate::types::{
|
||||
|
@ -36,6 +37,7 @@ use crate::{BlockFees, CbData, OutputCommitMapping};
|
|||
/// Retrieve all of the outputs (doesn't attempt to update from node)
|
||||
pub fn retrieve_outputs<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
show_spent: bool,
|
||||
tx_id: Option<u32>,
|
||||
parent_key_id: Option<&Identifier>,
|
||||
|
@ -68,7 +70,7 @@ where
|
|||
}
|
||||
|
||||
outputs.sort_by_key(|out| out.n_child);
|
||||
let keychain = wallet.keychain()?.clone();
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
|
||||
let res = outputs
|
||||
.into_iter()
|
||||
|
@ -133,6 +135,7 @@ where
|
|||
/// from a node
|
||||
pub fn refresh_outputs<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
parent_key_id: &Identifier,
|
||||
update_all: bool,
|
||||
) -> Result<(), Error>
|
||||
|
@ -142,7 +145,7 @@ where
|
|||
K: Keychain + 'a,
|
||||
{
|
||||
let height = wallet.w2n_client().get_chain_height()?;
|
||||
refresh_output_state(wallet, height, parent_key_id, update_all)?;
|
||||
refresh_output_state(wallet, keychain_mask, height, parent_key_id, update_all)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -150,6 +153,7 @@ where
|
|||
/// and a list of outputs we want to query the node for
|
||||
pub fn map_wallet_outputs<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
parent_key_id: &Identifier,
|
||||
update_all: bool,
|
||||
) -> Result<HashMap<pedersen::Commitment, (Identifier, Option<u64>)>, Error>
|
||||
|
@ -160,7 +164,7 @@ where
|
|||
{
|
||||
let mut wallet_outputs: HashMap<pedersen::Commitment, (Identifier, Option<u64>)> =
|
||||
HashMap::new();
|
||||
let keychain = wallet.keychain()?.clone();
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
let unspents: Vec<OutputData> = wallet
|
||||
.iter()
|
||||
.filter(|x| x.root_key_id == *parent_key_id && x.status != OutputStatus::Spent)
|
||||
|
@ -201,6 +205,7 @@ where
|
|||
/// Cancel transaction and associated outputs
|
||||
pub fn cancel_tx_and_outputs<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
tx: TxLogEntry,
|
||||
outputs: Vec<OutputData>,
|
||||
parent_key_id: &Identifier,
|
||||
|
@ -210,7 +215,7 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
|
||||
for mut o in outputs {
|
||||
// unlock locked outputs
|
||||
|
@ -237,6 +242,7 @@ where
|
|||
/// Apply refreshed API output data to the wallet
|
||||
pub fn apply_api_outputs<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
wallet_outputs: &HashMap<pedersen::Commitment, (Identifier, Option<u64>)>,
|
||||
api_outputs: &HashMap<pedersen::Commitment, (String, u64, u64)>,
|
||||
height: u64,
|
||||
|
@ -262,7 +268,7 @@ where
|
|||
warn!("Please wait for sync on node to complete or fork to resolve and try again.");
|
||||
return Ok(());
|
||||
}
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
for (commit, (id, mmr_index)) in wallet_outputs.iter() {
|
||||
if let Ok(mut output) = batch.get(id, mmr_index) {
|
||||
match api_outputs.get(&commit) {
|
||||
|
@ -317,6 +323,7 @@ where
|
|||
/// So we can refresh the local wallet outputs.
|
||||
fn refresh_output_state<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
height: u64,
|
||||
parent_key_id: &Identifier,
|
||||
update_all: bool,
|
||||
|
@ -330,19 +337,30 @@ where
|
|||
|
||||
// build a local map of wallet outputs keyed by commit
|
||||
// and a list of outputs we want to query the node for
|
||||
let wallet_outputs = map_wallet_outputs(wallet, parent_key_id, update_all)?;
|
||||
let wallet_outputs = map_wallet_outputs(wallet, keychain_mask, parent_key_id, update_all)?;
|
||||
|
||||
let wallet_output_keys = wallet_outputs.keys().map(|commit| commit.clone()).collect();
|
||||
|
||||
let api_outputs = wallet
|
||||
.w2n_client()
|
||||
.get_outputs_from_node(wallet_output_keys)?;
|
||||
apply_api_outputs(wallet, &wallet_outputs, &api_outputs, height, parent_key_id)?;
|
||||
clean_old_unconfirmed(wallet, height)?;
|
||||
apply_api_outputs(
|
||||
wallet,
|
||||
keychain_mask,
|
||||
&wallet_outputs,
|
||||
&api_outputs,
|
||||
height,
|
||||
parent_key_id,
|
||||
)?;
|
||||
clean_old_unconfirmed(wallet, keychain_mask, height)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn clean_old_unconfirmed<'a, T: ?Sized, C, K>(wallet: &mut T, height: u64) -> Result<(), Error>
|
||||
fn clean_old_unconfirmed<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
height: u64,
|
||||
) -> Result<(), Error>
|
||||
where
|
||||
T: WalletBackend<'a, C, K>,
|
||||
C: NodeClient + 'a,
|
||||
|
@ -361,7 +379,7 @@ where
|
|||
ids_to_del.push(out.key_id.clone())
|
||||
}
|
||||
}
|
||||
let mut batch = wallet.batch()?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
for id in ids_to_del {
|
||||
batch.delete(&id, &None)?;
|
||||
}
|
||||
|
@ -436,6 +454,7 @@ where
|
|||
/// Build a coinbase output and insert into wallet
|
||||
pub fn build_coinbase<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
block_fees: &BlockFees,
|
||||
test_mode: bool,
|
||||
) -> Result<CbData, Error>
|
||||
|
@ -444,7 +463,7 @@ where
|
|||
C: NodeClient + 'a,
|
||||
K: Keychain + 'a,
|
||||
{
|
||||
let (out, kern, block_fees) = receive_coinbase(wallet, block_fees, test_mode)?;
|
||||
let (out, kern, block_fees) = receive_coinbase(wallet, keychain_mask, block_fees, test_mode)?;
|
||||
|
||||
Ok(CbData {
|
||||
output: out,
|
||||
|
@ -457,6 +476,7 @@ where
|
|||
/// Build a coinbase output and the corresponding kernel
|
||||
pub fn receive_coinbase<'a, T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
block_fees: &BlockFees,
|
||||
test_mode: bool,
|
||||
) -> Result<(Output, TxKernel, BlockFees), Error>
|
||||
|
@ -473,16 +493,16 @@ where
|
|||
let key_id = match key_id {
|
||||
Some(key_id) => match keys::retrieve_existing_key(wallet, key_id, None) {
|
||||
Ok(k) => k.0,
|
||||
Err(_) => keys::next_available_key(wallet)?,
|
||||
Err(_) => keys::next_available_key(wallet, keychain_mask)?,
|
||||
},
|
||||
None => keys::next_available_key(wallet)?,
|
||||
None => keys::next_available_key(wallet, keychain_mask)?,
|
||||
};
|
||||
|
||||
{
|
||||
// Now acquire the wallet lock and write the new output.
|
||||
let amount = reward(block_fees.fees);
|
||||
let commit = wallet.calc_commit_for_cache(amount, &key_id)?;
|
||||
let mut batch = wallet.batch()?;
|
||||
let commit = wallet.calc_commit_for_cache(keychain_mask, amount, &key_id)?;
|
||||
let mut batch = wallet.batch(keychain_mask)?;
|
||||
batch.save(OutputData {
|
||||
root_key_id: parent_key_id,
|
||||
key_id: key_id.clone(),
|
||||
|
@ -510,10 +530,10 @@ where
|
|||
|
||||
debug!("receive_coinbase: {:?}", block_fees);
|
||||
|
||||
let keychain = wallet.keychain()?;
|
||||
let keychain = wallet.keychain(keychain_mask)?;
|
||||
let (out, kern) = reward::output(
|
||||
keychain,
|
||||
&ProofBuilder::new(keychain),
|
||||
&keychain,
|
||||
&ProofBuilder::new(&keychain),
|
||||
&key_id,
|
||||
block_fees.fees,
|
||||
test_mode,
|
||||
|
|
|
@ -67,7 +67,13 @@ where
|
|||
) -> Result<(), Error>;
|
||||
|
||||
///
|
||||
fn open_wallet(&mut self, name: Option<&str>, password: ZeroingString) -> Result<(), Error>;
|
||||
fn open_wallet(
|
||||
&mut self,
|
||||
name: Option<&str>,
|
||||
password: ZeroingString,
|
||||
create_mask: bool,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Option<SecretKey>, Error>;
|
||||
|
||||
///
|
||||
fn close_wallet(&mut self, name: Option<&str>) -> Result<(), Error>;
|
||||
|
@ -113,13 +119,22 @@ where
|
|||
K: Keychain + 'ck,
|
||||
{
|
||||
/// Set the keychain, which should already be initialized
|
||||
fn set_keychain(&mut self, k: Box<K>);
|
||||
/// Optionally return a token value used to XOR the stored
|
||||
/// key value
|
||||
fn set_keychain(
|
||||
&mut self,
|
||||
k: Box<K>,
|
||||
mask: bool,
|
||||
use_test_rng: bool,
|
||||
) -> Result<Option<SecretKey>, Error>;
|
||||
|
||||
/// Close wallet and remove any stored credentials (TBD)
|
||||
fn close(&mut self) -> Result<(), Error>;
|
||||
|
||||
/// Return the keychain being used
|
||||
fn keychain(&mut self) -> Result<&mut K, Error>;
|
||||
/// Return the keychain being used. Ensure a cloned copy so it will be dropped
|
||||
/// and zeroized by the caller
|
||||
/// Can optionally take a mask value
|
||||
fn keychain(&self, mask: Option<&SecretKey>) -> Result<K, Error>;
|
||||
|
||||
/// Return the client being used to communicate with the node
|
||||
fn w2n_client(&mut self) -> &mut C;
|
||||
|
@ -127,6 +142,7 @@ where
|
|||
/// return the commit for caching if allowed, none otherwise
|
||||
fn calc_commit_for_cache(
|
||||
&mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
amount: u64,
|
||||
id: &Identifier,
|
||||
) -> Result<Option<String>, Error>;
|
||||
|
@ -153,6 +169,7 @@ where
|
|||
/// Retrieves the private context associated with a given slate id
|
||||
fn get_private_context(
|
||||
&mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
slate_id: &[u8],
|
||||
participant_id: usize,
|
||||
) -> Result<Context, Error>;
|
||||
|
@ -173,19 +190,26 @@ where
|
|||
fn get_stored_tx(&self, entry: &TxLogEntry) -> Result<Option<Transaction>, Error>;
|
||||
|
||||
/// Create a new write batch to update or remove output data
|
||||
fn batch<'a>(&'a mut self) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error>;
|
||||
fn batch<'a>(
|
||||
&'a mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
) -> Result<Box<dyn WalletOutputBatch<K> + 'a>, Error>;
|
||||
|
||||
/// Next child ID when we want to create a new output, based on current parent
|
||||
fn next_child<'a>(&mut self) -> Result<Identifier, Error>;
|
||||
fn next_child<'a>(&mut self, keychain_mask: Option<&SecretKey>) -> Result<Identifier, Error>;
|
||||
|
||||
/// last verified height of outputs directly descending from the given parent key
|
||||
fn last_confirmed_height<'a>(&mut self) -> Result<u64, Error>;
|
||||
|
||||
/// Attempt to restore the contents of a wallet from seed
|
||||
fn restore(&mut self) -> Result<(), Error>;
|
||||
fn restore(&mut self, keychain_mask: Option<&SecretKey>) -> Result<(), Error>;
|
||||
|
||||
/// Attempt to check and fix wallet state
|
||||
fn check_repair(&mut self, delete_unconfirmed: bool) -> Result<(), Error>;
|
||||
fn check_repair(
|
||||
&mut self,
|
||||
keychain_mask: Option<&SecretKey>,
|
||||
delete_unconfirmed: bool,
|
||||
) -> Result<(), Error>;
|
||||
}
|
||||
|
||||
/// Batch trait to update the output data backend atomically. Trying to use a
|
||||
|
|
|
@ -806,19 +806,27 @@ where
|
|||
}
|
||||
|
||||
// don't open wallet for certain lifecycle commands
|
||||
match wallet_args.subcommand() {
|
||||
("init", Some(_)) => {}
|
||||
("recover", _) => {}
|
||||
let keychain_mask = match wallet_args.subcommand() {
|
||||
("init", Some(_)) => None,
|
||||
("recover", _) => None,
|
||||
_ => {
|
||||
let mut wallet_lock = wallet.lock();
|
||||
let lc = wallet_lock.lc_provider().unwrap();
|
||||
lc.open_wallet(None, prompt_password(&global_wallet_args.password))?;
|
||||
let mask = lc.open_wallet(
|
||||
None,
|
||||
prompt_password(&global_wallet_args.password),
|
||||
true,
|
||||
false,
|
||||
)?;
|
||||
if let Some(account) = wallet_args.value_of("account") {
|
||||
let wallet_inst = lc.wallet_inst()?;
|
||||
wallet_inst.set_parent_key_id_by_name(account)?;
|
||||
}
|
||||
mask
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let km = (&keychain_mask).as_ref();
|
||||
|
||||
let res = match wallet_args.subcommand() {
|
||||
("init", Some(args)) => {
|
||||
|
@ -841,42 +849,46 @@ where
|
|||
("listen", Some(args)) => {
|
||||
let mut c = wallet_config.clone();
|
||||
let a = arg_parse!(parse_listen_args(&mut c, &args));
|
||||
command::listen(wallet, &c, &a, &global_wallet_args.clone())
|
||||
command::listen(wallet, keychain_mask, &c, &a, &global_wallet_args.clone())
|
||||
}
|
||||
("owner_api", Some(_)) => {
|
||||
let mut g = global_wallet_args.clone();
|
||||
g.tls_conf = None;
|
||||
command::owner_api(wallet, &wallet_config, &g)
|
||||
command::owner_api(wallet, keychain_mask, &wallet_config, &g)
|
||||
}
|
||||
("web", Some(_)) => {
|
||||
command::owner_api(wallet, keychain_mask, &wallet_config, &global_wallet_args)
|
||||
}
|
||||
("web", Some(_)) => command::owner_api(wallet, &wallet_config, &global_wallet_args),
|
||||
("account", Some(args)) => {
|
||||
let a = arg_parse!(parse_account_args(&args));
|
||||
command::account(wallet, a)
|
||||
command::account(wallet, km, a)
|
||||
}
|
||||
("send", Some(args)) => {
|
||||
let a = arg_parse!(parse_send_args(&args));
|
||||
command::send(
|
||||
wallet,
|
||||
km,
|
||||
a,
|
||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||
)
|
||||
}
|
||||
("receive", Some(args)) => {
|
||||
let a = arg_parse!(parse_receive_args(&args));
|
||||
command::receive(wallet, &global_wallet_args, a)
|
||||
command::receive(wallet, km, &global_wallet_args, a)
|
||||
}
|
||||
("finalize", Some(args)) => {
|
||||
let a = arg_parse!(parse_finalize_args(&args));
|
||||
command::finalize(wallet, a)
|
||||
command::finalize(wallet, km, a)
|
||||
}
|
||||
("invoice", Some(args)) => {
|
||||
let a = arg_parse!(parse_issue_invoice_args(&args));
|
||||
command::issue_invoice_tx(wallet, a)
|
||||
command::issue_invoice_tx(wallet, km, a)
|
||||
}
|
||||
("pay", Some(args)) => {
|
||||
let a = arg_parse!(parse_process_invoice_args(&args));
|
||||
command::process_invoice(
|
||||
wallet,
|
||||
km,
|
||||
a,
|
||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||
)
|
||||
|
@ -885,6 +897,7 @@ where
|
|||
let a = arg_parse!(parse_info_args(&args));
|
||||
command::info(
|
||||
wallet,
|
||||
km,
|
||||
&global_wallet_args,
|
||||
a,
|
||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||
|
@ -892,6 +905,7 @@ where
|
|||
}
|
||||
("outputs", Some(_)) => command::outputs(
|
||||
wallet,
|
||||
km,
|
||||
&global_wallet_args,
|
||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||
),
|
||||
|
@ -899,6 +913,7 @@ where
|
|||
let a = arg_parse!(parse_txs_args(&args));
|
||||
command::txs(
|
||||
wallet,
|
||||
km,
|
||||
&global_wallet_args,
|
||||
a,
|
||||
wallet_config.dark_background_color_scheme.unwrap_or(true),
|
||||
|
@ -906,16 +921,16 @@ where
|
|||
}
|
||||
("repost", Some(args)) => {
|
||||
let a = arg_parse!(parse_repost_args(&args));
|
||||
command::repost(wallet, a)
|
||||
command::repost(wallet, km, a)
|
||||
}
|
||||
("cancel", Some(args)) => {
|
||||
let a = arg_parse!(parse_cancel_args(&args));
|
||||
command::cancel(wallet, a)
|
||||
command::cancel(wallet, km, a)
|
||||
}
|
||||
("restore", Some(_)) => command::restore(wallet),
|
||||
("restore", Some(_)) => command::restore(wallet, km),
|
||||
("check", Some(args)) => {
|
||||
let a = arg_parse!(parse_check_args(&args));
|
||||
command::check_repair(wallet, a)
|
||||
command::check_repair(wallet, km, a)
|
||||
}
|
||||
_ => {
|
||||
let msg = format!("Unknown wallet command, use 'grin help wallet' for details");
|
||||
|
|
|
@ -32,6 +32,7 @@ mod wallet_tests {
|
|||
use grin_wallet_libwallet::WalletInst;
|
||||
use grin_wallet_util::grin_core::global::{self, ChainTypes};
|
||||
use grin_wallet_util::grin_keychain::ExtKeychain;
|
||||
use util::secp::key::SecretKey;
|
||||
|
||||
use super::super::wallet_args;
|
||||
|
||||
|
@ -123,18 +124,21 @@ mod wallet_tests {
|
|||
passphrase: &str,
|
||||
account: &str,
|
||||
) -> Result<
|
||||
Arc<
|
||||
Mutex<
|
||||
Box<
|
||||
WalletInst<
|
||||
'static,
|
||||
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
(
|
||||
Arc<
|
||||
Mutex<
|
||||
Box<
|
||||
WalletInst<
|
||||
'static,
|
||||
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
|
||||
LocalWalletClient,
|
||||
ExtKeychain,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
Option<SecretKey>,
|
||||
),
|
||||
grin_wallet_controller::Error,
|
||||
> {
|
||||
wallet_config.chain_type = None;
|
||||
|
@ -156,11 +160,12 @@ mod wallet_tests {
|
|||
wallet_config.data_file_dir = top_level_wallet_dir.to_str().unwrap().into();
|
||||
}
|
||||
lc.set_wallet_directory(&wallet_config.data_file_dir);
|
||||
lc.open_wallet(None, ZeroingString::from(passphrase))
|
||||
let keychain_mask = lc
|
||||
.open_wallet(None, ZeroingString::from(passphrase), true, false)
|
||||
.unwrap();
|
||||
let wallet_inst = lc.wallet_inst()?;
|
||||
wallet_inst.set_parent_key_id_by_name(account)?;
|
||||
Ok(Arc::new(Mutex::new(wallet)))
|
||||
Ok((Arc::new(Mutex::new(wallet)), keychain_mask))
|
||||
}
|
||||
|
||||
fn execute_command(
|
||||
|
@ -206,16 +211,28 @@ mod wallet_tests {
|
|||
// add wallet to proxy
|
||||
//let wallet1 = test_framework::create_wallet(&format!("{}/wallet1", test_dir), client1.clone());
|
||||
let config1 = initial_setup_wallet(test_dir, "wallet1");
|
||||
let wallet1 = instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
wallet_proxy.add_wallet("wallet1", client1.get_send_instance(), wallet1.clone());
|
||||
let (wallet1, mask1_i) =
|
||||
instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
wallet_proxy.add_wallet(
|
||||
"wallet1",
|
||||
client1.get_send_instance(),
|
||||
wallet1.clone(),
|
||||
mask1_i.clone(),
|
||||
);
|
||||
|
||||
// Create wallet 2
|
||||
let client2 = LocalWalletClient::new("wallet2", wallet_proxy.tx.clone());
|
||||
execute_command(&app, test_dir, "wallet2", &client2, arg_vec.clone())?;
|
||||
|
||||
let config2 = initial_setup_wallet(test_dir, "wallet2");
|
||||
let wallet2 = instantiate_wallet(config2.clone(), client2.clone(), "password", "default")?;
|
||||
wallet_proxy.add_wallet("wallet2", client2.get_send_instance(), wallet2.clone());
|
||||
let (wallet2, mask2_i) =
|
||||
instantiate_wallet(config2.clone(), client2.clone(), "password", "default")?;
|
||||
wallet_proxy.add_wallet(
|
||||
"wallet2",
|
||||
client2.get_send_instance(),
|
||||
wallet2.clone(),
|
||||
mask2_i.clone(),
|
||||
);
|
||||
|
||||
// Set the wallet proxy listener running
|
||||
thread::spawn(move || {
|
||||
|
@ -271,14 +288,22 @@ mod wallet_tests {
|
|||
|
||||
// Mine a bit into wallet 1 so we have something to send
|
||||
// (TODO: Be able to stop listeners so we can test this better)
|
||||
let wallet1 = instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.set_active_account("mining")?;
|
||||
let (wallet1, mask1_i) =
|
||||
instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.set_active_account(m, "mining")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let mut bh = 10u64;
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), bh as usize, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(
|
||||
&chain,
|
||||
wallet1.clone(),
|
||||
mask1,
|
||||
bh as usize,
|
||||
false,
|
||||
);
|
||||
|
||||
let very_long_message = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
|
||||
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef\
|
||||
|
@ -342,18 +367,20 @@ mod wallet_tests {
|
|||
execute_command(&app, test_dir, "wallet1", &client1, arg_vec)?;
|
||||
bh += 1;
|
||||
|
||||
let wallet1 = instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let (wallet1, mask1_i) =
|
||||
instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
|
||||
// Check our transaction log, should have 10 entries
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.set_active_account("mining")?;
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.set_active_account(m, "mining")?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
assert_eq!(txs.len(), bh as usize);
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 10, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 10, false);
|
||||
bh += 10;
|
||||
|
||||
// update info for each
|
||||
|
@ -364,10 +391,13 @@ mod wallet_tests {
|
|||
execute_command(&app, test_dir, "wallet2", &client1, arg_vec)?;
|
||||
|
||||
// check results in wallet 2
|
||||
let wallet2 = instantiate_wallet(config2.clone(), client2.clone(), "password", "default")?;
|
||||
grin_wallet_controller::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.set_active_account("account_1")?;
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(true, 1)?;
|
||||
let (wallet2, mask2_i) =
|
||||
instantiate_wallet(config2.clone(), client2.clone(), "password", "default")?;
|
||||
let mask2 = (&mask2_i).as_ref();
|
||||
|
||||
grin_wallet_controller::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
api.set_active_account(m, "account_1")?;
|
||||
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
|
||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||
assert_eq!(wallet1_info.amount_currently_spendable, 10_000_000_000);
|
||||
Ok(())
|
||||
|
@ -419,11 +449,13 @@ mod wallet_tests {
|
|||
bh += 1;
|
||||
|
||||
// Check our transaction log, should have bh entries + one for the self receive
|
||||
let wallet1 = instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let (wallet1, mask1_i) =
|
||||
instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.set_active_account("mining")?;
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.set_active_account(m, "mining")?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
assert_eq!(txs.len(), bh as usize + 1);
|
||||
Ok(())
|
||||
|
@ -453,11 +485,13 @@ mod wallet_tests {
|
|||
bh += 1;
|
||||
|
||||
// Check our transaction log, should have bh entries + 2 for the self receives
|
||||
let wallet1 = instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let (wallet1, mask1_i) =
|
||||
instantiate_wallet(config1.clone(), client1.clone(), "password", "default")?;
|
||||
let mask1 = (&mask1_i).as_ref();
|
||||
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.set_active_account("mining")?;
|
||||
let (refreshed, txs) = api.retrieve_txs(true, None, None)?;
|
||||
grin_wallet_controller::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
|
||||
api.set_active_account(m, "mining")?;
|
||||
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
assert!(refreshed);
|
||||
assert_eq!(txs.len(), bh as usize + 2);
|
||||
Ok(())
|
||||
|
@ -559,7 +593,7 @@ mod wallet_tests {
|
|||
execute_command(&app, test_dir, "wallet2", &client2, arg_vec)?;
|
||||
|
||||
// bit more mining
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 5, false);
|
||||
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 5, false);
|
||||
//bh += 5;
|
||||
|
||||
// txs and outputs (mostly spit out for a visual in test logs)
|
||||
|
@ -591,9 +625,9 @@ mod wallet_tests {
|
|||
|
||||
// get tx output via -tx parameter
|
||||
let mut tx_id = "".to_string();
|
||||
grin_wallet_controller::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.set_active_account("default")?;
|
||||
let (_, txs) = api.retrieve_txs(true, None, None)?;
|
||||
grin_wallet_controller::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
|
||||
api.set_active_account(m, "default")?;
|
||||
let (_, txs) = api.retrieve_txs(m, true, None, None)?;
|
||||
let some_tx_id = txs[0].tx_slate_id.clone();
|
||||
assert!(some_tx_id.is_some());
|
||||
tx_id = some_tx_id.unwrap().to_hyphenated().to_string().clone();
|
||||
|
|
|
@ -41,12 +41,12 @@ grin_api = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
|||
grin_store = { git = "https://github.com/mimblewimble/grin", branch = "master" }
|
||||
|
||||
# For local testing
|
||||
#grin_core = { path = "../../grin/core", version= "2.0.0-beta.2"}
|
||||
#grin_keychain = { path = "../../grin/keychain", version= "2.0.0-beta.2"}
|
||||
#grin_chain = { path = "../../grin/chain", version= "2.0.0-beta.2"}
|
||||
#grin_util = { path = "../../grin/util", version= "2.0.0-beta.2"}
|
||||
#grin_api = { path = "../../grin/api", version= "2.0.0-beta.2"}
|
||||
#grin_store = { path = "../../grin/store", version= "2.0.0-beta.2"}
|
||||
#grin_core = { path = "../../grin/core", version= "2.0.1-beta.1"}
|
||||
#grin_keychain = { path = "../../grin/keychain", version= "2.0.1-beta.1"}
|
||||
#grin_chain = { path = "../../grin/chain", version= "2.0.1-beta.1"}
|
||||
#grin_util = { path = "../../grin/util", version= "2.0.1-beta.1"}
|
||||
#grin_api = { path = "../../grin/api", version= "2.0.1-beta.1"}
|
||||
#grin_store = { path = "../../grin/store", version= "2.0.1-beta.1"}
|
||||
|
||||
[dev-dependencies]
|
||||
pretty_assertions = "0.5.1"
|
||||
|
|
Loading…
Add table
Reference in a new issue