Foreign API documentation and small cleanup (#31)

* verify slate messages documentation

* rustfmt

* foreign API documentation

* rustfmt
This commit is contained in:
Yeastplume
2019-03-29 08:46:12 +00:00
committed by GitHub
parent f756b10d78
commit 7b8fe92f53
13 changed files with 360 additions and 88 deletions
+259 -21
View File
@@ -12,19 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! Main interface into all wallet API functions.
//! Wallet APIs are split into two seperate blocks of functionality
//! called the 'Owner' and 'Foreign' APIs:
//!
//! * 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).
//! Foreign API External Definition
use crate::keychain::Keychain;
use crate::libwallet::api_impl::foreign;
@@ -35,8 +23,20 @@ use crate::util::Mutex;
use std::marker::PhantomData;
use std::sync::Arc;
/// Wrapper around external API functions, intended to communicate
/// with other parties
/// Main interface into all wallet API functions.
/// Wallet APIs are split into two seperate blocks of functionality
/// called the ['Owner'](struct.Owner.html) and ['Foreign'](struct.Foreign.html) APIs
///
/// * 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).
pub struct Foreign<W: ?Sized, C, K>
where
W: WalletBackend<C, K>,
@@ -58,7 +58,64 @@ 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`](../grin_wallet_libwallet/types/trait.WalletBackend.html)'s
/// [`open_with_credentials`](../grin_wallet_libwallet/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`](../grin_wallet_libwallet/types/trait.WalletBackend.html#tymethod.close)
///
/// # Arguments
/// * `wallet_in` - A reference-counted mutex containing an implementation of the
/// [`WalletBackend`](../grin_wallet_libwallet/types/trait.WalletBackend.html) trait.
///
/// # Returns
/// * An instance of the ForeignApi holding a reference to the provided wallet
///
/// # Example
/// ```
/// use grin_wallet_util::grin_keychain as keychain;
/// use grin_wallet_util::grin_util as util;
/// use grin_wallet_api as api;
/// use grin_wallet_config as config;
/// use grin_wallet_impls as impls;
/// use grin_wallet_libwallet as libwallet;
///
/// use keychain::ExtKeychain;
/// use tempfile::tempdir;
///
/// use std::sync::Arc;
/// use util::Mutex;
///
/// use api::Foreign;
/// use config::WalletConfig;
/// use impls::{HTTPNodeClient, LMDBBackend};
/// use libwallet::types::WalletBackend;
///
/// let mut wallet_config = WalletConfig::default();
/// # let dir = tempdir().map_err(|e| format!("{:#?}", e)).unwrap();
/// # let dir = dir
/// # .path()
/// # .to_str()
/// # .ok_or("Failed to convert tmpdir path to string.".to_owned())
/// # .unwrap();
/// # wallet_config.data_file_dir = dir.to_owned();
///
/// // 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 = Foreign::new(wallet.clone());
/// // .. perform wallet operations
///
/// ```
pub fn new(wallet_in: Arc<Mutex<W>>) -> Self {
Foreign {
wallet: wallet_in,
@@ -68,7 +125,56 @@ where
}
}
/// Build a new (potential) coinbase transaction in the wallet
/// Builds a new unconfirmed coinbase output in the wallet, generally for inclusion in a
/// potential new block's coinbase output during mining.
///
/// All potential coinbase outputs are created as 'Unconfirmed' with the coinbase flag set.
/// If a potential coinbase output is found on the chain after a wallet update, it status
/// is set to `Unsent` and a [Transaction Log Entry](../grin_wallet_libwallet/types/struct.TxLogEntry.html)
/// will be created. Note the output will be unspendable until the coinbase maturity period
/// has expired.
///
/// # Arguments
///
/// * `block_fees` - A [`BlockFees`](../grin_wallet_libwallet/types/struct.BlockFees.html)
/// struct, set up as follows:
///
/// `fees` - should contain the sum of all transaction fees included in the potential
/// block
///
/// `height` - should contain the block height being mined
///
/// `key_id` - can optionally contain the corresponding keychain ID in the wallet to use
/// to create the output's blinding factor. If this is not provided, the next available key
/// id will be assigned
///
/// # Returns
/// * `Ok`([`cb_data`](../grin_wallet_libwallet/types/struct.CbData.html)`)` if successful. This
/// will contain the corresponding output, kernel and keyID used to create the coinbase output.
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
///
/// # Example
/// Set up as in [`new`](struct.Foreign.html#method.new) method above.
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone());
///
/// let block_fees = BlockFees {
/// fees: 800000,
/// height: 234323,
/// key_id: None,
/// };
/// // Build a new coinbase output
///
/// let res = api_foreign.build_coinbase(&block_fees);
///
/// if let Ok(cb_data) = res {
/// // cb_data is populated with coinbase output info
/// // ...
/// }
/// ```
pub fn build_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, Error> {
let mut w = self.wallet.lock();
w.open_with_credentials()?;
@@ -77,18 +183,110 @@ where
res
}
/// Verifies all messages in the slate match their public keys
/// Verifies all messages in the slate match their public keys.
///
/// The option messages themselves are part of the `participant_data` field within the slate.
/// Messages are signed with the same key used to sign for the paricipant's inputs, and can thus be
/// verified with the public key found in the `public_blind_excess` field. This function is a
/// simple helper to returns whether all signatures in the participant data match their public
/// keys.
///
/// # Arguments
///
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html).
///
/// # Returns
/// * `Ok(())` if successful and the signatures validate
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
///
/// # Example
/// Set up as in [`new`](struct.Foreign.html#method.new) method above.
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone());
///
/// # let slate = Slate::blank(2);
/// // Receive a slate via some means
///
/// let res = api_foreign.verify_slate_messages(&slate);
///
/// if let Err(e) = res {
/// // Messages don't validate, likely return an error
/// // ...
/// } else {
/// // Slate messages are fine
/// }
///
///
/// ```
pub fn verify_slate_messages(&self, slate: &Slate) -> Result<(), Error> {
foreign::verify_slate_messages(slate)
}
/// Receive a transaction from a sender
/// Recieve a tranaction created by another party, returning the modified
/// [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html) object, modified with
/// the recipient's output for the transaction amount, and public signature data. This slate can
/// then be sent back to the sender to finalize the transaction via the
/// [Owner API's `finalize_tx`](struct.Owner.html#method.finalize_tx) method.
///
/// This function creates a single output for the full amount, set to a status of
/// 'Awaiting finalization'. It will remain in this state until the wallet finds the
/// corresponding output on the chain, at which point it will become 'Unspent'. The slate
/// will be updated with the results of Signing round 1 and 2, adding the recipient's public
/// nonce, public excess value, and partial signature to the slate.
///
/// Also creates a corresponding [Transaction Log Entry](../grin_wallet_libwallet/types/struct.TxLogEntry.html)
/// in the wallet's transaction log.
///
/// # Arguments
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html).
/// The slate should contain the results of the sender's round 1 (e.g, public nonce and public
/// excess value).
/// * `dest_acct_name` - The name of the account into which the slate should be received. If
/// `None`, the default account is used.
/// * `message` - An optional participant message to include alongside the recipient's public
/// ParticipantData within the slate. This message will include a signature created with the
/// recipient'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.
///
/// # Returns
/// * a result containing:
/// * `Ok`([`slate`](../grin_wallet_libwallet/slate/struct.Slate.html)`)` if successful,
/// containing the new slate updated with the recipient's output and public signing information.
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
///
/// # Remarks
///
/// * This method will store a partially completed transaction in the wallet's transaction log.
///
/// # Example
/// Set up as in [new](struct.Foreign.html#method.new) method above.
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone());
/// # let slate = Slate::blank(2);
///
/// // . . .
/// // Obtain a sent slate somehow
/// let result = api_foreign.receive_tx(&slate, None, None);
///
/// if let Ok(slate) = result {
/// // Send back to recipient somehow
/// // ...
/// }
/// ```
pub fn receive_tx(
&self,
slate: &mut Slate,
slate: &Slate,
dest_acct_name: Option<&str>,
message: Option<String>,
) -> Result<(), Error> {
) -> Result<Slate, Error> {
let mut w = self.wallet.lock();
w.open_with_credentials()?;
let res = foreign::receive_tx(&mut *w, slate, dest_acct_name, message, self.doctest_mode);
@@ -96,3 +294,43 @@ where
res
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! doctest_helper_setup_doc_env_foreign {
($wallet:ident, $wallet_config:ident) => {
use grin_wallet_api as api;
use grin_wallet_config as config;
use grin_wallet_impls as impls;
use grin_wallet_libwallet as libwallet;
use grin_wallet_util::grin_keychain as keychain;
use grin_wallet_util::grin_util as util;
use libwallet::slate::Slate;
use keychain::ExtKeychain;
use tempfile::tempdir;
use std::sync::Arc;
use util::Mutex;
use api::Foreign;
use config::WalletConfig;
use impls::{HTTPNodeClient, LMDBBackend, WalletSeed};
use libwallet::types::{BlockFees, WalletBackend};
let dir = tempdir().map_err(|e| format!("{:#?}", e)).unwrap();
let dir = dir
.path()
.to_str()
.ok_or("Failed to convert tmpdir path to string.".to_owned())
.unwrap();
let mut wallet_config = WalletConfig::default();
wallet_config.data_file_dir = dir.to_owned();
let pw = "";
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(), pw, node_client).unwrap()),
);
};
}
+3 -3
View File
@@ -329,13 +329,13 @@ where
fn receive_tx(
&self,
mut slate: Slate,
slate: Slate,
dest_acct_name: Option<String>,
message: Option<String>,
) -> Result<Slate, ErrorKind> {
Foreign::receive_tx(
let slate = Foreign::receive_tx(
self,
&mut slate,
&slate,
dest_acct_name.as_ref().map(String::as_str),
message,
)
+25 -17
View File
@@ -12,19 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//! 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.
//!
//! 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).
//! Owner API External Definition
use crate::util::Mutex;
use chrono::prelude::*;
@@ -42,7 +30,20 @@ use crate::libwallet::types::{
};
use crate::libwallet::Error;
/// Functions intended for use by the owner (e.g. master seed holder) of the wallet.
/// Main interface into all wallet API functions.
/// Wallet APIs are split into two seperate blocks of functionality
/// called the ['Owner'](struct.Owner.html) and ['Foreign'](struct.Foreign.html) 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.
///
/// 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).
pub struct Owner<W: ?Sized, C, K>
where
W: WalletBackend<C, K>,
@@ -454,7 +455,7 @@ where
/// 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 keys, and will be publically verifiable. Note this message is for
/// 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.
@@ -668,7 +669,8 @@ where
/// outputs (via the [`tx_lock_outputs`](struct.Owner.html#method.tx_lock_outputs) function).
///
/// # Returns
/// * `Ok(())` if successful
/// * ``Ok([`slate`](../grin_wallet_libwallet/slate/struct.Slate.html))` if successful,
/// containing the new finalized slate.
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
///
/// # Example
@@ -868,12 +870,18 @@ where
/// Verifies all messages in the slate match their public keys.
///
/// The optional messages themselves are part of the `participant_data` field within the slate.
/// Messages are signed with the same key used to sign for the paricipant's inputs, and can thus be
/// verified with the public key found in the `public_blind_excess` field. This function is a
/// simple helper to returns whether all signatures in the participant data match their public
/// keys.
///
/// # Arguments
///
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html).
///
/// # Returns
/// * Ok(()) if successful and the signatures validate
/// * `Ok(())` if successful and the signatures validate
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered.
///
/// # Example
+1 -1
View File
@@ -1257,7 +1257,7 @@ pub fn run_doctest_owner(
{
let mut w2 = wallet2.lock();
w2.open_with_credentials().unwrap();
api_impl::foreign::receive_tx(&mut *w2, &mut slate, None, None, true).unwrap();
slate = api_impl::foreign::receive_tx(&mut *w2, &slate, None, None, true).unwrap();
w2.close().unwrap();
}
println!("RECIPIENT SLATE");