Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slatepack Workflow #423

Merged
merged 13 commits into from
Jun 3, 2020
Merged
175 changes: 87 additions & 88 deletions Cargo.lock

Large diffs are not rendered by default.

96 changes: 77 additions & 19 deletions api/src/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@

//! Foreign API External Definition

use crate::config::TorConfig;
use crate::keychain::Keychain;
use crate::libwallet::api_impl::foreign;
use crate::libwallet::{
BlockFees, CbData, Error, NodeClient, NodeVersionInfo, Slate, VersionInfo, WalletInst,
WalletLCProvider,
};
use crate::try_slatepack_sync_workflow;
use crate::util::secp::key::SecretKey;
use crate::util::Mutex;
use std::sync::Arc;
Expand All @@ -38,8 +40,10 @@ pub enum ForeignCheckMiddlewareFn {
VerifySlateMessages,
/// receive_tx
ReceiveTx,
/// finalize_invoice_tx
/// finalize_invoice_tx (delete HF3)
FinalizeInvoiceTx,
/// finalize_tx
FinalizeTx,
}

/// Main interface into all wallet API functions.
Expand Down Expand Up @@ -70,6 +74,9 @@ where
middleware: Option<ForeignCheckMiddleware>,
/// Stored keychain mask (in case the stored wallet seed is tokenized)
keychain_mask: Option<SecretKey>,
/// Optional TOR configuration, holding address of sender and
/// data directory
tor_config: Mutex<Option<TorConfig>>,
}

impl<'a, L, C, K> Foreign<'a, L, C, K>
Expand Down Expand Up @@ -158,7 +165,7 @@ where
/// // All wallet functions operate on an Arc::Mutex to allow multithreading where needed
/// let mut wallet = Arc::new(Mutex::new(wallet));
///
/// let api_foreign = Foreign::new(wallet.clone(), None, None);
/// let api_foreign = Foreign::new(wallet.clone(), None, None, false);
/// // .. perform wallet operations
///
/// ```
Expand All @@ -167,15 +174,30 @@ where
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
keychain_mask: Option<SecretKey>,
middleware: Option<ForeignCheckMiddleware>,
doctest_mode: bool,
) -> Self {
Foreign {
wallet_inst,
doctest_mode: false,
doctest_mode,
middleware,
keychain_mask,
tor_config: Mutex::new(None),
}
}

/// Set the TOR configuration for this instance of the ForeignAPI, used during
/// `recieve_tx` when a return address is specified
///
/// # Arguments
/// * `tor_config` - The optional [TorConfig](#) to use
/// # Returns
/// * Nothing

pub fn set_tor_config(&self, tor_config: Option<TorConfig>) {
let mut lock = self.tor_config.lock();
*lock = tor_config;
}

/// Return the version capabilities of the running ForeignApi Node
/// # Arguments
/// None
Expand All @@ -186,7 +208,7 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None, false);
///
/// let version_info = api_foreign.check_version();
/// // check and proceed accordingly
Expand Down Expand Up @@ -238,7 +260,7 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None, false);
///
/// let block_fees = BlockFees {
/// fees: 800000,
Expand Down Expand Up @@ -294,6 +316,9 @@ where
/// excess value).
/// * `dest_acct_name` - The name of the account into which the slate should be received. If
/// `None`, the default account is used.
/// * `r_addr` - If included, attempt to send the slate back to the sender using the slatepack sync
/// send (TOR). If providing this argument, check the `state` field of the slate to see if the
/// sync_send was successful (it should be S3 if the synced send sent successfully).
///
/// # Returns
/// * a result containing:
Expand All @@ -310,20 +335,25 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None, false);
/// # let slate = Slate::blank(2, false);
///
/// // . . .
/// // Obtain a sent slate somehow
/// let result = api_foreign.receive_tx(&slate, None);
/// 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: &Slate, dest_acct_name: Option<&str>) -> Result<Slate, Error> {
pub fn receive_tx(
&self,
slate: &Slate,
dest_acct_name: Option<&str>,
r_addr: Option<String>,
) -> Result<Slate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
if let Some(m) = self.middleware.as_ref() {
Expand All @@ -333,31 +363,50 @@ where
Some(slate),
)?;
}
foreign::receive_tx(
let ret_slate = foreign::receive_tx(
&mut **w,
(&self.keychain_mask).as_ref(),
slate,
dest_acct_name,
self.doctest_mode,
)
)?;
match r_addr {
Some(a) => {
let tor_config_lock = self.tor_config.lock();
let res = try_slatepack_sync_workflow(
&ret_slate,
&a,
tor_config_lock.clone(),
None,
true,
self.doctest_mode,
);
match res {
Ok(s) => return Ok(s.unwrap()),
Err(_) => return Ok(ret_slate),
}
}
None => Ok(ret_slate),
}
}

/// Finalizes an invoice transaction initiated by this wallet's Owner api.
/// Finalizes a (standard or invoice) transaction initiated by this wallet's Owner api.
/// This step assumes the paying party has completed round 1 and 2 of slate
/// creation, and added their partial signatures. The invoicer will verify
/// creation, and added their partial signatures. This wallet will verify
/// and add their partial sig, then create the finalized transaction,
/// ready to post to a node.
///
/// Note that this function DOES NOT POST the transaction to a node
/// for validation. This is done in separately via the
/// This function posts to the node if the `post_automatically`
/// argument is sent to true. Posting can be done in separately via the
/// [`post_tx`](struct.Owner.html#method.post_tx) function.
///
/// This function also stores the final transaction in the user's wallet files for retrieval
/// via the [`get_stored_tx`](struct.Owner.html#method.get_stored_tx) function.
///
/// # Arguments
/// * `slate` - The transaction [`Slate`](../grin_wallet_libwallet/slate/struct.Slate.html). The
/// payer should have filled in round 1 and 2.
/// * `post_automatically` - If true, post the finalized transaction to the configured listening
/// node
///
/// # Returns
/// * Ok([`slate`](../grin_wallet_libwallet/slate/struct.Slate.html)) if successful,
Expand All @@ -370,7 +419,7 @@ where
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_owner = Owner::new(wallet.clone(), None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None, false);
///
/// // . . .
/// // Issue the invoice tx via the owner API
Expand All @@ -385,11 +434,11 @@ where
/// // ...
/// # let slate = Slate::blank(2, true);
///
/// let slate = api_foreign.finalize_invoice_tx(&slate);
/// let slate = api_foreign.finalize_tx(&slate, true);
/// // if okay, then post via the owner API
/// ```

pub fn finalize_invoice_tx(&self, slate: &Slate) -> Result<Slate, Error> {
pub fn finalize_tx(&self, slate: &Slate, post_automatically: bool) -> Result<Slate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
if let Some(m) = self.middleware.as_ref() {
Expand All @@ -399,7 +448,16 @@ where
Some(slate),
)?;
}
foreign::finalize_invoice_tx(&mut **w, (&self.keychain_mask).as_ref(), slate)
let post_automatically = match self.doctest_mode {
true => false,
false => post_automatically,
};
foreign::finalize_tx(
&mut **w,
(&self.keychain_mask).as_ref(),
slate,
post_automatically,
)
}
}

Expand Down
28 changes: 19 additions & 9 deletions api/src/foreign_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,13 +183,12 @@ pub trait ForeignRpc {
&self,
slate: VersionedSlate,
dest_acct_name: Option<String>,
//TODO: Remove post-HF3
message: Option<String>,
dest: Option<String>,
) -> Result<VersionedSlate, ErrorKind>;

/**

Networked version of [Foreign::finalize_invoice_tx](struct.Foreign.html#method.finalize_invoice_tx).
Networked version of [Foreign::finalize_tx](struct.Foreign.html#method.finalize_tx).

# Json rpc example

Expand All @@ -198,7 +197,7 @@ pub trait ForeignRpc {
# r#"
{
"jsonrpc": "2.0",
"method": "finalize_invoice_tx",
"method": "finalize_tx",
"id": 1,
"params": [{
"ver": "4:2",
Expand Down Expand Up @@ -279,6 +278,9 @@ pub trait ForeignRpc {
# ,false, 5, false, true);
```
*/
fn finalize_tx(&self, slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind>;

/// For backwards-compatibility. Remove HF3
fn finalize_invoice_tx(&self, slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind>;
}

Expand All @@ -301,24 +303,32 @@ where
&self,
in_slate: VersionedSlate,
dest_acct_name: Option<String>,
//TODO: Remove post HF3
_message: Option<String>,
dest: Option<String>,
) -> Result<VersionedSlate, ErrorKind> {
let version = in_slate.version();
let slate_from = Slate::from(in_slate);
let out_slate = Foreign::receive_tx(
self,
&slate_from,
dest_acct_name.as_ref().map(String::as_str),
dest,
)
.map_err(|e| e.kind())?;
Ok(VersionedSlate::into_version(out_slate, version).map_err(|e| e.kind())?)
}

fn finalize_tx(&self, in_slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind> {
let version = in_slate.version();
let out_slate =
Foreign::finalize_tx(self, &Slate::from(in_slate), true).map_err(|e| e.kind())?;
Ok(VersionedSlate::into_version(out_slate, version).map_err(|e| e.kind())?)
}

//TODO: Delete HF3
fn finalize_invoice_tx(&self, in_slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind> {
let version = in_slate.version();
let out_slate =
Foreign::finalize_invoice_tx(self, &Slate::from(in_slate)).map_err(|e| e.kind())?;
Foreign::finalize_tx(self, &Slate::from(in_slate), false).map_err(|e| e.kind())?;
Ok(VersionedSlate::into_version(out_slate, version).map_err(|e| e.kind())?)
}
}
Expand Down Expand Up @@ -513,8 +523,8 @@ pub fn run_doctest_foreign(
}

let mut api_foreign = match init_invoice_tx {
false => Foreign::new(wallet1, mask1, Some(test_check_middleware)),
true => Foreign::new(wallet2, mask2, Some(test_check_middleware)),
false => Foreign::new(wallet1, mask1, Some(test_check_middleware), true),
true => Foreign::new(wallet2, mask2, Some(test_check_middleware), true),
};
api_foreign.doctest_mode = true;
let foreign_api = &api_foreign as &dyn ForeignRpc;
Expand Down
2 changes: 1 addition & 1 deletion api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ mod types;

pub use crate::foreign::{Foreign, ForeignCheckMiddleware, ForeignCheckMiddlewareFn};
pub use crate::foreign_rpc::ForeignRpc;
pub use crate::owner::Owner;
pub use crate::owner::{try_slatepack_sync_workflow, Owner};
pub use crate::owner_rpc::OwnerRpc;

pub use crate::foreign_rpc::foreign_rpc as foreign_rpc_client;
Expand Down
Loading