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

Store XORed wallet seed in-mem #200

Merged
merged 21 commits into from Aug 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
808 changes: 430 additions & 378 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions api/Cargo.toml
Expand Up @@ -14,6 +14,8 @@ failure = "0.1"
failure_derive = "0.1"
log = "0.4"
uuid = { version = "0.7", features = ["serde", "v4"] }
serde = "1"
serde_derive = "1"
serde_json = "1"
easy-jsonrpc = "0.5.1"
chrono = { version = "0.4.4", features = ["serde"] }
Expand Down
44 changes: 32 additions & 12 deletions api/src/foreign.rs
Expand Up @@ -20,6 +20,7 @@ use crate::libwallet::{
BlockFees, CbData, Error, NodeClient, NodeVersionInfo, Slate, VersionInfo, WalletInst,
WalletLCProvider,
};
use crate::util::secp::key::SecretKey;
use crate::util::Mutex;
use std::sync::Arc;

Expand Down Expand Up @@ -67,6 +68,8 @@ where
pub doctest_mode: bool,
/// foreign check middleware
middleware: Option<ForeignCheckMiddleware>,
/// Stored keychain mask (in case the stored wallet seed is tokenized)
keychain_mask: Option<SecretKey>,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now just stored by a Foreign API instance, for the case where you want to run a foreign and owner API in the same process but only reference a single instance of the wallet.

}

impl<'a, L, C, K> Foreign<'a, L, C, K>
Expand All @@ -86,6 +89,9 @@ where
/// # Arguments
/// * `wallet_in` - A reference-counted mutex containing an implementation of the
/// [`WalletBackend`](../grin_wallet_libwallet/types/trait.WalletBackend.html) trait.
/// * `keychain_mask` - Mask value stored internally to use when calling a wallet
/// whose seed has been XORed with a token value (such as when running the foreign
/// and owner listeners in the same instance)
/// * middleware - Option middleware which containts the NodeVersionInfo and can call
/// a predefined function with the slate to check if the operation should continue
///
Expand Down Expand Up @@ -142,24 +148,26 @@ where
///
/// // Wallet must be opened with the password (TBD)
/// let pw = ZeroingString::from("wallet_password");
/// lc.open_wallet(None, pw);
/// lc.open_wallet(None, pw, false, false);
///
/// // 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);
/// let api_foreign = Foreign::new(wallet.clone(), None, None);
/// // .. perform wallet operations
///
/// ```

pub fn new(
wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
keychain_mask: Option<SecretKey>,
middleware: Option<ForeignCheckMiddleware>,
) -> Self {
Foreign {
wallet_inst,
doctest_mode: false,
middleware,
keychain_mask,
}
}

Expand All @@ -173,7 +181,7 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
///
/// let version_info = api_foreign.check_version();
/// // check and proceed accordingly
Expand Down Expand Up @@ -225,7 +233,7 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
///
/// let block_fees = BlockFees {
/// fees: 800000,
Expand All @@ -252,7 +260,12 @@ where
None,
)?;
}
foreign::build_coinbase(&mut **w, block_fees, self.doctest_mode)
foreign::build_coinbase(
&mut **w,
(&self.keychain_mask).as_ref(),
block_fees,
self.doctest_mode,
)
}

/// Verifies all messages in the slate match their public keys.
Expand All @@ -276,7 +289,7 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
///
/// # let slate = Slate::blank(2);
/// // Receive a slate via some means
Expand Down Expand Up @@ -349,7 +362,7 @@ where
/// ```
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
/// # let slate = Slate::blank(2);
///
/// // . . .
Expand Down Expand Up @@ -377,7 +390,14 @@ where
Some(slate),
)?;
}
foreign::receive_tx(&mut **w, slate, dest_acct_name, message, self.doctest_mode)
foreign::receive_tx(
&mut **w,
(&self.keychain_mask).as_ref(),
slate,
dest_acct_name,
message,
self.doctest_mode,
)
}

/// Finalizes an invoice transaction initiated by this wallet's Owner api.
Expand Down Expand Up @@ -408,15 +428,15 @@ where
/// # grin_wallet_api::doctest_helper_setup_doc_env_foreign!(wallet, wallet_config);
///
/// let mut api_owner = Owner::new(wallet.clone());
/// let mut api_foreign = Foreign::new(wallet.clone(), None);
/// let mut api_foreign = Foreign::new(wallet.clone(), None, None);
///
/// // . . .
/// // Issue the invoice tx via the owner API
/// let args = IssueInvoiceTxArgs {
/// amount: 10_000_000_000,
/// ..Default::default()
/// };
/// let result = api_owner.issue_invoice_tx(args);
/// let result = api_owner.issue_invoice_tx(None, args);
///
/// // If result okay, send to payer, who will apply the transaction via their
/// // owner API, then send back the slate
Expand All @@ -437,7 +457,7 @@ where
Some(slate),
)?;
}
foreign::finalize_invoice_tx(&mut **w, slate)
foreign::finalize_invoice_tx(&mut **w, (&self.keychain_mask).as_ref(), slate)
}
}

Expand Down Expand Up @@ -487,7 +507,7 @@ macro_rules! doctest_helper_setup_doc_env_foreign {
>;
let lc = wallet.lc_provider().unwrap();
lc.set_wallet_directory(&wallet_config.data_file_dir);
lc.open_wallet(None, pw);
lc.open_wallet(None, pw, false, false);
let mut $wallet = Arc::new(Mutex::new(wallet));
};
}
64 changes: 46 additions & 18 deletions api/src/foreign_rpc.rs
Expand Up @@ -58,13 +58,13 @@ pub trait ForeignRpc {
}
}
# "#
# , 0, false, false);
# ,false, 0, false, false);
```
*/
fn check_version(&self) -> Result<VersionInfo, ErrorKind>;

/**
Networked version of [Foreign::build_coinbase](struct.Foreign.html#method.build_coinbase).
Networked Legacy (non-secure token) version of [Foreign::build_coinbase](struct.Foreign.html#method.build_coinbase).

# Json rpc example

Expand Down Expand Up @@ -108,9 +108,10 @@ pub trait ForeignRpc {
}
}
# "#
# , 4, false, false);
# ,false, 4, false, false);
```
*/

fn build_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, ErrorKind>;

/**
Expand Down Expand Up @@ -188,7 +189,7 @@ pub trait ForeignRpc {
}
}
# "#
# ,1 ,false, false);
# ,false, 1 ,false, false);
```
*/
fn verify_slate_messages(&self, slate: &Slate) -> Result<(), ErrorKind>;
Expand Down Expand Up @@ -341,7 +342,7 @@ pub trait ForeignRpc {
}
}
# "#
# , 5, true, false);
# ,false, 5, true, false);
```
*/
fn receive_tx(
Expand Down Expand Up @@ -509,7 +510,7 @@ pub trait ForeignRpc {
}
}
# "#
# , 5, false, true);
# ,false, 5, false, true);
```
*/
fn finalize_invoice_tx(&self, slate: &Slate) -> Result<Slate, ErrorKind>;
Expand Down Expand Up @@ -571,6 +572,7 @@ fn test_check_middleware(
pub fn run_doctest_foreign(
request: serde_json::Value,
test_dir: &str,
use_token: bool,
blocks_to_mine: u64,
init_tx: bool,
init_invoice_tx: bool,
Expand Down Expand Up @@ -622,10 +624,21 @@ pub fn run_doctest_foreign(
lc.set_wallet_directory(&format!("{}/wallet1", test_dir));
lc.create_wallet(None, Some(rec_phrase_1), 32, empty_string.clone())
.unwrap();
lc.open_wallet(None, empty_string.clone()).unwrap();
let mask1 = lc
.open_wallet(None, empty_string.clone(), use_token, true)
.unwrap();
let wallet1 = Arc::new(Mutex::new(wallet1));

wallet_proxy.add_wallet("wallet1", client1.get_send_instance(), wallet1.clone());
if mask1.is_some() {
println!("WALLET 1 MASK: {:?}", mask1.clone().unwrap());
}

wallet_proxy.add_wallet(
"wallet1",
client1.get_send_instance(),
wallet1.clone(),
mask1.clone(),
);

let rec_phrase_2 = util::ZeroingString::from(
"hour kingdom ripple lunch razor inquiry coyote clay stamp mean \
Expand All @@ -646,10 +659,17 @@ pub fn run_doctest_foreign(
lc.set_wallet_directory(&format!("{}/wallet2", test_dir));
lc.create_wallet(None, Some(rec_phrase_2), 32, empty_string.clone())
.unwrap();
lc.open_wallet(None, empty_string.clone()).unwrap();
let mask2 = lc
.open_wallet(None, empty_string.clone(), use_token, true)
.unwrap();
let wallet2 = Arc::new(Mutex::new(wallet2));

wallet_proxy.add_wallet("wallet2", client2.get_send_instance(), wallet2.clone());
wallet_proxy.add_wallet(
"wallet2",
client2.get_send_instance(),
wallet2.clone(),
mask2.clone(),
);

// Set the wallet proxy listener running
thread::spawn(move || {
Expand All @@ -660,12 +680,18 @@ pub fn run_doctest_foreign(

// Mine a few blocks to wallet 1 so there's something to send
for _ in 0..blocks_to_mine {
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), 1 as usize, false);
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
(&mask1).as_ref(),
1 as usize,
false,
);
//update local outputs after each block, so transaction IDs stay consistent
let mut w_lock = wallet1.lock();
let w = w_lock.lc_provider().unwrap().wallet_inst().unwrap();
let (wallet_refreshed, _) =
api_impl::owner::retrieve_summary_info(&mut **w, true, 1).unwrap();
api_impl::owner::retrieve_summary_info(&mut **w, (&mask1).as_ref(), true, 1).unwrap();
assert!(wallet_refreshed);
}

Expand All @@ -678,7 +704,7 @@ pub fn run_doctest_foreign(
amount,
..Default::default()
};
api_impl::owner::issue_invoice_tx(&mut **w, args, true).unwrap()
api_impl::owner::issue_invoice_tx(&mut **w, (&mask2).as_ref(), args, true).unwrap()
};
slate = {
let mut w_lock = wallet1.lock();
Expand All @@ -692,7 +718,8 @@ pub fn run_doctest_foreign(
selection_strategy_is_use_all: true,
..Default::default()
};
api_impl::owner::process_invoice_tx(&mut **w, &slate, args, true).unwrap()
api_impl::owner::process_invoice_tx(&mut **w, (&mask1).as_ref(), &slate, args, true)
.unwrap()
};
println!("INIT INVOICE SLATE");
// Spit out slate for input to finalize_invoice_tx
Expand All @@ -712,15 +739,15 @@ pub fn run_doctest_foreign(
selection_strategy_is_use_all: true,
..Default::default()
};
let slate = api_impl::owner::init_send_tx(&mut **w, args, true).unwrap();
let slate = api_impl::owner::init_send_tx(&mut **w, (&mask1).as_ref(), args, true).unwrap();
println!("INIT SLATE");
// Spit out slate for input to finalize_tx
println!("{}", serde_json::to_string_pretty(&slate).unwrap());
}

let mut api_foreign = match init_invoice_tx {
false => Foreign::new(wallet1, Some(test_check_middleware)),
true => Foreign::new(wallet2, Some(test_check_middleware)),
false => Foreign::new(wallet1, mask1, Some(test_check_middleware)),
true => Foreign::new(wallet2, mask2, Some(test_check_middleware)),
};
api_foreign.doctest_mode = true;
let foreign_api = &api_foreign as &dyn ForeignRpc;
Expand All @@ -730,7 +757,7 @@ pub fn run_doctest_foreign(
#[doc(hidden)]
#[macro_export]
macro_rules! doctest_helper_json_rpc_foreign_assert_response {
($request:expr, $expected_response:expr, $blocks_to_mine:expr, $init_tx:expr, $init_invoice_tx:expr) => {
($request:expr, $expected_response:expr, $use_token:expr, $blocks_to_mine:expr, $init_tx:expr, $init_invoice_tx: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 All @@ -752,6 +779,7 @@ macro_rules! doctest_helper_json_rpc_foreign_assert_response {
let response = run_doctest_foreign(
request_val,
dir,
$use_token,
$blocks_to_mine,
$init_tx,
$init_invoice_tx,
Expand Down
15 changes: 15 additions & 0 deletions api/src/lib.rs
Expand Up @@ -29,6 +29,8 @@ extern crate grin_wallet_impls as impls;
extern crate grin_wallet_libwallet as libwallet;

extern crate failure_derive;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

#[macro_use]
Expand All @@ -39,12 +41,25 @@ mod foreign_rpc;

mod owner;
mod owner_rpc;
mod owner_rpc_s;

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

pub use crate::foreign_rpc::foreign_rpc as foreign_rpc_client;
pub use crate::foreign_rpc::run_doctest_foreign;
pub use crate::owner_rpc::run_doctest_owner;

use grin_wallet_util::grin_core::libtx::secp_ser;
use util::secp::key::SecretKey;

/// Wrapper for API Tokens
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(transparent)]
pub struct Token {
#[serde(with = "secp_ser::option_seckey_serde")]
keychain_mask: Option<SecretKey>,
}