Skip to content

Commit

Permalink
Payment Proof export + validation (mimblewimble#289)
Browse files Browse the repository at this point in the history
* add payment proof struct and deser

* rustfmt

* adding proof export functions

* rustfmt

* add payment proof validation function

* rustfmt

* add RPC version of retrieve_payment_proof + doctest

* rustfmt

* add verify_proof rpc function and documentation for new functions

* rustfmt

* add export and verify commands

* rustfmt

* test + test framework fixes

* rustfmt

* check whether addresses belong to this wallet, output such when checking

* rustfmt

* remove raw pubkey address and replace with ov3 address in user-facing contexts

* merge from master and rustfmt

* doctests
  • Loading branch information
yeastplume authored Jan 22, 2020
1 parent e03e073 commit bc71fdf
Show file tree
Hide file tree
Showing 14 changed files with 769 additions and 66 deletions.
130 changes: 129 additions & 1 deletion api/src/owner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::libwallet::api_impl::owner_updater::{start_updater_log_thread, Status
use crate::libwallet::api_impl::{owner, owner_updater};
use crate::libwallet::{
address, AcctPathMapping, Error, ErrorKind, InitTxArgs, IssueInvoiceTxArgs, NodeClient,
NodeHeightResult, OutputCommitMapping, Slate, TxLogEntry, WalletInfo, WalletInst,
NodeHeightResult, OutputCommitMapping, PaymentProof, Slate, TxLogEntry, WalletInfo, WalletInst,
WalletLCProvider,
};
use crate::util::logger::LoggingConfig;
Expand Down Expand Up @@ -2012,6 +2012,132 @@ where
pub fn proof_address_from_onion_v3(&self, address_v3: &str) -> Result<DalekPublicKey, Error> {
address::pubkey_from_onion_v3(address_v3)
}

/// Returns a single, exportable [PaymentProof](../grin_wallet_libwallet/api_impl/types/struct.PaymentProof.html)
/// from a completed transaction within the wallet.
///
/// The transaction must have been created with a payment proof, and the transaction must be
/// complete in order for a payment proof to be returned. Either the `tx_id` or `tx_slate_id`
/// argument must be provided, or the function will return an error.
///
/// # Arguments
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
/// being used.
/// * `refresh_from_node` - If true, the wallet will attempt to contact
/// a node (via the [`NodeClient`](../grin_wallet_libwallet/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).
/// Note this setting is ignored if the updater process is running via a call to
/// [`start_updater`](struct.Owner.html#method.start_updater)
/// * `tx_id` - If `Some(i)` return the proof associated with the transaction with id `i`
/// * `tx_slate_id` - If `Some(uuid)`, return the proof associated with the transaction with the
/// given `uuid`
///
/// # Returns
/// * Ok([PaymentProof](../grin_wallet_libwallet/api_impl/types/struct.PaymentProof.html)) if successful
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered
/// or the proof is not present or complete
///
/// # Example
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
///
/// let api_owner = Owner::new(wallet.clone());
/// let update_from_node = true;
/// let tx_id = None;
/// let tx_slate_id = Some(Uuid::parse_str("0436430c-2b02-624c-2032-570501212b00").unwrap());
///
/// // Return all TxLogEntries
/// let result = api_owner.retrieve_payment_proof(None, update_from_node, tx_id, tx_slate_id);
///
/// if let Ok(p) = result {
/// //...
/// }
/// ```

pub fn retrieve_payment_proof(
&self,
keychain_mask: Option<&SecretKey>,
refresh_from_node: bool,
tx_id: Option<u32>,
tx_slate_id: Option<Uuid>,
) -> Result<PaymentProof, Error> {
let tx = {
let t = self.status_tx.lock();
t.clone()
};
let refresh_from_node = match self.updater_running.load(Ordering::Relaxed) {
true => false,
false => refresh_from_node,
};
owner::retrieve_payment_proof(
self.wallet_inst.clone(),
keychain_mask,
&tx,
refresh_from_node,
tx_id,
tx_slate_id,
)
}

/// Verifies a [PaymentProof](../grin_wallet_libwallet/api_impl/types/struct.PaymentProof.html)
/// This process entails:
///
/// * Ensuring the kernel identified by the proof's stored excess commitment exists in the kernel set
/// * Reproducing the signed message `amount|kernel_commitment|sender_address`
/// * Validating the proof's `recipient_sig` against the message using the recipient's
/// address as the public key and
/// * Validating the proof's `sender_sig` against the message using the senders's
/// address as the public key
///
/// This function also checks whether the sender or recipient address belongs to the currently
/// open wallet, and returns 2 booleans indicating whether the address belongs to the sender and
/// whether the address belongs to the recipient respectively
///
/// # Arguments
/// * `keychain_mask` - Wallet secret mask to XOR against the stored wallet seed before using, if
/// being used.
/// * `proof` A [PaymentProof](../grin_wallet_libwallet/api_impl/types/struct.PaymentProof.html))
///
/// # Returns
/// * Ok((bool, bool)) if the proof is valid. The first boolean indicates whether the sender
/// address belongs to this wallet, the second whether the recipient address belongs to this
/// wallet
/// * or [`libwallet::Error`](../grin_wallet_libwallet/struct.Error.html) if an error is encountered
/// or the proof is not present or complete
///
/// # Example
/// Set up as in [`new`](struct.Owner.html#method.new) method above.
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env!(wallet, wallet_config);
///
/// let api_owner = Owner::new(wallet.clone());
/// let update_from_node = true;
/// let tx_id = None;
/// let tx_slate_id = Some(Uuid::parse_str("0436430c-2b02-624c-2032-570501212b00").unwrap());
///
/// // Return all TxLogEntries
/// let result = api_owner.retrieve_payment_proof(None, update_from_node, tx_id, tx_slate_id);
///
/// // The proof will likely be exported as JSON to be provided to another party
///
/// if let Ok(p) = result {
/// let valid = api_owner.verify_payment_proof(None, &p);
/// if let Ok(_) = valid {
/// //...
/// }
/// }
/// ```

pub fn verify_payment_proof(
&self,
keychain_mask: Option<&SecretKey>,
proof: &PaymentProof,
) -> Result<(bool, bool), Error> {
owner::verify_payment_proof(self.wallet_inst.clone(), keychain_mask, proof)
}
}

#[doc(hidden)]
Expand All @@ -2037,6 +2163,8 @@ macro_rules! doctest_helper_setup_doc_env {
use impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient};
use libwallet::{BlockFees, InitTxArgs, IssueInvoiceTxArgs, Slate, WalletInst};

use uuid::Uuid;

let dir = tempdir().map_err(|e| format!("{:#?}", e)).unwrap();
let dir = dir
.path()
Expand Down
62 changes: 43 additions & 19 deletions api/src/owner_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::libwallet::{
OutputCommitMapping, Slate, SlateVersion, TxLogEntry, VersionedSlate, WalletInfo,
WalletLCProvider,
};
use crate::util::Mutex;
use crate::util::{from_hex, Mutex};
use crate::{Owner, OwnerRpcS};
use easy_jsonrpc_mw;
use std::sync::Arc;
Expand Down Expand Up @@ -64,7 +64,7 @@ pub trait OwnerRpc: Sync + Send {
"id": 1
}
# "#
# , false, 4, false, false, false);
# , false, 4, false, false, false, false);
```
*/
#[deprecated(
Expand Down Expand Up @@ -98,7 +98,7 @@ pub trait OwnerRpc: Sync + Send {
"id": 1
}
# "#
# ,false, 4, false, false, false);
# ,false, 4, false, false, false, false);
```
*/
fn create_account_path(&self, label: &String) -> Result<Identifier, ErrorKind>;
Expand Down Expand Up @@ -128,7 +128,7 @@ pub trait OwnerRpc: Sync + Send {
"id": 1
}
# "#
# , false, 4, false, false, false);
# , false, 4, false, false, false, false);
```
*/
fn set_active_account(&self, label: &String) -> Result<(), ErrorKind>;
Expand Down Expand Up @@ -194,7 +194,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 2, false, false, false);
# , false, 2, false, false, false, false);
```
*/
fn retrieve_outputs(
Expand Down Expand Up @@ -273,7 +273,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 2, false, false, false);
# , false, 2, false, false, false, false);
```
*/

Expand Down Expand Up @@ -319,7 +319,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# ,false, 4, false, false, false);
# ,false, 4, false, false, false, false);
```
*/

Expand Down Expand Up @@ -417,7 +417,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# ,false, 4, false, false, false);
# ,false, 4, false, false, false, false);
```
*/

Expand Down Expand Up @@ -499,7 +499,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# ,false, 4, false, false, false);
# ,false, 4, false, false, false, false);
```
*/

Expand Down Expand Up @@ -653,7 +653,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# ,false, 4, false, false, false);
# ,false, 4, false, false, false, false);
```
*/

Expand Down Expand Up @@ -739,7 +739,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# ,false, 5 ,true, false, false);
# ,false, 5 ,true, false, false, false);

```
*/
Expand Down Expand Up @@ -910,7 +910,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 5, true, true, false);
# , false, 5, true, true, false, false);
```
*/
fn finalize_tx(&self, slate: VersionedSlate) -> Result<VersionedSlate, ErrorKind>;
Expand Down Expand Up @@ -976,7 +976,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 5, true, true, true);
# , false, 5, true, true, true, false);
```
*/

Expand Down Expand Up @@ -1006,7 +1006,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 5, true, true, false);
# , false, 5, true, true, false, false);
```
*/
fn cancel_tx(&self, tx_id: Option<u32>, tx_slate_id: Option<Uuid>) -> Result<(), ErrorKind>;
Expand Down Expand Up @@ -1103,7 +1103,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 5, true, true, false);
# , false, 5, true, true, false, false);
```
*/
fn get_stored_tx(&self, tx: &TxLogEntry) -> Result<Option<TransactionV3>, ErrorKind>;
Expand Down Expand Up @@ -1183,7 +1183,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# ,false, 0 ,false, false, false);
# ,false, 0 ,false, false, false, false);
```
*/
fn verify_slate_messages(&self, slate: VersionedSlate) -> Result<(), ErrorKind>;
Expand Down Expand Up @@ -1212,7 +1212,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 1, false, false, false);
# , false, 1, false, false, false, false);
```
*/
fn scan(&self, start_height: Option<u64>, delete_unconfirmed: bool) -> Result<(), ErrorKind>;
Expand Down Expand Up @@ -1245,7 +1245,7 @@ pub trait OwnerRpc: Sync + Send {
}
}
# "#
# , false, 5, false, false, false);
# , false, 5, false, false, false, false);
```
*/
fn node_height(&self) -> Result<NodeHeightResult, ErrorKind>;
Expand Down Expand Up @@ -1372,13 +1372,16 @@ pub fn run_doctest_owner(
perform_tx: bool,
lock_tx: bool,
finalize_tx: bool,
payment_proof: bool,
) -> Result<Option<serde_json::Value>, String> {
use easy_jsonrpc_mw::Handler;
use grin_wallet_impls::test_framework::{self, LocalWalletClient, WalletProxy};
use grin_wallet_impls::{DefaultLCProvider, DefaultWalletImpl};
use grin_wallet_libwallet::{api_impl, WalletInst};
use grin_wallet_util::grin_keychain::ExtKeychain;

use ed25519_dalek::PublicKey as DalekPublicKey;

use crate::core::global;
use crate::core::global::ChainTypes;
use grin_wallet_util::grin_util as util;
Expand Down Expand Up @@ -1434,6 +1437,8 @@ pub fn run_doctest_owner(
mask1.clone(),
);

let mut slate_outer = Slate::blank(2);

let rec_phrase_2 = util::ZeroingString::from(
"hour kingdom ripple lunch razor inquiry coyote clay stamp mean \
sell finish magic kid tiny wage stand panther inside settle feed song hole exile",
Expand Down Expand Up @@ -1503,13 +1508,26 @@ pub fn run_doctest_owner(
let amount = 60_000_000_000;
let mut w_lock = wallet1.lock();
let w = w_lock.lc_provider().unwrap().wallet_inst().unwrap();
let proof_address = match payment_proof {
true => {
let bytes = from_hex(
"783f6528669742a990e0faf0a5fca5d5b3330e37bbb9cd5c628696d03ce4e810".to_string(),
)
.unwrap();
let mut b = [0u8; 32];
b.copy_from_slice(&bytes[0..32]);
Some(DalekPublicKey::from_bytes(&b).unwrap())
}
false => None,
};
let args = InitTxArgs {
src_acct_name: None,
amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
payment_proof_recipient_address: proof_address,
..Default::default()
};
let mut slate =
Expand Down Expand Up @@ -1541,6 +1559,11 @@ pub fn run_doctest_owner(
error!("FINALIZED TX SLATE");
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
}
slate_outer = slate;
}

if payment_proof {
let _ = api_impl::owner::post_tx(&client1, &slate_outer.tx, true).unwrap();
}

if perform_tx && lock_tx && finalize_tx {
Expand Down Expand Up @@ -1570,7 +1593,7 @@ pub fn run_doctest_owner(
#[doc(hidden)]
#[macro_export]
macro_rules! doctest_helper_json_rpc_owner_assert_response {
($request:expr, $expected_response:expr, $use_token:expr, $blocks_to_mine:expr, $perform_tx:expr, $lock_tx:expr, $finalize_tx:expr) => {
($request:expr, $expected_response:expr, $use_token:expr, $blocks_to_mine:expr, $perform_tx:expr, $lock_tx:expr, $finalize_tx:expr, $payment_proof:expr) => {
// create temporary wallet, run jsonrpc request on owner api of wallet, delete wallet, return
// json response.
// In order to prevent leaking tempdirs, This function should not panic.
Expand Down Expand Up @@ -1603,6 +1626,7 @@ macro_rules! doctest_helper_json_rpc_owner_assert_response {
$perform_tx,
$lock_tx,
$finalize_tx,
$payment_proof,
)
.unwrap()
.unwrap();
Expand Down
Loading

0 comments on commit bc71fdf

Please sign in to comment.