diff --git a/servers/tests/simulnet.rs b/servers/tests/simulnet.rs
index 849875c050..a7c9a757d2 100644
--- a/servers/tests/simulnet.rs
+++ b/servers/tests/simulnet.rs
@@ -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();
diff --git a/src/bin/cmd/wallet.rs b/src/bin/cmd/wallet.rs
index 7fa7b6b69d..7329d18bea 100644
--- a/src/bin/cmd/wallet.rs
+++ b/src/bin/cmd/wallet.rs
@@ -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(())
}
}
}
diff --git a/wallet/src/controller.rs b/wallet/src/controller.rs
index 5c783e052f..0028cbcd2b 100644
--- a/wallet/src/controller.rs
+++ b/wallet/src/controller.rs
@@ -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
,
api: APIOwner,
- ) -> Result {
+ ) -> Result<(bool, Option), 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, ""),
})
}
@@ -439,18 +439,6 @@ where
)
}
- fn issue_burn_tx(
- &self,
- _req: Request,
- mut api: APIOwner,
- ) -> Box + 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) -> WalletResponseFuture {
let api = APIOwner::new(self.wallet.clone());
match req
@@ -477,10 +465,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())),
diff --git a/wallet/src/libwallet/api.rs b/wallet/src/libwallet/api.rs
index 145f508db3..8e839157fd 100644
--- a/wallet/src/libwallet/api.rs
+++ b/wallet/src/libwallet/api.rs
@@ -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
where
W: WalletBackend,
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>,
phantom: PhantomData,
phantom_c: PhantomData,
@@ -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>> =
+ /// 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>) -> 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>> =
+ /// # 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, 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>> =
+ /// # 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 {
+ 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>> =
+ /// # 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`) - 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>> =
+ /// # 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>> =
+ /// # 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, 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 {
- 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 {
- 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::(&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();
diff --git a/wallet/src/libwallet/internal/tx.rs b/wallet/src/libwallet/internal/tx.rs
index 0884452edd..deae53479d 100644
--- a/wallet/src/libwallet/internal/tx.rs
+++ b/wallet/src/libwallet/internal/tx.rs
@@ -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(
- wallet: &mut T,
- amount: u64,
- minimum_confirmations: u64,
- max_outputs: usize,
- parent_key_id: &Identifier,
-) -> Result
-where
- T: WalletBackend,
- 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};
diff --git a/wallet/src/libwallet/types.rs b/wallet/src/libwallet/types.rs
index 4696df6a91..aa050a34ee 100644
--- a/wallet/src/libwallet/types.rs
+++ b/wallet/src/libwallet/types.rs
@@ -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 {
+ match self.tx_hex.as_ref() {
+ None => None,
+ Some(t) => {
+ let tx_bin = util::from_hex(t.clone()).unwrap();
+ Some(ser::deserialize::(&mut &tx_bin[..]).unwrap())
+ }
+ }
+ }
}
/// Map of named accounts to BIP32 paths
diff --git a/wallet/tests/accounts.rs b/wallet/tests/accounts.rs
index 58cecded22..40c6fce9c9 100644
--- a/wallet/tests/accounts.rs
+++ b/wallet/tests/accounts.rs
@@ -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(())
})?;
diff --git a/wallet/tests/common/testclient.rs b/wallet/tests/common/testclient.rs
index 4ef9cb3d5c..9a309144d9 100644
--- a/wallet/tests/common/testclient.rs
+++ b/wallet/tests/common/testclient.rs
@@ -376,11 +376,11 @@ impl WalletCommAdapter for LocalWalletClient {
fn listen(
&self,
- params: HashMap,
- config: WalletConfig,
- passphrase: &str,
- account: &str,
- node_api_secret: Option,
+ _params: HashMap,
+ _config: WalletConfig,
+ _passphrase: &str,
+ _account: &str,
+ _node_api_secret: Option,
) -> Result<(), libwallet::Error> {
unimplemented!();
}
diff --git a/wallet/tests/file.rs b/wallet/tests/file.rs
index 5b65aa77ac..03c0d6eac7 100644
--- a/wallet/tests/file.rs
+++ b/wallet/tests/file.rs
@@ -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(())
})?;
diff --git a/wallet/tests/repost.rs b/wallet/tests/repost.rs
index 7288fa58d7..0647ca0d53 100644
--- a/wallet/tests/repost.rs
+++ b/wallet/tests/repost.rs
@@ -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(())
})?;
diff --git a/wallet/tests/restore.rs b/wallet/tests/restore.rs
index 323de93f3d..ea782445e1 100644
--- a/wallet/tests/restore.rs
+++ b/wallet/tests/restore.rs
@@ -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(())
})?;
diff --git a/wallet/tests/self_send.rs b/wallet/tests/self_send.rs
index 5b4f09745d..5194fad34a 100644
--- a/wallet/tests/self_send.rs
+++ b/wallet/tests/self_send.rs
@@ -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(())
})?;
diff --git a/wallet/tests/transaction.rs b/wallet/tests/transaction.rs
index 11ffa3d5bd..30cc39f926 100644
--- a/wallet/tests/transaction.rs
+++ b/wallet/tests/transaction.rs
@@ -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!(