mirror of
https://github.com/mimblewimble/grin-wallet.git
synced 2025-01-21 03:21:08 +03:00
Final Owner API Changes (#32)
* node height return value and documentation * rustfmt * add parameter struct for initiate tx functions * rustfmt * change tx estimate to use InitTxArgs * rustfmt * transaction estimate * rustfmt * initiate tx args fixed * add send args to init * rustfmt * last owner api documentation
This commit is contained in:
parent
7b8fe92f53
commit
427f42c552
16 changed files with 698 additions and 632 deletions
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
use crate::keychain::Keychain;
|
use crate::keychain::Keychain;
|
||||||
use crate::libwallet::slate::Slate;
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::types::{BlockFees, CbData, NodeClient, WalletBackend};
|
use crate::libwallet::types::{BlockFees, CbData, InitTxArgs, NodeClient, WalletBackend};
|
||||||
use crate::libwallet::ErrorKind;
|
use crate::libwallet::ErrorKind;
|
||||||
use crate::Foreign;
|
use crate::Foreign;
|
||||||
use easy_jsonrpc;
|
use easy_jsonrpc;
|
||||||
|
@ -416,16 +416,16 @@ pub fn run_doctest_foreign(
|
||||||
let amount = 60_000_000_000;
|
let amount = 60_000_000_000;
|
||||||
let mut w = wallet1.lock();
|
let mut w = wallet1.lock();
|
||||||
w.open_with_credentials().unwrap();
|
w.open_with_credentials().unwrap();
|
||||||
let slate = api_impl::owner::initiate_tx(
|
let args = InitTxArgs {
|
||||||
&mut *w, None, // account
|
src_acct_name: None,
|
||||||
amount, // amount
|
amount,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None, None, true,
|
..Default::default()
|
||||||
)
|
};
|
||||||
.unwrap();
|
let slate = api_impl::owner::initiate_tx(&mut *w, args, true).unwrap();
|
||||||
println!("INIT SLATE");
|
println!("INIT SLATE");
|
||||||
// Spit out slate for input to finalize_tx
|
// Spit out slate for input to finalize_tx
|
||||||
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
|
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
use grin_wallet_util::grin_core as core;
|
use grin_wallet_util::grin_core as core;
|
||||||
use grin_wallet_util::grin_keychain as keychain;
|
use grin_wallet_util::grin_keychain as keychain;
|
||||||
use grin_wallet_util::grin_util as util;
|
use grin_wallet_util::grin_util as util;
|
||||||
|
extern crate grin_wallet_impls as impls;
|
||||||
extern crate grin_wallet_libwallet as libwallet;
|
extern crate grin_wallet_libwallet as libwallet;
|
||||||
|
|
||||||
extern crate failure_derive;
|
extern crate failure_derive;
|
||||||
|
|
444
api/src/owner.rs
444
api/src/owner.rs
|
@ -21,14 +21,15 @@ use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::core::core::Transaction;
|
use crate::core::core::Transaction;
|
||||||
|
use crate::impls::{HTTPWalletCommAdapter, KeybaseWalletCommAdapter};
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libwallet::api_impl::owner;
|
use crate::libwallet::api_impl::owner;
|
||||||
use crate::libwallet::slate::Slate;
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::types::{
|
use crate::libwallet::types::{
|
||||||
AcctPathMapping, NodeClient, OutputCommitMapping, TxEstimation, TxLogEntry, WalletBackend,
|
AcctPathMapping, InitTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping, TxLogEntry,
|
||||||
WalletInfo,
|
WalletBackend, WalletInfo,
|
||||||
};
|
};
|
||||||
use crate::libwallet::Error;
|
use crate::libwallet::{Error, ErrorKind};
|
||||||
|
|
||||||
/// Main interface into all wallet API functions.
|
/// Main interface into all wallet API functions.
|
||||||
/// Wallet APIs are split into two seperate blocks of functionality
|
/// Wallet APIs are split into two seperate blocks of functionality
|
||||||
|
@ -431,37 +432,15 @@ where
|
||||||
/// as via file transfer,) the lock call should happen immediately (before the file is sent
|
/// as via file transfer,) the lock call should happen immediately (before the file is sent
|
||||||
/// to the recipient).
|
/// to the recipient).
|
||||||
///
|
///
|
||||||
|
/// If the `send_args` [`InitTxSendArgs`](../grin_wallet_libwallet/types/struct.InitTxSendArgs.html),
|
||||||
|
/// of the [`args`](../grin_wallet_libwallet/types/struct.InitTxArgs.html), field is Some, this
|
||||||
|
/// function will attempt to perform a synchronous send to the recipient specified in the `dest`
|
||||||
|
/// field according to the `method` field, and will also finalize and post the transaction if
|
||||||
|
/// the `finalize` field is set.
|
||||||
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `src_acct_name` - The human readable account name from which to draw outputs
|
/// * `args` - [`InitTxArgs`](../grin_wallet_libwallet/types/struct.InitTxArgs.html),
|
||||||
/// for the transaction, overriding whatever the active account is as set via the
|
/// transaction initialization arguments. See struct documentation for further detail.
|
||||||
/// [`set_active_account`](struct.Owner.html#method.set_active_account) method.
|
|
||||||
/// If None, the transaction will use the active account.
|
|
||||||
/// * `amount` - The amount to send, in nanogrins. (`1 G = 1_000_000_000nG`)
|
|
||||||
/// * `minimum_confirmations` - The minimum number of confirmations an output
|
|
||||||
/// should have in order to be included in the transaction.
|
|
||||||
/// * `max_outputs` - By default, the wallet selects as many inputs as possible in a
|
|
||||||
/// transaction, to reduce the Output set and the fees. The wallet will attempt to spend
|
|
||||||
/// include up to `max_outputs` in a transaction, however if this is not enough to cover
|
|
||||||
/// the whole amount, the wallet will include more outputs. This parameter should be considered
|
|
||||||
/// a soft limit.
|
|
||||||
/// * `num_change_outputs` - The target number of change outputs to create in the transaction.
|
|
||||||
/// The actual number created will be `num_change_outputs` + whatever remainder is needed.
|
|
||||||
/// * `selection_strategy_is_use_all` - If `true`, attempt to use up as many outputs as
|
|
||||||
/// possible to create the transaction, up the 'soft limit' of `max_outputs`. This helps
|
|
||||||
/// to reduce the size of the UTXO set and the amount of data stored in the wallet, and
|
|
||||||
/// minimizes fees. This will generally result in many inputs and a large change output(s),
|
|
||||||
/// usually much larger than the amount being sent. If `false`, the transaction will include
|
|
||||||
/// as many outputs as are needed to meet the amount, (and no more) starting with the smallest
|
|
||||||
/// value outputs.
|
|
||||||
/// * `message` - An optional participant message to include alongside the sender's public
|
|
||||||
/// ParticipantData within the slate. This message will include a signature created with the
|
|
||||||
/// sender's private excess value, and will be publically verifiable. Note this message is for
|
|
||||||
/// the convenience of the participants during the exchange; it is not included in the final
|
|
||||||
/// transaction sent to the chain. The message will be truncated to 256 characters.
|
|
||||||
/// Validation of this message is optional.
|
|
||||||
/// * `target_slate_version` Optionally set the output target slate version (acceptable
|
|
||||||
/// down to the minimum slate version compatible with the current. If `None` the slate
|
|
||||||
/// is generated with the latest version.
|
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
/// * a result containing:
|
/// * a result containing:
|
||||||
|
@ -486,111 +465,69 @@ where
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
///
|
///
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
/// let amount = 2_000_000_000;
|
|
||||||
///
|
|
||||||
/// // Attempt to create a transaction using the 'default' account
|
/// // Attempt to create a transaction using the 'default' account
|
||||||
|
/// let args = InitTxArgs {
|
||||||
|
/// src_acct_name: None,
|
||||||
|
/// amount: 2_000_000_000,
|
||||||
|
/// minimum_confirmations: 2,
|
||||||
|
/// max_outputs: 500,
|
||||||
|
/// num_change_outputs: 1,
|
||||||
|
/// selection_strategy_is_use_all: true,
|
||||||
|
/// message: Some("Have some Grins. Love, Yeastplume".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
/// let result = api_owner.initiate_tx(
|
/// let result = api_owner.initiate_tx(
|
||||||
/// None,
|
/// args,
|
||||||
/// amount, // amount
|
/// );
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// Some("Have some Grins. Love, Yeastplume".to_owned()),
|
|
||||||
/// None, // Use the default slate version
|
|
||||||
/// );
|
|
||||||
///
|
///
|
||||||
/// if let Ok(slate) = result {
|
/// if let Ok(slate) = result {
|
||||||
/// // Send slate somehow
|
/// // Send slate somehow
|
||||||
/// // ...
|
/// // ...
|
||||||
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
/// // Lock our outputs if we're happy the slate was (or is being) sent
|
||||||
/// api_owner.tx_lock_outputs(&slate);
|
/// api_owner.tx_lock_outputs(&slate);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
pub fn initiate_tx(
|
pub fn initiate_tx(&self, args: InitTxArgs) -> Result<Slate, Error> {
|
||||||
&self,
|
let send_args = args.send_args.clone();
|
||||||
src_acct_name: Option<&str>,
|
let mut slate = {
|
||||||
amount: u64,
|
let mut w = self.wallet.lock();
|
||||||
minimum_confirmations: u64,
|
w.open_with_credentials()?;
|
||||||
max_outputs: usize,
|
let slate = owner::initiate_tx(&mut *w, args, self.doctest_mode)?;
|
||||||
num_change_outputs: usize,
|
w.close()?;
|
||||||
selection_strategy_is_use_all: bool,
|
slate
|
||||||
message: Option<String>,
|
};
|
||||||
target_slate_version: Option<u16>,
|
// Helper functionality. If send arguments exist, attempt to send
|
||||||
) -> Result<Slate, Error> {
|
match send_args {
|
||||||
let mut w = self.wallet.lock();
|
Some(sa) => {
|
||||||
w.open_with_credentials()?;
|
match sa.method.as_ref() {
|
||||||
let res = owner::initiate_tx(
|
"http" => {
|
||||||
&mut *w,
|
slate = HTTPWalletCommAdapter::new().send_tx_sync(&sa.dest, &slate)?
|
||||||
src_acct_name,
|
}
|
||||||
amount,
|
"keybase" => {
|
||||||
minimum_confirmations,
|
//TODO: in case of keybase, the response might take 60s and leave the service hanging
|
||||||
max_outputs,
|
slate = KeybaseWalletCommAdapter::new().send_tx_sync(&sa.dest, &slate)?;
|
||||||
num_change_outputs,
|
}
|
||||||
selection_strategy_is_use_all,
|
_ => {
|
||||||
message,
|
error!("unsupported payment method: {}", sa.method);
|
||||||
target_slate_version,
|
return Err(ErrorKind::ClientCallback(
|
||||||
self.doctest_mode,
|
"unsupported payment method".to_owned(),
|
||||||
);
|
))?;
|
||||||
w.close()?;
|
}
|
||||||
res
|
}
|
||||||
}
|
self.tx_lock_outputs(&slate)?;
|
||||||
|
let slate = match sa.finalize {
|
||||||
|
true => self.finalize_tx(&slate)?,
|
||||||
|
false => slate,
|
||||||
|
};
|
||||||
|
|
||||||
/// Estimates the amount to be locked and fee for the transaction without creating one.
|
if sa.post_tx {
|
||||||
///
|
self.post_tx(&slate.tx, sa.fluff)?;
|
||||||
/// # Arguments
|
}
|
||||||
/// * As found in [`initiate_tx`](struct.Owner.html#method.initiate_tx) above.
|
Ok(slate)
|
||||||
///
|
}
|
||||||
/// # Returns
|
None => Ok(slate),
|
||||||
/// * a result containing a
|
}
|
||||||
/// [`TxEstimation`](../grin_wallet_libwallet/types/struct.TxEstimation.html)
|
|
||||||
///
|
|
||||||
/// # Example
|
|
||||||
/// Set up as in [new](struct.Owner.html#method.new) method above.
|
|
||||||
/// ```
|
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
|
||||||
///
|
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
|
||||||
/// let amount = 2_000_000_000;
|
|
||||||
///
|
|
||||||
/// // Estimate transaction using default account
|
|
||||||
/// let result = api_owner.estimate_initiate_tx(
|
|
||||||
/// None,
|
|
||||||
/// amount, // amount
|
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// );
|
|
||||||
///
|
|
||||||
/// if let Ok(est) = result {
|
|
||||||
/// // ...
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
|
|
||||||
pub fn estimate_initiate_tx(
|
|
||||||
&self,
|
|
||||||
src_acct_name: Option<&str>,
|
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
) -> Result<TxEstimation, Error> {
|
|
||||||
let mut w = self.wallet.lock();
|
|
||||||
w.open_with_credentials()?;
|
|
||||||
let res = owner::estimate_initiate_tx(
|
|
||||||
&mut *w,
|
|
||||||
src_acct_name,
|
|
||||||
amount,
|
|
||||||
minimum_confirmations,
|
|
||||||
max_outputs,
|
|
||||||
num_change_outputs,
|
|
||||||
selection_strategy_is_use_all,
|
|
||||||
);
|
|
||||||
w.close()?;
|
|
||||||
res
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locks the outputs associated with the inputs to the transaction in the given
|
/// Locks the outputs associated with the inputs to the transaction in the given
|
||||||
|
@ -621,19 +558,19 @@ where
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
///
|
///
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
/// let amount = 2_000_000_000;
|
/// let args = InitTxArgs {
|
||||||
///
|
/// src_acct_name: None,
|
||||||
/// // Attempt to create a transaction using the 'default' account
|
/// amount: 2_000_000_000,
|
||||||
|
/// minimum_confirmations: 10,
|
||||||
|
/// max_outputs: 500,
|
||||||
|
/// num_change_outputs: 1,
|
||||||
|
/// selection_strategy_is_use_all: true,
|
||||||
|
/// message: Some("Remember to lock this when we're happy this is sent".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
/// let result = api_owner.initiate_tx(
|
/// let result = api_owner.initiate_tx(
|
||||||
/// None,
|
/// args,
|
||||||
/// amount, // amount
|
/// );
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// Some("Remember to lock when we're happy this is sent".to_owned()),
|
|
||||||
/// None, // Use the default slate version
|
|
||||||
/// );
|
|
||||||
///
|
///
|
||||||
/// if let Ok(slate) = result {
|
/// if let Ok(slate) = result {
|
||||||
/// // Send slate somehow
|
/// // Send slate somehow
|
||||||
|
@ -679,19 +616,19 @@ where
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
///
|
///
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
/// let amount = 2_000_000_000;
|
/// let args = InitTxArgs {
|
||||||
///
|
/// src_acct_name: None,
|
||||||
/// // Attempt to create a transaction using the 'default' account
|
/// amount: 2_000_000_000,
|
||||||
|
/// minimum_confirmations: 10,
|
||||||
|
/// max_outputs: 500,
|
||||||
|
/// num_change_outputs: 1,
|
||||||
|
/// selection_strategy_is_use_all: true,
|
||||||
|
/// message: Some("Finalize this tx now".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
/// let result = api_owner.initiate_tx(
|
/// let result = api_owner.initiate_tx(
|
||||||
/// None,
|
/// args,
|
||||||
/// amount, // amount
|
/// );
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// Some("Finalize this tx now".to_owned()),
|
|
||||||
/// None, // Use the default slate version
|
|
||||||
/// );
|
|
||||||
///
|
///
|
||||||
/// if let Ok(slate) = result {
|
/// if let Ok(slate) = result {
|
||||||
/// // Send slate somehow
|
/// // Send slate somehow
|
||||||
|
@ -736,19 +673,19 @@ where
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
///
|
///
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
/// let amount = 2_000_000_000;
|
/// let args = InitTxArgs {
|
||||||
///
|
/// src_acct_name: None,
|
||||||
/// // Attempt to create a transaction using the 'default' account
|
/// amount: 2_000_000_000,
|
||||||
|
/// minimum_confirmations: 10,
|
||||||
|
/// max_outputs: 500,
|
||||||
|
/// num_change_outputs: 1,
|
||||||
|
/// selection_strategy_is_use_all: true,
|
||||||
|
/// message: Some("Post this tx".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
/// let result = api_owner.initiate_tx(
|
/// let result = api_owner.initiate_tx(
|
||||||
/// None,
|
/// args,
|
||||||
/// amount, // amount
|
/// );
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// Some("Finalize this tx now".to_owned()),
|
|
||||||
/// None, // Use the default slate version
|
|
||||||
/// );
|
|
||||||
///
|
///
|
||||||
/// if let Ok(slate) = result {
|
/// if let Ok(slate) = result {
|
||||||
/// // Send slate somehow
|
/// // Send slate somehow
|
||||||
|
@ -797,19 +734,19 @@ where
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
///
|
///
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
/// let amount = 2_000_000_000;
|
/// let args = InitTxArgs {
|
||||||
///
|
/// src_acct_name: None,
|
||||||
/// // Attempt to create a transaction using the 'default' account
|
/// amount: 2_000_000_000,
|
||||||
|
/// minimum_confirmations: 10,
|
||||||
|
/// max_outputs: 500,
|
||||||
|
/// num_change_outputs: 1,
|
||||||
|
/// selection_strategy_is_use_all: true,
|
||||||
|
/// message: Some("Cancel this tx".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
/// let result = api_owner.initiate_tx(
|
/// let result = api_owner.initiate_tx(
|
||||||
/// None,
|
/// args,
|
||||||
/// amount, // amount
|
/// );
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// Some("Cancel this tx".to_owned()),
|
|
||||||
/// None, // Use the default slate version
|
|
||||||
/// );
|
|
||||||
///
|
///
|
||||||
/// if let Ok(slate) = result {
|
/// if let Ok(slate) = result {
|
||||||
/// // Send slate somehow
|
/// // Send slate somehow
|
||||||
|
@ -890,19 +827,19 @@ where
|
||||||
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
///
|
///
|
||||||
/// let mut api_owner = Owner::new(wallet.clone());
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
/// let amount = 2_000_000_000;
|
/// let args = InitTxArgs {
|
||||||
///
|
/// src_acct_name: None,
|
||||||
/// // Attempt to create a transaction using the 'default' account
|
/// amount: 2_000_000_000,
|
||||||
|
/// minimum_confirmations: 10,
|
||||||
|
/// max_outputs: 500,
|
||||||
|
/// num_change_outputs: 1,
|
||||||
|
/// selection_strategy_is_use_all: true,
|
||||||
|
/// message: Some("Just verify messages".to_owned()),
|
||||||
|
/// ..Default::default()
|
||||||
|
/// };
|
||||||
/// let result = api_owner.initiate_tx(
|
/// let result = api_owner.initiate_tx(
|
||||||
/// None,
|
/// args,
|
||||||
/// amount, // amount
|
/// );
|
||||||
/// 10, // minimum confirmations
|
|
||||||
/// 500, // max outputs
|
|
||||||
/// 1, // num change outputs
|
|
||||||
/// true, // select all outputs
|
|
||||||
/// Some("Finalize this tx now".to_owned()),
|
|
||||||
/// None, // Use the default slate version
|
|
||||||
/// );
|
|
||||||
///
|
///
|
||||||
/// if let Ok(slate) = result {
|
/// if let Ok(slate) = result {
|
||||||
/// // Send slate somehow
|
/// // Send slate somehow
|
||||||
|
@ -919,8 +856,40 @@ where
|
||||||
owner::verify_slate_messages(slate)
|
owner::verify_slate_messages(slate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to restore contents of wallet
|
/// Scans the entire UTXO set from the node, creating outputs for each scanned
|
||||||
/// TODO: Full docs
|
/// output that matches the wallet's master seed. This function is intended to be called as part
|
||||||
|
/// of a recovery process (either from BIP32 phrase or backup seed files,) and will error if the
|
||||||
|
/// wallet is non-empty, i.e. contains any outputs at all.
|
||||||
|
///
|
||||||
|
/// This operation scans the entire chain, and is expected to be time intensive. It is imperative
|
||||||
|
/// that no other processes should be trying to use the wallet at the same time this function is
|
||||||
|
/// running.
|
||||||
|
///
|
||||||
|
/// A single [TxLogEntry](../grin_wallet_libwallet/types/struct.TxLogEntry.html) is created for
|
||||||
|
/// all non-coinbase outputs discovered and restored during this process. A separate entry
|
||||||
|
/// is created for each coinbase output.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * None
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(())` if successful
|
||||||
|
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
|
||||||
|
|
||||||
|
/// # Example
|
||||||
|
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
||||||
|
/// ```
|
||||||
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
|
///
|
||||||
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
|
/// let result = api_owner.restore();
|
||||||
|
///
|
||||||
|
/// if let Ok(_) = result {
|
||||||
|
/// // Wallet outputs should be consistent with what's on chain
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
pub fn restore(&self) -> Result<(), Error> {
|
pub fn restore(&self) -> Result<(), Error> {
|
||||||
let mut w = self.wallet.lock();
|
let mut w = self.wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
|
@ -929,8 +898,52 @@ where
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to check and fix the contents of the wallet
|
/// Scans the entire UTXO set from the node, identify which outputs belong to the given wallet
|
||||||
/// TODO: Full docs
|
/// update the wallet state to be consistent with what's currently in the UTXO set.
|
||||||
|
///
|
||||||
|
/// This function can be used to repair wallet state, particularly by restoring outputs that may
|
||||||
|
/// be missing if the wallet owner has cancelled transactions locally that were then successfully
|
||||||
|
/// posted to the chain.
|
||||||
|
///
|
||||||
|
/// This operation scans the entire chain, and is expected to be time intensive. It is imperative
|
||||||
|
/// that no other processes should be trying to use the wallet at the same time this function is
|
||||||
|
/// running.
|
||||||
|
///
|
||||||
|
/// When an output is found that doesn't exist in the wallet, a corresponding
|
||||||
|
/// [TxLogEntry](../grin_wallet_libwallet/types/struct.TxLogEntry.html) is created.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `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,
|
||||||
|
/// restore all missing outputs, and mark any outputs that have been marked 'Spent' but are still
|
||||||
|
/// in the UTXO set as 'Unspent' (as can happen during a fork). It will also attempt to cancel any
|
||||||
|
/// transaction log entries associated with any locked outputs or outputs incorrectly marked 'Spent'.
|
||||||
|
/// Note this completely removes all outstanding transactions, so users should be very aware what
|
||||||
|
/// will happen if this flag is set. Note that if transactions/outputs are removed that later
|
||||||
|
/// confirm on the chain, another call to this function will restore them.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * `Ok(())` if successful
|
||||||
|
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
|
||||||
|
|
||||||
|
/// # Example
|
||||||
|
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
||||||
|
/// ```
|
||||||
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
|
///
|
||||||
|
/// let mut api_owner = Owner::new(wallet.clone());
|
||||||
|
/// let result = api_owner.check_repair(
|
||||||
|
/// false,
|
||||||
|
/// );
|
||||||
|
///
|
||||||
|
/// if let Ok(_) = result {
|
||||||
|
/// // Wallet outputs should be consistent with what's on chain
|
||||||
|
/// // ...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
pub fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), Error> {
|
pub fn check_repair(&self, delete_unconfirmed: bool) -> Result<(), Error> {
|
||||||
let mut w = self.wallet.lock();
|
let mut w = self.wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
|
@ -939,9 +952,44 @@ where
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve current height from node
|
/// Retrieves the last known height known by the wallet. This is determined as follows:
|
||||||
// TODO: Should return u64 as string
|
/// * If the wallet can successfully contact its configured node, the reported node
|
||||||
pub fn node_height(&self) -> Result<(u64, bool), Error> {
|
/// height is returned, and the `updated_from_node` field in the response is `true`
|
||||||
|
/// * If the wallet cannot contact the node, this function returns the maximum height
|
||||||
|
/// of all outputs contained within the wallet, and the `updated_from_node` fields
|
||||||
|
/// in the response is set to false.
|
||||||
|
///
|
||||||
|
/// Clients should generally ensure the `updated_from_node` field is returned as
|
||||||
|
/// `true` before assuming the height for any operation.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * None
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
/// * Ok with a [`NodeHeightResult`](../grin_wallet_libwallet/types/struct.NodeHeightResult.html)
|
||||||
|
/// if successful. If the height result was obtained from the configured node,
|
||||||
|
/// `updated_from_node` will be set to `true`
|
||||||
|
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
|
||||||
|
/// ```
|
||||||
|
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
|
||||||
|
///
|
||||||
|
/// let api_owner = Owner::new(wallet.clone());
|
||||||
|
/// let result = api_owner.node_height();
|
||||||
|
///
|
||||||
|
/// if let Ok(node_height_result) = result {
|
||||||
|
/// if node_height_result.updated_from_node {
|
||||||
|
/// //we can assume node_height_result.height is relatively safe to use
|
||||||
|
///
|
||||||
|
/// }
|
||||||
|
/// //...
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
pub fn node_height(&self) -> Result<NodeHeightResult, Error> {
|
||||||
let mut w = self.wallet.lock();
|
let mut w = self.wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
let res = owner::node_height(&mut *w);
|
let res = owner::node_height(&mut *w);
|
||||||
|
@ -970,7 +1018,7 @@ macro_rules! doctest_helper_setup_doc_env {
|
||||||
use api::Owner;
|
use api::Owner;
|
||||||
use config::WalletConfig;
|
use config::WalletConfig;
|
||||||
use impls::{HTTPNodeClient, LMDBBackend, WalletSeed};
|
use impls::{HTTPNodeClient, LMDBBackend, WalletSeed};
|
||||||
use libwallet::types::WalletBackend;
|
use libwallet::types::{InitTxArgs, WalletBackend};
|
||||||
|
|
||||||
let dir = tempdir().map_err(|e| format!("{:#?}", e)).unwrap();
|
let dir = tempdir().map_err(|e| format!("{:#?}", e)).unwrap();
|
||||||
let dir = dir
|
let dir = dir
|
||||||
|
|
|
@ -19,8 +19,8 @@ use crate::core::core::Transaction;
|
||||||
use crate::keychain::{Identifier, Keychain};
|
use crate::keychain::{Identifier, Keychain};
|
||||||
use crate::libwallet::slate::Slate;
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::types::{
|
use crate::libwallet::types::{
|
||||||
AcctPathMapping, NodeClient, OutputCommitMapping, TxEstimation, TxLogEntry, WalletBackend,
|
AcctPathMapping, InitTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping, TxLogEntry,
|
||||||
WalletInfo,
|
WalletBackend, WalletInfo,
|
||||||
};
|
};
|
||||||
use crate::libwallet::ErrorKind;
|
use crate::libwallet::ErrorKind;
|
||||||
use crate::Owner;
|
use crate::Owner;
|
||||||
|
@ -321,7 +321,19 @@ pub trait OwnerRpc {
|
||||||
{
|
{
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"method": "initiate_tx",
|
"method": "initiate_tx",
|
||||||
"params": [null, 6000000000, 2, 500, 1, true, "my message", null],
|
"params": {
|
||||||
|
"args": {
|
||||||
|
"src_acct_name": null,
|
||||||
|
"amount": "6000000000",
|
||||||
|
"minimum_confirmations": 2,
|
||||||
|
"max_outputs": 500,
|
||||||
|
"num_change_outputs": 1,
|
||||||
|
"selection_strategy_is_use_all": true,
|
||||||
|
"message": "my message",
|
||||||
|
"target_slate_version": null,
|
||||||
|
"send_args": null
|
||||||
|
}
|
||||||
|
},
|
||||||
"id": 1
|
"id": 1
|
||||||
}
|
}
|
||||||
# "#
|
# "#
|
||||||
|
@ -388,62 +400,11 @@ pub trait OwnerRpc {
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fn initiate_tx(
|
fn initiate_tx(&self, args: InitTxArgs) -> Result<Slate, ErrorKind>;
|
||||||
&self,
|
|
||||||
src_acct_name: Option<String>,
|
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
message: Option<String>,
|
|
||||||
target_slate_version: Option<u16>,
|
|
||||||
) -> Result<Slate, ErrorKind>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Networked version of [Owner::estimate_initiate_tx](struct.Owner.html#method.estimate_initiate_tx).
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
|
|
||||||
# r#"
|
|
||||||
{
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"method": "estimate_initiate_tx",
|
|
||||||
"params": [null, 6000000000, 2, 500, 1, true],
|
|
||||||
"id": 1
|
|
||||||
}
|
|
||||||
# "#
|
|
||||||
# ,
|
|
||||||
# r#"
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"jsonrpc": "2.0",
|
|
||||||
"result": {
|
|
||||||
"Ok": {
|
|
||||||
"total": "60000000000",
|
|
||||||
"fee": "8000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# "#
|
|
||||||
# ,4, false, false, false);
|
|
||||||
```
|
|
||||||
*/
|
|
||||||
fn estimate_initiate_tx(
|
|
||||||
&self,
|
|
||||||
src_acct_name: Option<String>,
|
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
) -> Result<TxEstimation, ErrorKind>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Networked version of [Owner::tx_lock_outputs](struct.Owner.html#method.tx_lock_outputs).
|
Networked version of [Owner::tx_lock_outputs](struct.Owner.html#method.tx_lock_outputs).
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
|
# grin_wallet_api::doctest_helper_json_rpc_owner_assert_response!(
|
||||||
# r#"
|
# r#"
|
||||||
|
@ -1029,17 +990,17 @@ pub trait OwnerRpc {
|
||||||
"id": 1,
|
"id": 1,
|
||||||
"jsonrpc": "2.0",
|
"jsonrpc": "2.0",
|
||||||
"result": {
|
"result": {
|
||||||
"Ok": [
|
"Ok": {
|
||||||
5,
|
"height": "5",
|
||||||
true
|
"updated_from_node": true
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# "#
|
# "#
|
||||||
# , 5, false, false, false);
|
# , 5, false, false, false);
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
fn node_height(&self) -> Result<(u64, bool), ErrorKind>;
|
fn node_height(&self) -> Result<NodeHeightResult, ErrorKind>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: ?Sized, C, K> OwnerRpc for Owner<W, C, K>
|
impl<W: ?Sized, C, K> OwnerRpc for Owner<W, C, K>
|
||||||
|
@ -1087,50 +1048,8 @@ where
|
||||||
.map_err(|e| e.kind())
|
.map_err(|e| e.kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initiate_tx(
|
fn initiate_tx(&self, args: InitTxArgs) -> Result<Slate, ErrorKind> {
|
||||||
&self,
|
Owner::initiate_tx(self, args).map_err(|e| e.kind())
|
||||||
src_acct_name: Option<String>,
|
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
message: Option<String>,
|
|
||||||
target_slate_version: Option<u16>,
|
|
||||||
) -> Result<Slate, ErrorKind> {
|
|
||||||
Owner::initiate_tx(
|
|
||||||
self,
|
|
||||||
src_acct_name.as_ref().map(String::as_str),
|
|
||||||
amount,
|
|
||||||
minimum_confirmations,
|
|
||||||
max_outputs,
|
|
||||||
num_change_outputs,
|
|
||||||
selection_strategy_is_use_all,
|
|
||||||
message,
|
|
||||||
target_slate_version,
|
|
||||||
)
|
|
||||||
.map_err(|e| e.kind())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn estimate_initiate_tx(
|
|
||||||
&self,
|
|
||||||
src_acct_name: Option<String>,
|
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
) -> Result<TxEstimation, ErrorKind> {
|
|
||||||
Owner::estimate_initiate_tx(
|
|
||||||
self,
|
|
||||||
src_acct_name.as_ref().map(String::as_str),
|
|
||||||
amount,
|
|
||||||
minimum_confirmations,
|
|
||||||
max_outputs,
|
|
||||||
num_change_outputs,
|
|
||||||
selection_strategy_is_use_all,
|
|
||||||
)
|
|
||||||
.map_err(|e| e.kind())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finalize_tx(&self, mut slate: Slate) -> Result<Slate, ErrorKind> {
|
fn finalize_tx(&self, mut slate: Slate) -> Result<Slate, ErrorKind> {
|
||||||
|
@ -1165,7 +1084,7 @@ where
|
||||||
Owner::check_repair(self, delete_unconfirmed).map_err(|e| e.kind())
|
Owner::check_repair(self, delete_unconfirmed).map_err(|e| e.kind())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn node_height(&self) -> Result<(u64, bool), ErrorKind> {
|
fn node_height(&self) -> Result<NodeHeightResult, ErrorKind> {
|
||||||
Owner::node_height(self).map_err(|e| e.kind())
|
Owner::node_height(self).map_err(|e| e.kind())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1244,16 +1163,16 @@ pub fn run_doctest_owner(
|
||||||
let amount = 60_000_000_000;
|
let amount = 60_000_000_000;
|
||||||
let mut w = wallet1.lock();
|
let mut w = wallet1.lock();
|
||||||
w.open_with_credentials().unwrap();
|
w.open_with_credentials().unwrap();
|
||||||
let mut slate = api_impl::owner::initiate_tx(
|
let args = InitTxArgs {
|
||||||
&mut *w, None, // account
|
src_acct_name: None,
|
||||||
amount, // amount
|
amount,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None, None, true,
|
..Default::default()
|
||||||
)
|
};
|
||||||
.unwrap();
|
let mut slate = api_impl::owner::initiate_tx(&mut *w, args, true).unwrap();
|
||||||
{
|
{
|
||||||
let mut w2 = wallet2.lock();
|
let mut w2 = wallet2.lock();
|
||||||
w2.open_with_credentials().unwrap();
|
w2.open_with_credentials().unwrap();
|
||||||
|
|
|
@ -35,7 +35,7 @@ use crate::impls::{
|
||||||
LMDBBackend, NullWalletCommAdapter,
|
LMDBBackend, NullWalletCommAdapter,
|
||||||
};
|
};
|
||||||
use crate::impls::{HTTPNodeClient, WalletSeed};
|
use crate::impls::{HTTPNodeClient, WalletSeed};
|
||||||
use crate::libwallet::types::{NodeClient, WalletInst};
|
use crate::libwallet::types::{InitTxArgs, NodeClient, WalletInst};
|
||||||
use crate::{controller, display};
|
use crate::{controller, display};
|
||||||
|
|
||||||
/// Arguments common to all wallet commands
|
/// Arguments common to all wallet commands
|
||||||
|
@ -247,31 +247,35 @@ pub fn send(
|
||||||
let strategies = vec!["smallest", "all"]
|
let strategies = vec!["smallest", "all"]
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|strategy| {
|
.map(|strategy| {
|
||||||
let est = api
|
let init_args = InitTxArgs {
|
||||||
.estimate_initiate_tx(
|
src_acct_name: None,
|
||||||
None,
|
amount: args.amount,
|
||||||
args.amount,
|
minimum_confirmations: args.minimum_confirmations,
|
||||||
args.minimum_confirmations,
|
max_outputs: args.max_outputs as u32,
|
||||||
args.max_outputs,
|
num_change_outputs: args.change_outputs as u32,
|
||||||
args.change_outputs,
|
selection_strategy_is_use_all: strategy == "all",
|
||||||
strategy == "all",
|
estimate_only: Some(true),
|
||||||
)
|
..Default::default()
|
||||||
.unwrap();
|
};
|
||||||
(strategy, est.total, est.fee)
|
let slate = api.initiate_tx(init_args).unwrap();
|
||||||
|
(strategy, slate.amount, slate.fee)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
display::estimate(args.amount, strategies, dark_scheme);
|
display::estimate(args.amount, strategies, dark_scheme);
|
||||||
} else {
|
} else {
|
||||||
let result = api.initiate_tx(
|
let init_args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
args.amount,
|
amount: args.amount,
|
||||||
args.minimum_confirmations,
|
minimum_confirmations: args.minimum_confirmations,
|
||||||
args.max_outputs,
|
max_outputs: args.max_outputs as u32,
|
||||||
args.change_outputs,
|
num_change_outputs: args.change_outputs as u32,
|
||||||
args.selection_strategy == "all",
|
selection_strategy_is_use_all: args.selection_strategy == "all",
|
||||||
args.message.clone(),
|
message: args.message.clone(),
|
||||||
args.target_slate_version,
|
target_slate_version: args.target_slate_version,
|
||||||
);
|
send_args: None,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let result = api.initiate_tx(init_args);
|
||||||
let mut slate = match result {
|
let mut slate = match result {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
info!(
|
info!(
|
||||||
|
@ -421,9 +425,9 @@ pub fn outputs(
|
||||||
dark_scheme: bool,
|
dark_scheme: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
controller::owner_single_use(wallet.clone(), |api| {
|
controller::owner_single_use(wallet.clone(), |api| {
|
||||||
let (height, _) = api.node_height()?;
|
let res = api.node_height()?;
|
||||||
let (validated, outputs) = api.retrieve_outputs(g_args.show_spent, true, None)?;
|
let (validated, outputs) = api.retrieve_outputs(g_args.show_spent, true, None)?;
|
||||||
display::outputs(&g_args.account, height, validated, outputs, dark_scheme)?;
|
display::outputs(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -441,12 +445,12 @@ pub fn txs(
|
||||||
dark_scheme: bool,
|
dark_scheme: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
controller::owner_single_use(wallet.clone(), |api| {
|
controller::owner_single_use(wallet.clone(), |api| {
|
||||||
let (height, _) = api.node_height()?;
|
let res = api.node_height()?;
|
||||||
let (validated, txs) = api.retrieve_txs(true, args.id, None)?;
|
let (validated, txs) = api.retrieve_txs(true, args.id, None)?;
|
||||||
let include_status = !args.id.is_some();
|
let include_status = !args.id.is_some();
|
||||||
display::txs(
|
display::txs(
|
||||||
&g_args.account,
|
&g_args.account,
|
||||||
height,
|
res.height,
|
||||||
validated,
|
validated,
|
||||||
&txs,
|
&txs,
|
||||||
include_status,
|
include_status,
|
||||||
|
@ -456,7 +460,7 @@ pub fn txs(
|
||||||
// inputs/outputs and messages
|
// inputs/outputs and messages
|
||||||
if args.id.is_some() {
|
if args.id.is_some() {
|
||||||
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
|
let (_, outputs) = api.retrieve_outputs(true, false, args.id)?;
|
||||||
display::outputs(&g_args.account, height, validated, outputs, dark_scheme)?;
|
display::outputs(&g_args.account, res.height, validated, outputs, dark_scheme)?;
|
||||||
// should only be one here, but just in case
|
// should only be one here, but just in case
|
||||||
for tx in txs {
|
for tx in txs {
|
||||||
display::tx_messages(&tx, dark_scheme)?;
|
display::tx_messages(&tx, dark_scheme)?;
|
||||||
|
|
|
@ -23,7 +23,8 @@ use crate::impls::{FileWalletCommAdapter, HTTPWalletCommAdapter, KeybaseWalletCo
|
||||||
use crate::keychain::Keychain;
|
use crate::keychain::Keychain;
|
||||||
use crate::libwallet::slate::Slate;
|
use crate::libwallet::slate::Slate;
|
||||||
use crate::libwallet::types::{
|
use crate::libwallet::types::{
|
||||||
CbData, NodeClient, OutputCommitMapping, SendTXArgs, TxLogEntry, WalletBackend, WalletInfo,
|
CbData, InitTxArgs, NodeClient, OutputCommitMapping, SendTXArgs, TxLogEntry, WalletBackend,
|
||||||
|
WalletInfo,
|
||||||
};
|
};
|
||||||
use crate::libwallet::{Error, ErrorKind};
|
use crate::libwallet::{Error, ErrorKind};
|
||||||
use crate::util::to_base64;
|
use crate::util::to_base64;
|
||||||
|
@ -289,7 +290,8 @@ where
|
||||||
_req: &Request<Body>,
|
_req: &Request<Body>,
|
||||||
api: Owner<T, C, K>,
|
api: Owner<T, C, K>,
|
||||||
) -> Result<(u64, bool), Error> {
|
) -> Result<(u64, bool), Error> {
|
||||||
api.node_height()
|
let res = api.node_height()?;
|
||||||
|
Ok((res.height, res.updated_from_node))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_get_request(&self, req: &Request<Body>) -> Result<Response<Body>, Error> {
|
fn handle_get_request(&self, req: &Request<Body>) -> Result<Response<Body>, Error> {
|
||||||
|
@ -299,7 +301,7 @@ where
|
||||||
match req
|
match req
|
||||||
.uri()
|
.uri()
|
||||||
.path()
|
.path()
|
||||||
.trim_right_matches("/")
|
.trim_end_matches("/")
|
||||||
.rsplit("/")
|
.rsplit("/")
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -320,16 +322,19 @@ where
|
||||||
api: Owner<T, C, K>,
|
api: Owner<T, C, K>,
|
||||||
) -> Box<dyn Future<Item = Slate, Error = Error> + Send> {
|
) -> Box<dyn Future<Item = Slate, Error = Error> + Send> {
|
||||||
Box::new(parse_body(req).and_then(move |args: SendTXArgs| {
|
Box::new(parse_body(req).and_then(move |args: SendTXArgs| {
|
||||||
let result = api.initiate_tx(
|
let init_args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
args.amount,
|
amount: args.amount,
|
||||||
args.minimum_confirmations,
|
minimum_confirmations: args.minimum_confirmations,
|
||||||
args.max_outputs,
|
max_outputs: args.max_outputs as u32,
|
||||||
args.num_change_outputs,
|
num_change_outputs: args.num_change_outputs as u32,
|
||||||
args.selection_strategy_is_use_all,
|
selection_strategy_is_use_all: args.selection_strategy_is_use_all,
|
||||||
args.message,
|
message: args.message.clone(),
|
||||||
args.target_slate_version,
|
target_slate_version: args.target_slate_version,
|
||||||
);
|
send_args: None,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
let result = api.initiate_tx(init_args);
|
||||||
let mut slate = match result {
|
let mut slate = match result {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
info!(
|
info!(
|
||||||
|
@ -554,7 +559,7 @@ where
|
||||||
match req
|
match req
|
||||||
.uri()
|
.uri()
|
||||||
.path()
|
.path()
|
||||||
.trim_right_matches("/")
|
.trim_end_matches("/")
|
||||||
.rsplit("/")
|
.rsplit("/")
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
@ -688,7 +693,7 @@ where
|
||||||
match req
|
match req
|
||||||
.uri()
|
.uri()
|
||||||
.path()
|
.path()
|
||||||
.trim_right_matches("/")
|
.trim_end_matches("/")
|
||||||
.rsplit("/")
|
.rsplit("/")
|
||||||
.next()
|
.next()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -26,6 +26,7 @@ use self::core::global::ChainTypes;
|
||||||
use self::keychain::{ExtKeychain, Keychain};
|
use self::keychain::{ExtKeychain, Keychain};
|
||||||
use grin_wallet_libwallet as libwallet;
|
use grin_wallet_libwallet as libwallet;
|
||||||
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
||||||
|
use libwallet::types::InitTxArgs;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -179,14 +180,16 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||||
let mut slate = api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None, reward, // amount
|
src_acct_name: None,
|
||||||
2, // minimum confirmations
|
amount: reward,
|
||||||
500, // max outputs
|
minimum_confirmations: 2,
|
||||||
1, // num change outputs
|
max_outputs: 500,
|
||||||
true, // select all outputs
|
num_change_outputs: 1,
|
||||||
None, None,
|
selection_strategy_is_use_all: true,
|
||||||
)?;
|
..Default::default()
|
||||||
|
};
|
||||||
|
let mut slate = api.initiate_tx(args)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||||
api.tx_lock_outputs(&slate)?;
|
api.tx_lock_outputs(&slate)?;
|
||||||
slate = api.finalize_tx(&slate)?;
|
slate = api.finalize_tx(&slate)?;
|
||||||
|
|
|
@ -28,7 +28,7 @@ use self::keychain::ExtKeychain;
|
||||||
use grin_wallet_libwallet as libwallet;
|
use grin_wallet_libwallet as libwallet;
|
||||||
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
||||||
use impls::FileWalletCommAdapter;
|
use impls::FileWalletCommAdapter;
|
||||||
use libwallet::types::WalletInst;
|
use libwallet::types::{InitTxArgs, WalletInst};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -178,16 +178,16 @@ fn check_repair_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// perform a transaction, but don't let it finish
|
// perform a transaction, but don't let it finish
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||||
// send to send
|
// send to send
|
||||||
let mut slate = api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
reward * 2, // amount
|
amount: reward * 2,
|
||||||
cm, // minimum confirmations
|
minimum_confirmations: cm,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None, // optional message
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let mut slate = api.initiate_tx(args)?;
|
||||||
// output tx file
|
// output tx file
|
||||||
let file_adapter = FileWalletCommAdapter::new();
|
let file_adapter = FileWalletCommAdapter::new();
|
||||||
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
let send_file = format!("{}/part_tx_1.tx", test_dir);
|
||||||
|
|
|
@ -31,6 +31,8 @@ use std::fs;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use grin_wallet_libwallet::types::InitTxArgs;
|
||||||
|
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
fn clean_output_dir(test_dir: &str) {
|
fn clean_output_dir(test_dir: &str) {
|
||||||
|
@ -105,16 +107,17 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||||
assert_eq!(wallet1_info.total, bh * reward);
|
assert_eq!(wallet1_info.total, bh * reward);
|
||||||
// send to send
|
// send to send
|
||||||
let mut slate = api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
Some("mining"),
|
src_acct_name: Some("mining".to_owned()),
|
||||||
reward * 2, // amount
|
amount: reward * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
Some(message.to_owned()), // optional message
|
message: Some(message.to_owned()),
|
||||||
None,
|
..Default::default()
|
||||||
)?;
|
};
|
||||||
|
let mut slate = api.initiate_tx(args)?;
|
||||||
// output tx file
|
// output tx file
|
||||||
let file_adapter = FileWalletCommAdapter::new();
|
let file_adapter = FileWalletCommAdapter::new();
|
||||||
file_adapter.send_tx_async(&send_file, &mut slate)?;
|
file_adapter.send_tx_async(&send_file, &mut slate)?;
|
||||||
|
|
|
@ -26,6 +26,7 @@ use self::core::global;
|
||||||
use self::core::global::ChainTypes;
|
use self::core::global::ChainTypes;
|
||||||
use self::keychain::ExtKeychain;
|
use self::keychain::ExtKeychain;
|
||||||
use self::libwallet::slate::Slate;
|
use self::libwallet::slate::Slate;
|
||||||
|
use self::libwallet::types::InitTxArgs;
|
||||||
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
||||||
use impls::FileWalletCommAdapter;
|
use impls::FileWalletCommAdapter;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
@ -103,16 +104,16 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||||
assert_eq!(wallet1_info.total, bh * reward);
|
assert_eq!(wallet1_info.total, bh * reward);
|
||||||
// send to send
|
// send to send
|
||||||
let mut slate = api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
Some("mining"),
|
src_acct_name: Some("mining".to_owned()),
|
||||||
reward * 2, // amount
|
amount: reward * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let mut slate = api.initiate_tx(args)?;
|
||||||
// output tx file
|
// output tx file
|
||||||
let file_adapter = FileWalletCommAdapter::new();
|
let file_adapter = FileWalletCommAdapter::new();
|
||||||
file_adapter.send_tx_async(&send_file, &mut slate)?;
|
file_adapter.send_tx_async(&send_file, &mut slate)?;
|
||||||
|
@ -200,16 +201,16 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
|
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 2, // amount
|
amount: reward * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&mut slate)?;
|
slate = sender_api.finalize_tx(&mut slate)?;
|
||||||
|
|
|
@ -26,7 +26,7 @@ use self::core::global;
|
||||||
use self::core::global::ChainTypes;
|
use self::core::global::ChainTypes;
|
||||||
use self::keychain::{ExtKeychain, Identifier, Keychain};
|
use self::keychain::{ExtKeychain, Identifier, Keychain};
|
||||||
use self::libwallet::slate::Slate;
|
use self::libwallet::slate::Slate;
|
||||||
use self::libwallet::types::AcctPathMapping;
|
use self::libwallet::types::{AcctPathMapping, InitTxArgs};
|
||||||
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
@ -237,14 +237,16 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
let mut slate = Slate::blank(1);
|
let mut slate = Slate::blank(1);
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None, amount, // amount
|
src_acct_name: None,
|
||||||
2, // minimum confirmations
|
amount: amount,
|
||||||
500, // max outputs
|
minimum_confirmations: 2,
|
||||||
1, // num change outputs
|
max_outputs: 500,
|
||||||
true, // select all outputs
|
num_change_outputs: 1,
|
||||||
None, None,
|
selection_strategy_is_use_all: true,
|
||||||
)?;
|
..Default::default()
|
||||||
|
};
|
||||||
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&slate)?;
|
slate = sender_api.finalize_tx(&slate)?;
|
||||||
|
@ -258,16 +260,16 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// Send some to wallet 3
|
// Send some to wallet 3
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 2, // amount
|
amount: amount * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&slate)?;
|
slate = sender_api.finalize_tx(&slate)?;
|
||||||
|
@ -281,16 +283,16 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// Wallet3 to wallet 2
|
// Wallet3 to wallet 2
|
||||||
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 3, // amount
|
amount: amount * 3,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&slate)?;
|
slate = sender_api.finalize_tx(&slate)?;
|
||||||
|
@ -310,16 +312,16 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// Wallet3 to wallet 2 again (to another account)
|
// Wallet3 to wallet 2 again (to another account)
|
||||||
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet3.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 3, // amount
|
amount: amount * 3,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&slate)?;
|
slate = sender_api.finalize_tx(&slate)?;
|
||||||
|
|
|
@ -26,6 +26,7 @@ use self::core::global::ChainTypes;
|
||||||
use self::keychain::ExtKeychain;
|
use self::keychain::ExtKeychain;
|
||||||
use grin_wallet_libwallet as libwallet;
|
use grin_wallet_libwallet as libwallet;
|
||||||
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
||||||
|
use libwallet::types::InitTxArgs;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -86,16 +87,16 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
assert_eq!(wallet1_info.last_confirmed_height, bh);
|
||||||
assert_eq!(wallet1_info.total, bh * reward);
|
assert_eq!(wallet1_info.total, bh * reward);
|
||||||
// send to send
|
// send to send
|
||||||
let mut slate = api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
Some("mining"),
|
src_acct_name: Some("mining".to_owned()),
|
||||||
reward * 2, // amount
|
amount: reward * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let mut slate = api.initiate_tx(args)?;
|
||||||
api.tx_lock_outputs(&slate)?;
|
api.tx_lock_outputs(&slate)?;
|
||||||
// Send directly to self
|
// Send directly to self
|
||||||
wallet::controller::foreign_single_use(wallet1.clone(), |api| {
|
wallet::controller::foreign_single_use(wallet1.clone(), |api| {
|
||||||
|
|
|
@ -27,7 +27,7 @@ use self::core::global;
|
||||||
use self::core::global::ChainTypes;
|
use self::core::global::ChainTypes;
|
||||||
use self::keychain::ExtKeychain;
|
use self::keychain::ExtKeychain;
|
||||||
use self::libwallet::slate::Slate;
|
use self::libwallet::slate::Slate;
|
||||||
use self::libwallet::types::OutputStatus;
|
use self::libwallet::types::{InitTxArgs, OutputStatus};
|
||||||
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
use impls::test_framework::{self, LocalWalletClient, WalletProxy};
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -100,14 +100,16 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
let mut slate = Slate::blank(1);
|
let mut slate = Slate::blank(1);
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None, amount, // amount
|
src_acct_name: None,
|
||||||
2, // minimum confirmations
|
amount: amount,
|
||||||
500, // max outputs
|
minimum_confirmations: 2,
|
||||||
1, // num change outputs
|
max_outputs: 500,
|
||||||
true, // select all outputs
|
num_change_outputs: 1,
|
||||||
None, None,
|
selection_strategy_is_use_all: true,
|
||||||
)?;
|
..Default::default()
|
||||||
|
};
|
||||||
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
|
|
||||||
// Check we are creating a tx with the expected lock_height of 0.
|
// Check we are creating a tx with the expected lock_height of 0.
|
||||||
// We will check this produces a Plain kernel later.
|
// We will check this produces a Plain kernel later.
|
||||||
|
@ -250,26 +252,32 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
|
|
||||||
// Estimate fee and locked amount for a transaction
|
// Estimate fee and locked amount for a transaction
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
let est = sender_api.estimate_initiate_tx(
|
let init_args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 2, // amount
|
amount: amount * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
)?;
|
estimate_only: Some(true),
|
||||||
assert_eq!(est.total, 600_000_000_000);
|
..Default::default()
|
||||||
|
};
|
||||||
|
let est = sender_api.initiate_tx(init_args)?;
|
||||||
|
assert_eq!(est.amount, 600_000_000_000);
|
||||||
assert_eq!(est.fee, 4_000_000);
|
assert_eq!(est.fee, 4_000_000);
|
||||||
|
|
||||||
let est = sender_api.estimate_initiate_tx(
|
let init_args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 2, // amount
|
amount: amount * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
false, // select the smallest amount of outputs
|
selection_strategy_is_use_all: false, //select smallest number
|
||||||
)?;
|
estimate_only: Some(true),
|
||||||
assert_eq!(est.total, 180_000_000_000);
|
..Default::default()
|
||||||
|
};
|
||||||
|
let est = sender_api.initiate_tx(init_args)?;
|
||||||
|
assert_eq!(est.amount, 180_000_000_000);
|
||||||
assert_eq!(est.fee, 6_000_000);
|
assert_eq!(est.fee, 6_000_000);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -279,16 +287,16 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
// the stored transaction instead
|
// the stored transaction instead
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None,
|
src_acct_name: None,
|
||||||
amount * 2, // amount
|
amount: amount * 2,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None,
|
..Default::default()
|
||||||
None,
|
};
|
||||||
)?;
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&slate)?;
|
slate = sender_api.finalize_tx(&slate)?;
|
||||||
|
@ -378,14 +386,17 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||||
let mut slate = Slate::blank(1);
|
let mut slate = Slate::blank(1);
|
||||||
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
wallet::controller::owner_single_use(wallet1.clone(), |sender_api| {
|
||||||
// note this will increment the block count as part of the transaction "Posting"
|
// note this will increment the block count as part of the transaction "Posting"
|
||||||
let slate_i = sender_api.initiate_tx(
|
let args = InitTxArgs {
|
||||||
None, amount, // amount
|
src_acct_name: None,
|
||||||
2, // minimum confirmations
|
amount: amount,
|
||||||
500, // max outputs
|
minimum_confirmations: 2,
|
||||||
1, // num change outputs
|
max_outputs: 500,
|
||||||
true, // select all outputs
|
num_change_outputs: 1,
|
||||||
None, None,
|
selection_strategy_is_use_all: true,
|
||||||
)?;
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let slate_i = sender_api.initiate_tx(args)?;
|
||||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||||
sender_api.tx_lock_outputs(&slate)?;
|
sender_api.tx_lock_outputs(&slate)?;
|
||||||
slate = sender_api.finalize_tx(&slate)?;
|
slate = sender_api.finalize_tx(&slate)?;
|
||||||
|
|
|
@ -23,7 +23,7 @@ use crate::keychain;
|
||||||
use crate::libwallet;
|
use crate::libwallet;
|
||||||
use crate::libwallet::api_impl::{foreign, owner};
|
use crate::libwallet::api_impl::{foreign, owner};
|
||||||
use crate::libwallet::types::{
|
use crate::libwallet::types::{
|
||||||
BlockFees, CbData, NodeClient, WalletBackend, WalletInfo, WalletInst,
|
BlockFees, CbData, InitTxArgs, NodeClient, WalletBackend, WalletInfo, WalletInst,
|
||||||
};
|
};
|
||||||
use crate::lmdb_wallet::LMDBBackend;
|
use crate::lmdb_wallet::LMDBBackend;
|
||||||
use crate::util;
|
use crate::util;
|
||||||
|
@ -196,15 +196,16 @@ where
|
||||||
let slate = {
|
let slate = {
|
||||||
let mut w = wallet.lock();
|
let mut w = wallet.lock();
|
||||||
w.open_with_credentials()?;
|
w.open_with_credentials()?;
|
||||||
let slate_i = owner::initiate_tx(
|
let args = InitTxArgs {
|
||||||
&mut *w, None, // account
|
src_acct_name: None,
|
||||||
amount, // amount
|
amount,
|
||||||
2, // minimum confirmations
|
minimum_confirmations: 2,
|
||||||
500, // max outputs
|
max_outputs: 500,
|
||||||
1, // num change outputs
|
num_change_outputs: 1,
|
||||||
true, // select all outputs
|
selection_strategy_is_use_all: true,
|
||||||
None, None, test_mode,
|
..Default::default()
|
||||||
)?;
|
};
|
||||||
|
let slate_i = owner::initiate_tx(&mut *w, args, test_mode)?;
|
||||||
let slate = client.send_tx_slate_direct(dest, &slate_i)?;
|
let slate = client.send_tx_slate_direct(dest, &slate_i)?;
|
||||||
owner::tx_lock_outputs(&mut *w, &slate)?;
|
owner::tx_lock_outputs(&mut *w, &slate)?;
|
||||||
let slate = owner::finalize_tx(&mut *w, &slate)?;
|
let slate = owner::finalize_tx(&mut *w, &slate)?;
|
||||||
|
|
|
@ -25,8 +25,8 @@ use crate::grin_keychain::{Identifier, Keychain};
|
||||||
use crate::internal::{keys, selection, tx, updater};
|
use crate::internal::{keys, selection, tx, updater};
|
||||||
use crate::slate::Slate;
|
use crate::slate::Slate;
|
||||||
use crate::types::{
|
use crate::types::{
|
||||||
AcctPathMapping, NodeClient, OutputCommitMapping, TxEstimation, TxLogEntry, TxWrapper,
|
AcctPathMapping, InitTxArgs, NodeClient, NodeHeightResult, OutputCommitMapping, TxLogEntry,
|
||||||
WalletBackend, WalletInfo,
|
TxWrapper, WalletBackend, WalletInfo,
|
||||||
};
|
};
|
||||||
use crate::{Error, ErrorKind};
|
use crate::{Error, ErrorKind};
|
||||||
|
|
||||||
|
@ -137,14 +137,7 @@ where
|
||||||
/// Initiate tx as sender
|
/// Initiate tx as sender
|
||||||
pub fn initiate_tx<T: ?Sized, C, K>(
|
pub fn initiate_tx<T: ?Sized, C, K>(
|
||||||
w: &mut T,
|
w: &mut T,
|
||||||
src_acct_name: Option<&str>,
|
args: InitTxArgs,
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
message: Option<String>,
|
|
||||||
target_slate_version: Option<u16>,
|
|
||||||
use_test_rng: bool,
|
use_test_rng: bool,
|
||||||
) -> Result<Slate, Error>
|
) -> Result<Slate, Error>
|
||||||
where
|
where
|
||||||
|
@ -152,9 +145,9 @@ where
|
||||||
C: NodeClient,
|
C: NodeClient,
|
||||||
K: Keychain,
|
K: Keychain,
|
||||||
{
|
{
|
||||||
let parent_key_id = match src_acct_name {
|
let parent_key_id = match args.src_acct_name {
|
||||||
Some(d) => {
|
Some(d) => {
|
||||||
let pm = w.get_acct_path(d.to_owned())?;
|
let pm = w.get_acct_path(d)?;
|
||||||
match pm {
|
match pm {
|
||||||
Some(p) => p.path,
|
Some(p) => p.path,
|
||||||
None => w.parent_key_id(),
|
None => w.parent_key_id(),
|
||||||
|
@ -163,7 +156,7 @@ where
|
||||||
None => w.parent_key_id(),
|
None => w.parent_key_id(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let message = match message {
|
let message = match args.message {
|
||||||
Some(mut m) => {
|
Some(mut m) => {
|
||||||
m.truncate(USER_MESSAGE_MAX_LEN);
|
m.truncate(USER_MESSAGE_MAX_LEN);
|
||||||
Some(m)
|
Some(m)
|
||||||
|
@ -171,15 +164,32 @@ where
|
||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut slate = tx::new_tx_slate(&mut *w, amount, 2, use_test_rng)?;
|
let mut slate = tx::new_tx_slate(&mut *w, args.amount, 2, use_test_rng)?;
|
||||||
|
|
||||||
|
// if we just want to estimate, don't save a context, just send the results
|
||||||
|
// back
|
||||||
|
if let Some(true) = args.estimate_only {
|
||||||
|
let (total, fee) = tx::estimate_send_tx(
|
||||||
|
&mut *w,
|
||||||
|
args.amount,
|
||||||
|
args.minimum_confirmations,
|
||||||
|
args.max_outputs as usize,
|
||||||
|
args.num_change_outputs as usize,
|
||||||
|
args.selection_strategy_is_use_all,
|
||||||
|
&parent_key_id,
|
||||||
|
)?;
|
||||||
|
slate.amount = total;
|
||||||
|
slate.fee = fee;
|
||||||
|
return Ok(slate);
|
||||||
|
}
|
||||||
|
|
||||||
let context = tx::add_inputs_to_slate(
|
let context = tx::add_inputs_to_slate(
|
||||||
&mut *w,
|
&mut *w,
|
||||||
&mut slate,
|
&mut slate,
|
||||||
minimum_confirmations,
|
args.minimum_confirmations,
|
||||||
max_outputs,
|
args.max_outputs as usize,
|
||||||
num_change_outputs,
|
args.num_change_outputs as usize,
|
||||||
selection_strategy_is_use_all,
|
args.selection_strategy_is_use_all,
|
||||||
&parent_key_id,
|
&parent_key_id,
|
||||||
0,
|
0,
|
||||||
message,
|
message,
|
||||||
|
@ -193,49 +203,12 @@ where
|
||||||
batch.save_private_context(slate.id.as_bytes(), &context)?;
|
batch.save_private_context(slate.id.as_bytes(), &context)?;
|
||||||
batch.commit()?;
|
batch.commit()?;
|
||||||
}
|
}
|
||||||
if let Some(v) = target_slate_version {
|
if let Some(v) = args.target_slate_version {
|
||||||
slate.version_info.orig_version = v;
|
slate.version_info.orig_version = v;
|
||||||
}
|
}
|
||||||
Ok(slate)
|
Ok(slate)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Estimate
|
|
||||||
pub fn estimate_initiate_tx<T: ?Sized, C, K>(
|
|
||||||
w: &mut T,
|
|
||||||
src_acct_name: Option<&str>,
|
|
||||||
amount: u64,
|
|
||||||
minimum_confirmations: u64,
|
|
||||||
max_outputs: usize,
|
|
||||||
num_change_outputs: usize,
|
|
||||||
selection_strategy_is_use_all: bool,
|
|
||||||
) -> Result<TxEstimation, Error>
|
|
||||||
where
|
|
||||||
T: WalletBackend<C, K>,
|
|
||||||
C: NodeClient,
|
|
||||||
K: Keychain,
|
|
||||||
{
|
|
||||||
let parent_key_id = match src_acct_name {
|
|
||||||
Some(d) => {
|
|
||||||
let pm = w.get_acct_path(d.to_owned())?;
|
|
||||||
match pm {
|
|
||||||
Some(p) => p.path,
|
|
||||||
None => w.parent_key_id(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => w.parent_key_id(),
|
|
||||||
};
|
|
||||||
let (total, fee) = tx::estimate_send_tx(
|
|
||||||
&mut *w,
|
|
||||||
amount,
|
|
||||||
minimum_confirmations,
|
|
||||||
max_outputs,
|
|
||||||
num_change_outputs,
|
|
||||||
selection_strategy_is_use_all,
|
|
||||||
&parent_key_id,
|
|
||||||
)?;
|
|
||||||
Ok(TxEstimation { total, fee })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Lock sender outputs
|
/// Lock sender outputs
|
||||||
pub fn tx_lock_outputs<T: ?Sized, C, K>(w: &mut T, slate: &Slate) -> Result<(), Error>
|
pub fn tx_lock_outputs<T: ?Sized, C, K>(w: &mut T, slate: &Slate) -> Result<(), Error>
|
||||||
where
|
where
|
||||||
|
@ -348,7 +321,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// node height
|
/// node height
|
||||||
pub fn node_height<T: ?Sized, C, K>(w: &mut T) -> Result<(u64, bool), Error>
|
pub fn node_height<T: ?Sized, C, K>(w: &mut T) -> Result<NodeHeightResult, Error>
|
||||||
where
|
where
|
||||||
T: WalletBackend<C, K>,
|
T: WalletBackend<C, K>,
|
||||||
C: NodeClient,
|
C: NodeClient,
|
||||||
|
@ -356,14 +329,20 @@ where
|
||||||
{
|
{
|
||||||
let res = w.w2n_client().get_chain_height();
|
let res = w.w2n_client().get_chain_height();
|
||||||
match res {
|
match res {
|
||||||
Ok(height) => Ok((height, true)),
|
Ok(height) => Ok(NodeHeightResult {
|
||||||
|
height,
|
||||||
|
updated_from_node: true,
|
||||||
|
}),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
let outputs = retrieve_outputs(w, true, false, None)?;
|
let outputs = retrieve_outputs(w, true, false, None)?;
|
||||||
let height = match outputs.1.iter().map(|m| m.output.height).max() {
|
let height = match outputs.1.iter().map(|m| m.output.height).max() {
|
||||||
Some(height) => height,
|
Some(height) => height,
|
||||||
None => 0,
|
None => 0,
|
||||||
};
|
};
|
||||||
Ok((height, false))
|
Ok(NodeHeightResult {
|
||||||
|
height,
|
||||||
|
updated_from_node: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -373,29 +373,6 @@ impl fmt::Display for OutputStatus {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map Outputdata to commits
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct OutputCommitMapping {
|
|
||||||
/// Output Data
|
|
||||||
pub output: OutputData,
|
|
||||||
/// The commit
|
|
||||||
#[serde(
|
|
||||||
serialize_with = "secp_ser::as_hex",
|
|
||||||
deserialize_with = "secp_ser::commitment_from_hex"
|
|
||||||
)]
|
|
||||||
pub commit: pedersen::Commitment,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transaction Estimate
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct TxEstimation {
|
|
||||||
/// Total amount to be locked
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub total: u64,
|
|
||||||
/// Transaction Fee
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub fee: u64,
|
|
||||||
}
|
|
||||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
/// Holds the context for a single aggsig transaction
|
/// Holds the context for a single aggsig transaction
|
||||||
pub struct Context {
|
pub struct Context {
|
||||||
|
@ -545,37 +522,6 @@ impl<'de> serde::de::Visitor<'de> for BlockIdentifierVisitor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fees in block to use for coinbase amount calculation
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct BlockFees {
|
|
||||||
/// fees
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub fees: u64,
|
|
||||||
/// height
|
|
||||||
#[serde(with = "secp_ser::string_or_u64")]
|
|
||||||
pub height: u64,
|
|
||||||
/// key id
|
|
||||||
pub key_id: Option<Identifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockFees {
|
|
||||||
/// return key id
|
|
||||||
pub fn key_id(&self) -> Option<Identifier> {
|
|
||||||
self.key_id.clone()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Response to build a coinbase output.
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
||||||
pub struct CbData {
|
|
||||||
/// Output
|
|
||||||
pub output: Output,
|
|
||||||
/// Kernel
|
|
||||||
pub kernel: TxKernel,
|
|
||||||
/// Key Id
|
|
||||||
pub key_id: Option<Identifier>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// a contained wallet info struct, so automated tests can parse wallet info
|
/// a contained wallet info struct, so automated tests can parse wallet info
|
||||||
/// can add more fields here over time as needed
|
/// can add more fields here over time as needed
|
||||||
#[derive(Serialize, Eq, PartialEq, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Eq, PartialEq, Deserialize, Debug, Clone)]
|
||||||
|
@ -752,7 +698,11 @@ pub struct TxWrapper {
|
||||||
pub tx_hex: String,
|
pub tx_hex: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Types to facilitate API arguments and serialization
|
||||||
|
|
||||||
/// Send TX API Args
|
/// Send TX API Args
|
||||||
|
// TODO: This is here to ensure the legacy V1 API remains intact
|
||||||
|
// remove this when v1 api is removed
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct SendTXArgs {
|
pub struct SendTXArgs {
|
||||||
/// amount to send
|
/// amount to send
|
||||||
|
@ -774,3 +724,141 @@ pub struct SendTXArgs {
|
||||||
/// Optional slate version to target when sending
|
/// Optional slate version to target when sending
|
||||||
pub target_slate_version: Option<u16>,
|
pub target_slate_version: Option<u16>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// V2 Init / Send TX API Args
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct InitTxArgs {
|
||||||
|
/// The human readable account name from which to draw outputs
|
||||||
|
/// for the transaction, overriding whatever the active account is as set via the
|
||||||
|
/// [`set_active_account`](../grin_wallet_api/owner/struct.Owner.html#method.set_active_account) method.
|
||||||
|
pub src_acct_name: Option<String>,
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
/// The amount to send, in nanogrins. (`1 G = 1_000_000_000nG`)
|
||||||
|
pub amount: u64,
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
/// The minimum number of confirmations an output
|
||||||
|
/// should have in order to be included in the transaction.
|
||||||
|
pub minimum_confirmations: u64,
|
||||||
|
/// By default, the wallet selects as many inputs as possible in a
|
||||||
|
/// transaction, to reduce the Output set and the fees. The wallet will attempt to spend
|
||||||
|
/// include up to `max_outputs` in a transaction, however if this is not enough to cover
|
||||||
|
/// the whole amount, the wallet will include more outputs. This parameter should be considered
|
||||||
|
/// a soft limit.
|
||||||
|
pub max_outputs: u32,
|
||||||
|
/// The target number of change outputs to create in the transaction.
|
||||||
|
/// The actual number created will be `num_change_outputs` + whatever remainder is needed.
|
||||||
|
pub num_change_outputs: u32,
|
||||||
|
/// If `true`, attempt to use up as many outputs as
|
||||||
|
/// possible to create the transaction, up the 'soft limit' of `max_outputs`. This helps
|
||||||
|
/// to reduce the size of the UTXO set and the amount of data stored in the wallet, and
|
||||||
|
/// minimizes fees. This will generally result in many inputs and a large change output(s),
|
||||||
|
/// usually much larger than the amount being sent. If `false`, the transaction will include
|
||||||
|
/// as many outputs as are needed to meet the amount, (and no more) starting with the smallest
|
||||||
|
/// value outputs.
|
||||||
|
pub selection_strategy_is_use_all: bool,
|
||||||
|
/// An optional participant message to include alongside the sender's public
|
||||||
|
/// ParticipantData within the slate. This message will include a signature created with the
|
||||||
|
/// sender's private excess value, and will be publically verifiable. Note this message is for
|
||||||
|
/// the convenience of the participants during the exchange; it is not included in the final
|
||||||
|
/// transaction sent to the chain. The message will be truncated to 256 characters.
|
||||||
|
pub message: Option<String>,
|
||||||
|
/// Optionally set the output target slate version (acceptable
|
||||||
|
/// down to the minimum slate version compatible with the current. If `None` the slate
|
||||||
|
/// is generated with the latest version.
|
||||||
|
pub target_slate_version: Option<u16>,
|
||||||
|
/// If true, just return an estimate of the resulting slate, containing fees and amounts
|
||||||
|
/// locked without actually locking outputs or creating the transaction. Note if this is set to
|
||||||
|
/// 'true', the amount field in the slate will contain the total amount locked, not the provided
|
||||||
|
/// transaction amount
|
||||||
|
pub estimate_only: Option<bool>,
|
||||||
|
/// Sender arguments. If present, the underlying function will also attempt to send the
|
||||||
|
/// transaction to a destination and optionally finalize the result
|
||||||
|
pub send_args: Option<InitTxSendArgs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send TX API Args, for convenience functionality that inits the transaction and sends
|
||||||
|
/// in one go
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct InitTxSendArgs {
|
||||||
|
/// The transaction method. Can currently be 'http' or 'keybase'.
|
||||||
|
pub method: String,
|
||||||
|
/// The destination, contents will depend on the particular method
|
||||||
|
pub dest: String,
|
||||||
|
/// Whether to finalize the result immediately if the send was successful
|
||||||
|
pub finalize: bool,
|
||||||
|
/// Whether to post the transasction if the send and finalize were successful
|
||||||
|
pub post_tx: bool,
|
||||||
|
/// Whether to use dandelion when posting. If false, skip the dandelion relay
|
||||||
|
pub fluff: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for InitTxArgs {
|
||||||
|
fn default() -> InitTxArgs {
|
||||||
|
InitTxArgs {
|
||||||
|
src_acct_name: None,
|
||||||
|
amount: 0,
|
||||||
|
minimum_confirmations: 10,
|
||||||
|
max_outputs: 500,
|
||||||
|
num_change_outputs: 1,
|
||||||
|
selection_strategy_is_use_all: true,
|
||||||
|
message: None,
|
||||||
|
target_slate_version: None,
|
||||||
|
estimate_only: Some(false),
|
||||||
|
send_args: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fees in block to use for coinbase amount calculation
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct BlockFees {
|
||||||
|
/// fees
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub fees: u64,
|
||||||
|
/// height
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub height: u64,
|
||||||
|
/// key id
|
||||||
|
pub key_id: Option<Identifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BlockFees {
|
||||||
|
/// return key id
|
||||||
|
pub fn key_id(&self) -> Option<Identifier> {
|
||||||
|
self.key_id.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Response to build a coinbase output.
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct CbData {
|
||||||
|
/// Output
|
||||||
|
pub output: Output,
|
||||||
|
/// Kernel
|
||||||
|
pub kernel: TxKernel,
|
||||||
|
/// Key Id
|
||||||
|
pub key_id: Option<Identifier>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map Outputdata to commits
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct OutputCommitMapping {
|
||||||
|
/// Output Data
|
||||||
|
pub output: OutputData,
|
||||||
|
/// The commit
|
||||||
|
#[serde(
|
||||||
|
serialize_with = "secp_ser::as_hex",
|
||||||
|
deserialize_with = "secp_ser::commitment_from_hex"
|
||||||
|
)]
|
||||||
|
pub commit: pedersen::Commitment,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Node height result
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
pub struct NodeHeightResult {
|
||||||
|
/// Last known height
|
||||||
|
#[serde(with = "secp_ser::string_or_u64")]
|
||||||
|
pub height: u64,
|
||||||
|
/// Whether this height was updated from the node
|
||||||
|
pub updated_from_node: bool,
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue