Cleanup of wallet owner API, rustdoc documentation (#2036)
* doc start * rustfmt * tightening up wallet owner API * rustfmt * remove burn tx functions * more tx api documentation * rustfmt
This commit is contained in:
@@ -973,7 +973,7 @@ fn replicate_tx_fluff_failure() {
|
||||
slate = client1_w.send_tx_sync(dest, &slate)?;
|
||||
api.finalize_tx(&mut slate)?;
|
||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
api.post_tx(&slate, false)?;
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
}).unwrap();
|
||||
|
||||
|
||||
+29
-42
@@ -15,10 +15,14 @@
|
||||
use clap::ArgMatches;
|
||||
use rpassword;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use serde_json as json;
|
||||
|
||||
use api::TLSConfig;
|
||||
use config::GlobalWalletConfig;
|
||||
use core::{core, global};
|
||||
@@ -328,7 +332,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
} else {
|
||||
let label = create.unwrap();
|
||||
let res = controller::owner_single_use(wallet, |api| {
|
||||
api.new_account_path(label)?;
|
||||
api.create_account_path(label)?;
|
||||
thread::sleep(Duration::from_millis(200));
|
||||
println!("Account: '{}' Created!", label);
|
||||
Ok(())
|
||||
@@ -460,7 +464,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
}
|
||||
if adapter.supports_sync() {
|
||||
let result = api.post_tx(&slate, fluff);
|
||||
let result = api.post_tx(&slate.tx, fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Tx sent",);
|
||||
@@ -513,7 +517,7 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
let mut slate = adapter.receive_tx_async(tx_file)?;
|
||||
let _ = api.finalize_tx(&mut slate).expect("Finalize failed");
|
||||
|
||||
let result = api.post_tx(&slate, fluff);
|
||||
let result = api.post_tx(&slate.tx, fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Transaction sent successfully, check the wallet again for confirmation.");
|
||||
@@ -525,24 +529,6 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
}
|
||||
}
|
||||
}
|
||||
("burn", Some(send_args)) => {
|
||||
let amount = send_args
|
||||
.value_of("amount")
|
||||
.expect("Amount to burn required");
|
||||
let amount = core::amount_from_hr_string(amount)
|
||||
.expect("Could not parse amount as number with optional decimal point.");
|
||||
let minimum_confirmations: u64 = send_args
|
||||
.value_of("minimum_confirmations")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.expect("Could not parse minimum_confirmations as a whole number.");
|
||||
let max_outputs = 500;
|
||||
api.issue_burn_tx(amount, minimum_confirmations, max_outputs)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!("Error burning tx: {:?} Config: {:?}", e, wallet_config)
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
("info", Some(args)) => {
|
||||
let minimum_confirmations: u64 = args
|
||||
.value_of("minimum_confirmations")
|
||||
@@ -651,32 +637,33 @@ pub fn wallet_command(wallet_args: &ArgMatches, config: GlobalWalletConfig) -> i
|
||||
|
||||
let dump_file = repost_args.value_of("dumpfile");
|
||||
let fluff = repost_args.is_present("fluff");
|
||||
let (_, txs) = api.retrieve_txs(true, Some(tx_id), None)?;
|
||||
let stored_tx = txs[0].get_stored_tx();
|
||||
if stored_tx.is_none() {
|
||||
println!(
|
||||
"Transaction with id {} does not have transaction data. Not reposting.",
|
||||
tx_id
|
||||
);
|
||||
std::process::exit(0);
|
||||
}
|
||||
match dump_file {
|
||||
None => {
|
||||
let result = api.post_stored_tx(tx_id, fluff);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
info!("Reposted transaction at {}", tx_id);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Transaction reposting failed: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
if txs[0].confirmed {
|
||||
println!("Transaction with id {} is confirmed. Not reposting.", tx_id);
|
||||
std::process::exit(0);
|
||||
}
|
||||
api.post_tx(&stored_tx.unwrap(), fluff)?;
|
||||
info!("Reposted transaction at {}", tx_id);
|
||||
println!("Reposted transaction at {}", tx_id);
|
||||
Ok(())
|
||||
}
|
||||
Some(f) => {
|
||||
let result = api.dump_stored_tx(tx_id, true, f);
|
||||
match result {
|
||||
Ok(_) => {
|
||||
warn!("Dumped transaction data for tx {} to {}", tx_id, f);
|
||||
Ok(())
|
||||
}
|
||||
Err(e) => {
|
||||
error!("Transaction reposting failed: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
let mut tx_file = File::create(f)?;
|
||||
tx_file.write_all(json::to_string(&stored_tx).unwrap().as_bytes())?;
|
||||
tx_file.sync_all()?;
|
||||
info!("Dumped transaction data for tx {} to {}", tx_id, f);
|
||||
println!("Dumped transaction data for tx {} to {}", tx_id, f);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,31 +222,31 @@ where
|
||||
api.retrieve_txs(update_from_node, tx_id, tx_slate_id)
|
||||
}
|
||||
|
||||
fn dump_stored_tx(
|
||||
fn retrieve_stored_tx(
|
||||
&self,
|
||||
req: &Request<Body>,
|
||||
api: APIOwner<T, C, K>,
|
||||
) -> Result<Transaction, Error> {
|
||||
) -> Result<(bool, Option<Transaction>), Error> {
|
||||
let params = parse_params(req);
|
||||
if let Some(id_string) = params.get("id") {
|
||||
match id_string[0].parse() {
|
||||
Ok(id) => match api.dump_stored_tx(id, false, "") {
|
||||
Ok(tx) => Ok(tx),
|
||||
Ok(id) => match api.retrieve_txs(true, Some(id), None) {
|
||||
Ok((_, txs)) => Ok((txs[0].confirmed, txs[0].get_stored_tx())),
|
||||
Err(e) => {
|
||||
error!("dump_stored_tx: failed with error: {}", e);
|
||||
error!("retrieve_stored_tx: failed with error: {}", e);
|
||||
Err(e)
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
error!("dump_stored_tx: could not parse id: {}", e);
|
||||
error!("retrieve_stored_tx: could not parse id: {}", e);
|
||||
Err(ErrorKind::TransactionDumpError(
|
||||
"dump_stored_tx: cannot dump transaction. Could not parse id in request.",
|
||||
"retrieve_stored_tx: cannot dump transaction. Could not parse id in request.",
|
||||
).into())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Err(ErrorKind::TransactionDumpError(
|
||||
"dump_stored_tx: Cannot dump transaction. Missing id param in request.",
|
||||
"retrieve_stored_tx: Cannot retrieve transaction. Missing id param in request.",
|
||||
).into())
|
||||
}
|
||||
}
|
||||
@@ -292,7 +292,7 @@ where
|
||||
"retrieve_summary_info" => json_response(&self.retrieve_summary_info(req, api)?),
|
||||
"node_height" => json_response(&self.node_height(req, api)?),
|
||||
"retrieve_txs" => json_response(&self.retrieve_txs(req, api)?),
|
||||
"dump_stored_tx" => json_response(&self.dump_stored_tx(req, api)?),
|
||||
"retrieve_stored_tx" => json_response(&self.retrieve_stored_tx(req, api)?),
|
||||
_ => response(StatusCode::BAD_REQUEST, ""),
|
||||
})
|
||||
}
|
||||
@@ -440,18 +440,6 @@ where
|
||||
)
|
||||
}
|
||||
|
||||
fn issue_burn_tx(
|
||||
&self,
|
||||
_req: Request<Body>,
|
||||
mut api: APIOwner<T, C, K>,
|
||||
) -> Box<Future<Item = (), Error = Error> + Send> {
|
||||
// TODO: Args
|
||||
Box::new(match api.issue_burn_tx(60, 10, 1000) {
|
||||
Ok(_) => ok(()),
|
||||
Err(e) => err(e),
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_post_request(&self, req: Request<Body>) -> WalletResponseFuture {
|
||||
let api = APIOwner::new(self.wallet.clone());
|
||||
match req
|
||||
@@ -478,10 +466,6 @@ where
|
||||
self.post_tx(req, api)
|
||||
.and_then(|_| ok(response(StatusCode::OK, ""))),
|
||||
),
|
||||
"issue_burn_tx" => Box::new(
|
||||
self.issue_burn_tx(req, api)
|
||||
.and_then(|_| ok(response(StatusCode::OK, ""))),
|
||||
),
|
||||
_ => Box::new(err(ErrorKind::GenericError(
|
||||
"Unknown error handling post request".to_owned(),
|
||||
).into())),
|
||||
|
||||
+329
-130
@@ -12,20 +12,28 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Wrappers around library functions, intended to split functions
|
||||
//! into external and internal APIs (i.e. functions for the local wallet
|
||||
//! vs. functions to interact with someone else)
|
||||
//! Still experimental, not sure this is the best way to do this
|
||||
//! Main interface into all wallet API functions.
|
||||
//! Wallet APIs are split into two seperate blocks of functionality
|
||||
//! called the 'Owner' and 'Foreign' APIs:
|
||||
//! * The 'Owner' API is intended to expose methods that are to be
|
||||
//! used by the wallet owner only. It is vital that this API is not
|
||||
//! exposed to anyone other than the owner of the wallet (i.e. the
|
||||
//! person with access to the seed and password.
|
||||
//! * The 'Foreign' API contains methods that other wallets will
|
||||
//! use to interact with the owner's wallet. This API can be exposed
|
||||
//! to the outside world, with the consideration as to how that can
|
||||
//! be done securely up to the implementor.
|
||||
//!
|
||||
//! Methods in both APIs are intended to be 'single use', that is to say each
|
||||
//! method will 'open' the wallet (load the keychain with its master seed), perform
|
||||
//! its operation, then 'close' the wallet (unloading references to the keychain and master
|
||||
//! seed).
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::Arc;
|
||||
use util::Mutex;
|
||||
use uuid::Uuid;
|
||||
|
||||
use serde_json as json;
|
||||
|
||||
use core::core::hash::Hashed;
|
||||
use core::core::Transaction;
|
||||
use core::ser;
|
||||
@@ -40,16 +48,15 @@ use libwallet::{Error, ErrorKind};
|
||||
use util;
|
||||
use util::secp::pedersen;
|
||||
|
||||
/// Wrapper around internal API functions, containing a reference to
|
||||
/// the wallet/keychain that they're acting upon
|
||||
/// Functions intended for use by the owner (e.g. master seed holder) of the wallet.
|
||||
pub struct APIOwner<W: ?Sized, C, K>
|
||||
where
|
||||
W: WalletBackend<C, K>,
|
||||
C: NodeClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Wallet, contains its keychain (TODO: Split these up into 2 traits
|
||||
/// perhaps)
|
||||
/// A reference-counted mutex to an implementation of the
|
||||
/// [WalletBackend](../types/trait.WalletBackend.html) trait.
|
||||
pub wallet: Arc<Mutex<W>>,
|
||||
phantom: PhantomData<K>,
|
||||
phantom_c: PhantomData<C>,
|
||||
@@ -61,7 +68,52 @@ where
|
||||
C: NodeClient,
|
||||
K: Keychain,
|
||||
{
|
||||
/// Create new API instance
|
||||
/// Create a new API instance with the given wallet instance. All subsequent
|
||||
/// API calls will operate on this instance of the wallet.
|
||||
///
|
||||
/// Each method will call the [WalletBackend](../types/trait.WalletBackend.html)'s
|
||||
/// [open_with_credentials](../types/trait.WalletBackend.html#tymethod.open_with_credentials)
|
||||
/// (initialising a keychain with the master seed,) perform its operation, then close the keychain
|
||||
/// with a call to [close](../types/trait.WalletBackend.html#tymethod.close)
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `wallet_in` - A reference-counted mutex containing an implementation of the
|
||||
/// [WalletBackend](../types/trait.WalletBackend.html) trait.
|
||||
///
|
||||
/// # Returns
|
||||
/// * An instance of the OwnerAPI holding a reference to the provided wallet
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # extern crate grin_wallet as wallet;
|
||||
/// # extern crate grin_keychain as keychain;
|
||||
/// # extern crate grin_util as util;
|
||||
///
|
||||
/// use std::sync::Arc;
|
||||
/// use util::Mutex;
|
||||
///
|
||||
/// use keychain::ExtKeychain;
|
||||
/// use wallet::libwallet::api::APIOwner;
|
||||
///
|
||||
/// // These contain sample implementations of each part needed for a wallet
|
||||
/// use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
///
|
||||
/// let mut wallet_config = WalletConfig::default();
|
||||
///
|
||||
/// // A NodeClient must first be created to handle communication between
|
||||
/// // the wallet and the node.
|
||||
///
|
||||
/// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
/// let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// Arc::new(Mutex::new(
|
||||
/// LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// ));
|
||||
///
|
||||
/// let api_owner = APIOwner::new(wallet.clone());
|
||||
/// // .. perform wallet operations
|
||||
///
|
||||
/// ```
|
||||
|
||||
pub fn new(wallet_in: Arc<Mutex<W>>) -> Self {
|
||||
APIOwner {
|
||||
wallet: wallet_in,
|
||||
@@ -70,9 +122,214 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempt to update and retrieve outputs
|
||||
/// Return (whether the outputs were validated against a node, OutputData)
|
||||
/// if tx_id is some then only retrieve outputs for associated transaction
|
||||
/// Returns a list of accounts stored in the wallet (i.e. mappings between
|
||||
/// user-specified labels and BIP32 derivation paths.
|
||||
///
|
||||
/// # Returns
|
||||
/// * Result Containing:
|
||||
/// * A Vector of [AcctPathMapping](../types/struct.AcctPathMapping.html) data
|
||||
/// * or [libwallet::Error](../struct.Error.html) if an error is encountered.
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// * A wallet should always have the path with the label 'default' path defined,
|
||||
/// with path m/0/0
|
||||
/// * This method does not need to use the wallet seed or keychain.
|
||||
///
|
||||
/// # Example
|
||||
/// Set up as in [new](struct.APIOwner.html#method.new) method above.
|
||||
/// ```
|
||||
/// # extern crate grin_wallet as wallet;
|
||||
/// # extern crate grin_keychain as keychain;
|
||||
/// # extern crate grin_util as util;
|
||||
/// # use std::sync::Arc;
|
||||
/// # use util::Mutex;
|
||||
/// # use keychain::ExtKeychain;
|
||||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # let mut wallet_config = WalletConfig::default();
|
||||
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
/// # LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// # ));
|
||||
///
|
||||
/// let api_owner = APIOwner::new(wallet.clone());
|
||||
///
|
||||
/// let result = api_owner.accounts();
|
||||
///
|
||||
/// if let Ok(accts) = result {
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn accounts(&self) -> Result<Vec<AcctPathMapping>, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
keys::accounts(&mut *w)
|
||||
}
|
||||
|
||||
/// Creates a new 'account', which is a mapping of a user-specified
|
||||
/// label to a BIP32 path
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `label` - A human readable label to which to map the new BIP32 Path
|
||||
///
|
||||
/// # Returns
|
||||
/// * Result Containing:
|
||||
/// * A [Keychain Identifier](#) for the new path
|
||||
/// * or [libwallet::Error](../struct.Error.html) if an error is encountered.
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// * Wallets should be initialised with the 'default' path mapped to `m/0/0`
|
||||
/// * Each call to this function will increment the first element of the path
|
||||
/// so the first call will create an account at `m/1/0` and the second at
|
||||
/// `m/2/0` etc. . .
|
||||
/// * The account path is used throughout as the parent key for most key-derivation
|
||||
/// operations. See [set_active_account](struct.APIOwner.html#method.set_active_account) for
|
||||
/// further details.
|
||||
///
|
||||
/// * This function does not need to use the root wallet seed or keychain.
|
||||
///
|
||||
/// # Example
|
||||
/// Set up as in [new](struct.APIOwner.html#method.new) method above.
|
||||
/// ```
|
||||
/// # extern crate grin_wallet as wallet;
|
||||
/// # extern crate grin_keychain as keychain;
|
||||
/// # extern crate grin_util as util;
|
||||
/// # use std::sync::Arc;
|
||||
/// # use util::Mutex;
|
||||
/// # use keychain::ExtKeychain;
|
||||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # let mut wallet_config = WalletConfig::default();
|
||||
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
/// # LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// # ));
|
||||
///
|
||||
/// let api_owner = APIOwner::new(wallet.clone());
|
||||
///
|
||||
/// let result = api_owner.create_account_path("account1");
|
||||
///
|
||||
/// if let Ok(identifier) = result {
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn create_account_path(&self, label: &str) -> Result<Identifier, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
keys::new_acct_path(&mut *w, label)
|
||||
}
|
||||
|
||||
/// Sets the wallet's currently active account. This sets the
|
||||
/// BIP32 parent path used for most key-derivation operations.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `label` - The human readable label for the account. Accounts can be retrieved via
|
||||
/// the [account](struct.APIOwner.html#method.accounts) method
|
||||
/// # Returns
|
||||
/// * Result Containing:
|
||||
/// * `Ok(())` if the path was correctly set
|
||||
/// * or [libwallet::Error](../struct.Error.html) if an error is encountered.
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// * Wallet parent paths are 2 path elements long, e.g. `m/0/0` is the path
|
||||
/// labelled 'default'. Keys derived from this parent path are 3 elements long,
|
||||
/// e.g. the secret keys derived from the `m/0/0` path will be at paths `m/0/0/0`,
|
||||
/// `m/0/0/1` etc...
|
||||
///
|
||||
/// * This function does not need to use the root wallet seed or keychain.
|
||||
///
|
||||
/// # Example
|
||||
/// Set up as in [new](struct.APIOwner.html#method.new) method above.
|
||||
/// ```
|
||||
/// # extern crate grin_wallet as wallet;
|
||||
/// # extern crate grin_keychain as keychain;
|
||||
/// # extern crate grin_util as util;
|
||||
/// # use std::sync::Arc;
|
||||
/// # use util::Mutex;
|
||||
/// # use keychain::ExtKeychain;
|
||||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # let mut wallet_config = WalletConfig::default();
|
||||
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
/// # LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// # ));
|
||||
///
|
||||
/// let api_owner = APIOwner::new(wallet.clone());
|
||||
///
|
||||
/// let result = api_owner.create_account_path("account1");
|
||||
///
|
||||
/// if let Ok(identifier) = result {
|
||||
/// // set the account active
|
||||
/// let result2 = api_owner.set_active_account("account1");
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn set_active_account(&self, label: &str) -> Result<(), Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
w.set_parent_key_id_by_name(label)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns a list of outputs from the active account in the wallet.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `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.
|
||||
/// * `refresh_from_node` - If true, the wallet will attempt to contact
|
||||
/// a node (via the [NodeClient](../types/trait.NodeClient.html)
|
||||
/// provided during wallet instantiation). If `false`, the results will
|
||||
/// contain output information that may be out-of-date (from the last time
|
||||
/// the wallet's output set was refreshed against the node).
|
||||
/// * `tx_id` - If `Some(i)`, only return the outputs associated with
|
||||
/// the transaction log entry of id `i`.
|
||||
///
|
||||
/// # Returns
|
||||
/// * (`bool`, `Vec<OutputData, Commitment>`) - A tuple:
|
||||
/// * The first `bool` element indicates whether the data was successfully
|
||||
/// refreshed from the node (note this may be false even if the `refresh_from_node`
|
||||
/// argument was set to `true`.
|
||||
/// * The second element contains the result set, of which each element is
|
||||
/// a mapping between the wallet's internal [OutputData](../types/struct.OutputData.html)
|
||||
/// and the Output commitment as identified in the chain's UTXO set
|
||||
///
|
||||
/// # Example
|
||||
/// Set up as in [new](struct.APIOwner.html#method.new) method above.
|
||||
/// ```
|
||||
/// # extern crate grin_wallet as wallet;
|
||||
/// # extern crate grin_keychain as keychain;
|
||||
/// # extern crate grin_util as util;
|
||||
/// # use std::sync::Arc;
|
||||
/// # use util::Mutex;
|
||||
/// # use keychain::ExtKeychain;
|
||||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # let mut wallet_config = WalletConfig::default();
|
||||
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
/// # LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// # ));
|
||||
///
|
||||
/// let api_owner = APIOwner::new(wallet.clone());
|
||||
/// let show_spent = false;
|
||||
/// let update_from_node = true;
|
||||
/// let tx_id = None;
|
||||
///
|
||||
/// let result = api_owner.retrieve_outputs(show_spent, update_from_node, tx_id);
|
||||
///
|
||||
/// if let Ok((was_updated, output_mapping)) = result {
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn retrieve_outputs(
|
||||
&self,
|
||||
include_spent: bool,
|
||||
@@ -97,8 +354,59 @@ where
|
||||
res
|
||||
}
|
||||
|
||||
/// Attempt to update outputs and retrieve transactions
|
||||
/// Return (whether the outputs were validated against a node, OutputData)
|
||||
/// Returns a list of [Transaction Log Entries](../types/struct.TxLogEntry.html)
|
||||
/// from the active account in the wallet.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `refresh_from_node` - If true, the wallet will attempt to contact
|
||||
/// a node (via the [NodeClient](../types/trait.NodeClient.html)
|
||||
/// provided during wallet instantiation). If `false`, the results will
|
||||
/// contain transaction information that may be out-of-date (from the last time
|
||||
/// the wallet's output set was refreshed against the node).
|
||||
/// * `tx_id` - If `Some(i)`, only return the transactions associated with
|
||||
/// the transaction log entry of id `i`.
|
||||
/// * `tx_slate_id` - If `Some(uuid)`, only return transactions associated with
|
||||
/// the given [Slate](../../libtx/slate/struct.Slate.html) uuid.
|
||||
///
|
||||
/// # Returns
|
||||
/// * (`bool`, `Vec<[TxLogEntry](../types/struct.TxLogEntry.html)>`) - A tuple:
|
||||
/// * The first `bool` element indicates whether the data was successfully
|
||||
/// refreshed from the node (note this may be false even if the `refresh_from_node`
|
||||
/// argument was set to `true`.
|
||||
/// * The second element contains the set of retrieved
|
||||
/// [TxLogEntries](../types/struct/TxLogEntry.html)
|
||||
///
|
||||
/// # Example
|
||||
/// Set up as in [new](struct.APIOwner.html#method.new) method above.
|
||||
/// ```
|
||||
/// # extern crate grin_wallet as wallet;
|
||||
/// # extern crate grin_keychain as keychain;
|
||||
/// # extern crate grin_util as util;
|
||||
/// # use std::sync::Arc;
|
||||
/// # use util::Mutex;
|
||||
/// # use keychain::ExtKeychain;
|
||||
/// # use wallet::libwallet::api::APIOwner;
|
||||
/// # use wallet::{LMDBBackend, HTTPNodeClient, WalletBackend, WalletConfig};
|
||||
/// # let mut wallet_config = WalletConfig::default();
|
||||
/// # let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
|
||||
/// # let mut wallet:Arc<Mutex<WalletBackend<HTTPNodeClient, ExtKeychain>>> =
|
||||
/// # Arc::new(Mutex::new(
|
||||
/// # LMDBBackend::new(wallet_config.clone(), "", node_client).unwrap()
|
||||
/// # ));
|
||||
///
|
||||
/// let api_owner = APIOwner::new(wallet.clone());
|
||||
/// let update_from_node = true;
|
||||
/// let tx_id = None;
|
||||
/// let tx_slate_id = None;
|
||||
///
|
||||
/// // Return all TxLogEntries
|
||||
/// let result = api_owner.retrieve_txs(update_from_node, tx_id, tx_slate_id);
|
||||
///
|
||||
/// if let Ok((was_updated, tx_log_entries)) = result {
|
||||
/// //...
|
||||
/// }
|
||||
/// ```
|
||||
|
||||
pub fn retrieve_txs(
|
||||
&self,
|
||||
refresh_from_node: bool,
|
||||
@@ -145,18 +453,6 @@ where
|
||||
res
|
||||
}
|
||||
|
||||
/// Return list of existing account -> Path mappings
|
||||
pub fn accounts(&mut self) -> Result<Vec<AcctPathMapping>, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
keys::accounts(&mut *w)
|
||||
}
|
||||
|
||||
/// Create a new account path
|
||||
pub fn new_account_path(&mut self, label: &str) -> Result<Identifier, Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
keys::new_acct_path(&mut *w, label)
|
||||
}
|
||||
|
||||
/// Creates a new partial transaction for the given amount
|
||||
pub fn initiate_tx(
|
||||
&mut self,
|
||||
@@ -260,33 +556,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Issue a burn TX
|
||||
pub fn issue_burn_tx(
|
||||
&mut self,
|
||||
amount: u64,
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
) -> Result<(), Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
w.open_with_credentials()?;
|
||||
let parent_key_id = w.parent_key_id();
|
||||
let tx_burn = tx::issue_burn_tx(
|
||||
&mut *w,
|
||||
amount,
|
||||
minimum_confirmations,
|
||||
max_outputs,
|
||||
&parent_key_id,
|
||||
)?;
|
||||
let tx_hex = util::to_hex(ser::ser_vec(&tx_burn).unwrap());
|
||||
w.w2n_client()
|
||||
.post_tx(&TxWrapper { tx_hex: tx_hex }, false)?;
|
||||
w.close()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Posts a transaction to the chain
|
||||
pub fn post_tx(&self, slate: &Slate, fluff: bool) -> Result<(), Error> {
|
||||
let tx_hex = util::to_hex(ser::ser_vec(&slate.tx).unwrap());
|
||||
pub fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), Error> {
|
||||
let tx_hex = util::to_hex(ser::ser_vec(tx).unwrap());
|
||||
let client = {
|
||||
let mut w = self.wallet.lock();
|
||||
w.w2n_client().clone()
|
||||
@@ -298,86 +570,13 @@ where
|
||||
} else {
|
||||
debug!(
|
||||
"api: post_tx: successfully posted tx: {}, fluff? {}",
|
||||
slate.tx.hash(),
|
||||
tx.hash(),
|
||||
fluff
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes stored transaction data to a given file
|
||||
pub fn dump_stored_tx(
|
||||
&self,
|
||||
tx_id: u32,
|
||||
write_to_disk: bool,
|
||||
dest: &str,
|
||||
) -> Result<Transaction, Error> {
|
||||
let (confirmed, tx_hex) = {
|
||||
let mut w = self.wallet.lock();
|
||||
w.open_with_credentials()?;
|
||||
let parent_key_id = w.parent_key_id();
|
||||
let res = tx::retrieve_tx_hex(&mut *w, &parent_key_id, tx_id)?;
|
||||
w.close()?;
|
||||
res
|
||||
};
|
||||
if confirmed {
|
||||
warn!(
|
||||
"api: dump_stored_tx: transaction at {} is already confirmed.",
|
||||
tx_id
|
||||
);
|
||||
}
|
||||
if tx_hex.is_none() {
|
||||
error!(
|
||||
"api: dump_stored_tx: completed transaction at {} does not exist.",
|
||||
tx_id
|
||||
);
|
||||
return Err(ErrorKind::TransactionBuildingNotCompleted(tx_id))?;
|
||||
}
|
||||
let tx_bin = util::from_hex(tx_hex.unwrap()).unwrap();
|
||||
let tx = ser::deserialize::<Transaction>(&mut &tx_bin[..])?;
|
||||
if write_to_disk {
|
||||
let mut tx_file = File::create(dest)?;
|
||||
tx_file.write_all(json::to_string(&tx).unwrap().as_bytes())?;
|
||||
tx_file.sync_all()?;
|
||||
}
|
||||
Ok(tx)
|
||||
}
|
||||
|
||||
/// (Re)Posts a transaction that's already been stored to the chain
|
||||
pub fn post_stored_tx(&self, tx_id: u32, fluff: bool) -> Result<(), Error> {
|
||||
let client;
|
||||
let (confirmed, tx_hex) = {
|
||||
let mut w = self.wallet.lock();
|
||||
w.open_with_credentials()?;
|
||||
let parent_key_id = w.parent_key_id();
|
||||
client = w.w2n_client().clone();
|
||||
let res = tx::retrieve_tx_hex(&mut *w, &parent_key_id, tx_id)?;
|
||||
w.close()?;
|
||||
res
|
||||
};
|
||||
if confirmed {
|
||||
error!(
|
||||
"api: repost_tx: transaction at {} is confirmed. NOT resending.",
|
||||
tx_id
|
||||
);
|
||||
return Err(ErrorKind::TransactionAlreadyConfirmed)?;
|
||||
}
|
||||
if tx_hex.is_none() {
|
||||
error!(
|
||||
"api: repost_tx: completed transaction at {} does not exist.",
|
||||
tx_id
|
||||
);
|
||||
return Err(ErrorKind::TransactionBuildingNotCompleted(tx_id))?;
|
||||
}
|
||||
client.post_tx(
|
||||
&TxWrapper {
|
||||
tx_hex: tx_hex.unwrap(),
|
||||
},
|
||||
fluff,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attempt to restore contents of wallet
|
||||
pub fn restore(&mut self) -> Result<(), Error> {
|
||||
let mut w = self.wallet.lock();
|
||||
|
||||
@@ -14,16 +14,12 @@
|
||||
|
||||
//! Transaction building functions
|
||||
|
||||
use std::sync::Arc;
|
||||
use util::{self, RwLock};
|
||||
use util;
|
||||
use uuid::Uuid;
|
||||
|
||||
use core::core::verifier_cache::LruVerifierCache;
|
||||
use core::core::Transaction;
|
||||
use core::ser;
|
||||
use keychain::{Identifier, Keychain};
|
||||
use libtx::slate::Slate;
|
||||
use libtx::{build, tx_fee};
|
||||
use libwallet::internal::{selection, updater};
|
||||
use libwallet::types::{Context, NodeClient, TxLogEntryType, WalletBackend};
|
||||
use libwallet::{Error, ErrorKind};
|
||||
@@ -231,58 +227,6 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Issue a burn tx
|
||||
pub fn issue_burn_tx<T: ?Sized, C, K>(
|
||||
wallet: &mut T,
|
||||
amount: u64,
|
||||
minimum_confirmations: u64,
|
||||
max_outputs: usize,
|
||||
parent_key_id: &Identifier,
|
||||
) -> Result<Transaction, Error>
|
||||
where
|
||||
T: WalletBackend<C, K>,
|
||||
C: NodeClient,
|
||||
K: Keychain,
|
||||
{
|
||||
// TODO
|
||||
// let keychain = &Keychain::burn_enabled(wallet.keychain(),
|
||||
// &Identifier::zero());
|
||||
let keychain = wallet.keychain().clone();
|
||||
|
||||
let current_height = wallet.w2n_client().get_chain_height()?;
|
||||
|
||||
let _ = updater::refresh_outputs(wallet, parent_key_id);
|
||||
|
||||
// select some spendable coins from the wallet
|
||||
let (_, coins) = selection::select_coins(
|
||||
wallet,
|
||||
amount,
|
||||
current_height,
|
||||
minimum_confirmations,
|
||||
max_outputs,
|
||||
false,
|
||||
parent_key_id,
|
||||
);
|
||||
|
||||
debug!("selected some coins - {}", coins.len());
|
||||
|
||||
let fee = tx_fee(coins.len(), 2, 1, None);
|
||||
let num_change_outputs = 1;
|
||||
let (mut parts, _) =
|
||||
selection::inputs_and_change(&coins, wallet, amount, fee, num_change_outputs)?;
|
||||
|
||||
//TODO: If we end up using this, create change output here
|
||||
|
||||
// add burn output and fees
|
||||
parts.push(build::output(amount - fee, Identifier::zero()));
|
||||
|
||||
// finalize the burn transaction and send
|
||||
let tx_burn = build::transaction(parts, &keychain)?;
|
||||
let verifier_cache = Arc::new(RwLock::new(LruVerifierCache::new()));
|
||||
tx_burn.validate(verifier_cache)?;
|
||||
Ok(tx_burn)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use keychain::{ExtKeychain, ExtKeychainPath, Keychain};
|
||||
|
||||
@@ -26,6 +26,7 @@ use failure::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
use core::core::hash::Hash;
|
||||
use core::core::Transaction;
|
||||
use core::ser;
|
||||
|
||||
use keychain::{Identifier, Keychain};
|
||||
@@ -33,6 +34,7 @@ use keychain::{Identifier, Keychain};
|
||||
use libtx::aggsig;
|
||||
use libwallet::error::{Error, ErrorKind};
|
||||
|
||||
use util;
|
||||
use util::secp::key::{PublicKey, SecretKey};
|
||||
use util::secp::{self, pedersen, Secp256k1};
|
||||
|
||||
@@ -639,6 +641,17 @@ impl TxLogEntry {
|
||||
pub fn update_confirmation_ts(&mut self) {
|
||||
self.confirmation_ts = Some(Utc::now());
|
||||
}
|
||||
|
||||
/// Retrieve the stored transaction, if any
|
||||
pub fn get_stored_tx(&self) -> Option<Transaction> {
|
||||
match self.tx_hex.as_ref() {
|
||||
None => None,
|
||||
Some(t) => {
|
||||
let tx_bin = util::from_hex(t.clone()).unwrap();
|
||||
Some(ser::deserialize::<Transaction>(&mut &tx_bin[..]).unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Map of named accounts to BIP32 paths
|
||||
|
||||
@@ -86,21 +86,21 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let new_path = api.new_account_path("account1").unwrap();
|
||||
let new_path = api.create_account_path("account1").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0));
|
||||
let new_path = api.new_account_path("account2").unwrap();
|
||||
let new_path = api.create_account_path("account2").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 2, 0, 0, 0));
|
||||
let new_path = api.new_account_path("account3").unwrap();
|
||||
let new_path = api.create_account_path("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.new_account_path("account1");
|
||||
let res = api.create_account_path("account1");
|
||||
assert!(res.is_err());
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add account to wallet 2
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
let new_path = api.new_account_path("listener_account").unwrap();
|
||||
let new_path = api.create_account_path("listener_account").unwrap();
|
||||
assert_eq!(new_path, ExtKeychain::derive_key_id(2, 1, 0, 0, 0));
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -194,7 +194,7 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate)?;
|
||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
api.finalize_tx(&mut slate)?;
|
||||
api.post_tx(&slate, false)?;
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
||||
@@ -376,11 +376,11 @@ impl WalletCommAdapter for LocalWalletClient {
|
||||
|
||||
fn listen(
|
||||
&self,
|
||||
params: HashMap<String, String>,
|
||||
config: WalletConfig,
|
||||
passphrase: &str,
|
||||
account: &str,
|
||||
node_api_secret: Option<String>,
|
||||
_params: HashMap<String, String>,
|
||||
_config: WalletConfig,
|
||||
_passphrase: &str,
|
||||
_account: &str,
|
||||
_node_api_secret: Option<String>,
|
||||
) -> Result<(), libwallet::Error> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
@@ -74,15 +74,15 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.new_account_path("mining")?;
|
||||
api.new_account_path("listener")?;
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.new_account_path("account1")?;
|
||||
api.new_account_path("account2")?;
|
||||
api.create_account_path("account1")?;
|
||||
api.create_account_path("account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -141,7 +141,7 @@ fn file_exchange_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
let adapter = FileWalletCommAdapter::new();
|
||||
let mut slate = adapter.receive_tx_async(&receive_file)?;
|
||||
api.finalize_tx(&mut slate)?;
|
||||
api.post_tx(&slate, false);
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -75,15 +75,15 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.new_account_path("mining")?;
|
||||
api.new_account_path("listener")?;
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.new_account_path("account1")?;
|
||||
api.new_account_path("account2")?;
|
||||
api.create_account_path("account1")?;
|
||||
api.create_account_path("account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -155,7 +155,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
// Now repost from cached
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||
api.post_stored_tx(txs[0].id, false)?;
|
||||
api.post_tx(&txs[0].get_stored_tx().unwrap(), false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
@@ -220,7 +220,7 @@ fn file_repost_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
// Now repost from cached
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
let (_, txs) = api.retrieve_txs(true, None, Some(slate.id))?;
|
||||
api.post_stored_tx(txs[0].id, false)?;
|
||||
api.post_tx(&txs[0].get_stored_tx().unwrap(), false)?;
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -198,8 +198,8 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
|
||||
// wallet 2 will use another account
|
||||
wallet::controller::owner_single_use(wallet2.clone(), |api| {
|
||||
api.new_account_path("account1")?;
|
||||
api.new_account_path("account2")?;
|
||||
api.create_account_path("account1")?;
|
||||
api.create_account_path("account2")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -240,7 +240,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
slate = client1.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
sender_api.finalize_tx(&mut slate)?;
|
||||
sender_api.post_tx(&slate, false)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -261,7 +261,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
slate = client1.send_tx_slate_direct("wallet3", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
sender_api.finalize_tx(&mut slate)?;
|
||||
sender_api.post_tx(&slate, false)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -282,7 +282,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
sender_api.finalize_tx(&mut slate)?;
|
||||
sender_api.post_tx(&slate, false)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -309,7 +309,7 @@ fn setup_restore(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
slate = client3.send_tx_slate_direct("wallet2", &slate_i)?;
|
||||
sender_api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
sender_api.finalize_tx(&mut slate)?;
|
||||
sender_api.post_tx(&slate, false)?;
|
||||
sender_api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
|
||||
@@ -72,8 +72,8 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
|
||||
// add some accounts
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.new_account_path("mining")?;
|
||||
api.new_account_path("listener")?;
|
||||
api.create_account_path("mining")?;
|
||||
api.create_account_path("listener")?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -109,7 +109,7 @@ fn self_send_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
})?;
|
||||
api.finalize_tx(&mut slate)?;
|
||||
api.tx_lock_outputs(&slate, lock_fn)?;
|
||||
api.post_tx(&slate, false)?; // mines a block
|
||||
api.post_tx(&slate.tx, false)?; // mines a block
|
||||
bh += 1;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -157,7 +157,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
|
||||
// post transaction
|
||||
wallet::controller::owner_single_use(wallet1.clone(), |api| {
|
||||
api.post_tx(&slate, false)?;
|
||||
api.post_tx(&slate.tx, false)?;
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
@@ -255,13 +255,12 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {
|
||||
let (refreshed, _wallet1_info) = sender_api.retrieve_summary_info(true, 1)?;
|
||||
assert!(refreshed);
|
||||
let (_, txs) = sender_api.retrieve_txs(true, None, None)?;
|
||||
|
||||
// find the transaction
|
||||
let tx = txs
|
||||
.iter()
|
||||
.find(|t| t.tx_slate_id == Some(slate.id))
|
||||
.unwrap();
|
||||
sender_api.post_stored_tx(tx.id, false)?;
|
||||
sender_api.post_tx(&tx.get_stored_tx().unwrap(), false)?;
|
||||
let (_, wallet1_info) = sender_api.retrieve_summary_info(true, 1)?;
|
||||
// should be mined now
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user