Add init_api_secure function (#206)

* adding initial version of init_secure_api

* rustfmt

* fix ECDH algo

* rustfmt

* trying to figure out best way of doing encryption

* refactor secure requests and responses into json-rpc responses, with base64 payload for encrypted messages

* rustfmt

* return proper errors from encrypted api, include tests covering encrypted API error cases

* rustfmt

* add test for normal error (unencrypted)

* rustfmt

* change ports for test, add foreign listener to V2 sanity tests, add ability to select owner api port via command line

* rustfmt

* turn it to 11

* explicit teardown after rpc tests

* update tests with explicit teardowns

* update tests to perform explicit teardown

* fix warnings, ensure all tests teardown

* log output to diagnose CI windows build failures

* disable owner api doctests on windows

* rustfmt
This commit is contained in:
Yeastplume
2019-08-19 13:05:21 +01:00
committed by GitHub
parent 62d976f9ef
commit a58cae651e
33 changed files with 1224 additions and 294 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ tokio-retry = "0.1"
uuid = { version = "0.7", features = ["serde", "v4"] }
url = "1.7.0"
chrono = { version = "0.4.4", features = ["serde"] }
easy-jsonrpc = "0.5.1"
easy-jsonrpc-mw = "0.5.3"
lazy_static = "1"
grin_wallet_util = { path = "../util", version = "2.1.0-beta.1" }
+149 -5
View File
@@ -32,15 +32,22 @@ use serde_json;
use std::net::SocketAddr;
use std::sync::Arc;
use crate::apiwallet::{Foreign, ForeignCheckMiddlewareFn, ForeignRpc, Owner, OwnerRpc, OwnerRpcS};
use easy_jsonrpc;
use easy_jsonrpc::{Handler, MaybeReply};
use crate::apiwallet::{
EncryptedRequest, EncryptedResponse, EncryptionErrorResponse, Foreign,
ForeignCheckMiddlewareFn, ForeignRpc, Owner, OwnerRpc, OwnerRpcS,
};
use easy_jsonrpc_mw;
use easy_jsonrpc_mw::{Handler, MaybeReply};
lazy_static! {
pub static ref GRIN_OWNER_BASIC_REALM: HeaderValue =
HeaderValue::from_str("Basic realm=GrinOwnerAPI").unwrap();
}
lazy_static! {
pub static ref OWNER_API_SHARED_KEY: Arc<Mutex<Option<SecretKey>>> = Arc::new(Mutex::new(None));
}
fn check_middleware(
name: ForeignCheckMiddlewareFn,
node_version_info: Option<NodeVersionInfo>,
@@ -138,7 +145,6 @@ where
}
let api_handler_v2 = OwnerAPIHandlerV2::new(wallet.clone());
let api_handler_v3 = OwnerAPIHandlerV3::new(wallet.clone());
router
@@ -295,6 +301,106 @@ where
pub wallet: Arc<Mutex<Box<dyn WalletInst<'static, L, C, K> + 'static>>>,
}
pub struct OwnerV3Helpers;
impl OwnerV3Helpers {
/// Checks whether a request is to init the secure API
pub fn is_init_secure_api(val: &serde_json::Value) -> bool {
if let Some(m) = val["method"].as_str() {
match m {
"init_secure_api" => true,
_ => false,
}
} else {
false
}
}
/// Checks whether a request is an encrypted request
pub fn is_encrypted_request(val: &serde_json::Value) -> bool {
if let Some(m) = val["method"].as_str() {
match m {
"encrypted_request_v3" => true,
_ => false,
}
} else {
false
}
}
/// whether encryption is enabled
pub fn encryption_enabled() -> bool {
let share_key_ref = OWNER_API_SHARED_KEY.lock();
share_key_ref.is_some()
}
/// If incoming is an encrypted request, check there is a shared key,
/// Otherwise return an error value
pub fn check_encryption_started() -> Result<(), serde_json::Value> {
match OwnerV3Helpers::encryption_enabled() {
true => Ok(()),
false => Err(EncryptionErrorResponse::new(
1,
-32001,
"Encryption must be enabled. Please call 'init_secure_api` first",
)
.as_json_value()),
}
}
/// Update the statically held owner API shared key
pub fn update_owner_api_shared_key(val: &serde_json::Value, new_key: Option<SecretKey>) {
if let Some(_) = val["result"]["Ok"].as_str() {
let mut share_key_ref = OWNER_API_SHARED_KEY.lock();
*share_key_ref = new_key;
}
}
/// Decrypt an encrypted request
pub fn decrypt_request(
req: &serde_json::Value,
) -> Result<(u32, serde_json::Value), serde_json::Value> {
let share_key_ref = OWNER_API_SHARED_KEY.lock();
let shared_key = share_key_ref.as_ref().unwrap();
let enc_req: EncryptedRequest = serde_json::from_value(req.clone()).map_err(|e| {
EncryptionErrorResponse::new(
1,
-32002,
&format!("Encrypted request format error: {}", e),
)
.as_json_value()
})?;
let id = enc_req.id;
let res = enc_req.decrypt(&shared_key).map_err(|e| {
EncryptionErrorResponse::new(1, -32002, &format!("Decryption error: {}", e.kind()))
.as_json_value()
})?;
Ok((id, res))
}
/// Encrypt a response
pub fn encrypt_response(
id: u32,
res: &serde_json::Value,
) -> Result<serde_json::Value, serde_json::Value> {
let share_key_ref = OWNER_API_SHARED_KEY.lock();
let shared_key = share_key_ref.as_ref().unwrap();
let enc_res = EncryptedResponse::from_json(id, res, &shared_key).map_err(|e| {
EncryptionErrorResponse::new(1, -32003, &format!("EncryptionError: {}", e.kind()))
.as_json_value()
})?;
let res = enc_res.as_json_value().map_err(|e| {
EncryptionErrorResponse::new(
1,
-32002,
&format!("Encrypted response format error: {}", e),
)
.as_json_value()
})?;
Ok(res)
}
}
impl<L, C, K> OwnerAPIHandlerV3<L, C, K>
where
L: WalletLCProvider<'static, C, K>,
@@ -314,9 +420,47 @@ where
api: Owner<'static, L, C, K>,
) -> Box<dyn Future<Item = serde_json::Value, Error = Error> + Send> {
Box::new(parse_body(req).and_then(move |val: serde_json::Value| {
let mut val = val;
let owner_api_s = &api as &dyn OwnerRpcS;
let mut is_init_secure_api = OwnerV3Helpers::is_init_secure_api(&val);
let mut was_encrypted = false;
let mut encrypted_req_id = 0;
if !is_init_secure_api {
if let Err(v) = OwnerV3Helpers::check_encryption_started() {
return ok(v);
}
let res = OwnerV3Helpers::decrypt_request(&val);
match res {
Err(e) => return ok(e),
Ok(v) => {
encrypted_req_id = v.0;
val = v.1;
}
}
was_encrypted = true;
}
// check again, in case it was an encrypted call to init_secure_api
is_init_secure_api = OwnerV3Helpers::is_init_secure_api(&val);
match owner_api_s.handle_request(val) {
MaybeReply::Reply(r) => ok(r),
MaybeReply::Reply(mut r) => {
let unencrypted_intercept = r.clone();
if was_encrypted {
let res = OwnerV3Helpers::encrypt_response(encrypted_req_id, &r);
r = match res {
Ok(v) => v,
Err(v) => return ok(v),
}
}
// intercept init_secure_api response (after encryption,
// in case it was an encrypted call to 'init_api_secure')
if is_init_secure_api {
OwnerV3Helpers::update_owner_api_shared_key(
&unencrypted_intercept,
api.shared_key.lock().clone(),
);
}
ok(r)
}
MaybeReply::DontReply => {
// Since it's http, we need to return something. We return [] because jsonrpc
// clients will parse it as an empty batch response.
+3 -3
View File
@@ -30,12 +30,10 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
/// Various tests on accounts within the same wallet
fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -265,7 +263,9 @@ fn accounts_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
#[test]
fn accounts() {
let test_dir = "test_output/accounts";
setup(test_dir);
if let Err(e) = accounts_test_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
+4 -3
View File
@@ -32,7 +32,7 @@ use util::ZeroingString;
#[macro_use]
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
macro_rules! send_to_dest {
($a:expr, $m: expr, $b:expr, $c:expr, $d:expr) => {
@@ -48,8 +48,6 @@ macro_rules! wallet_info {
/// Various tests on checking functionality
fn check_repair_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -753,12 +751,15 @@ fn check_repair() {
if let Err(e) = check_repair_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
#[test]
fn two_wallets_one_seed() {
let test_dir = "test_output/two_wallets_one_seed";
setup(test_dir);
if let Err(e) = two_wallets_one_seed_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
+5 -4
View File
@@ -101,7 +101,7 @@ pub fn create_local_wallet(
Arc<
Mutex<
Box<
WalletInst<
dyn WalletInst<
'static,
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
LocalWalletClient,
@@ -114,7 +114,7 @@ pub fn create_local_wallet(
) {
let mut wallet = Box::new(DefaultWalletImpl::<LocalWalletClient>::new(client).unwrap())
as Box<
WalletInst<
dyn WalletInst<
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
LocalWalletClient,
ExtKeychain,
@@ -130,6 +130,7 @@ pub fn create_local_wallet(
(Arc::new(Mutex::new(wallet)), mask)
}
#[allow(dead_code)]
pub fn open_local_wallet(
test_dir: &str,
name: &str,
@@ -139,7 +140,7 @@ pub fn open_local_wallet(
Arc<
Mutex<
Box<
WalletInst<
dyn WalletInst<
'static,
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
LocalWalletClient,
@@ -152,7 +153,7 @@ pub fn open_local_wallet(
) {
let mut wallet = Box::new(DefaultWalletImpl::<LocalWalletClient>::new(client).unwrap())
as Box<
WalletInst<
dyn WalletInst<
DefaultLCProvider<'static, LocalWalletClient, ExtKeychain>,
LocalWalletClient,
ExtKeychain,
+3 -3
View File
@@ -31,12 +31,10 @@ use serde_json;
#[macro_use]
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
/// self send impl
fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -224,7 +222,9 @@ fn file_exchange_test_impl(test_dir: &'static str) -> Result<(), libwallet::Erro
#[test]
fn wallet_file_exchange() {
let test_dir = "test_output/file_exchange";
setup(test_dir);
if let Err(e) = file_exchange_test_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
+168 -175
View File
@@ -31,193 +31,186 @@ use common::{clean_output_dir, create_wallet_proxy, setup};
/// self send impl
fn invoice_tx_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
{
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
create_wallet_and_add!(
client1,
wallet1,
mask1_i,
test_dir,
"wallet1",
None,
&mut wallet_proxy,
true
);
let mask1 = (&mask1_i).as_ref();
create_wallet_and_add!(
client2,
wallet2,
mask2_i,
test_dir,
"wallet2",
None,
&mut wallet_proxy,
true
);
let mask2 = (&mask2_i).as_ref();
create_wallet_and_add!(
client1,
wallet1,
mask1_i,
test_dir,
"wallet1",
None,
&mut wallet_proxy,
true
);
let mask1 = (&mask1_i).as_ref();
create_wallet_and_add!(
client2,
wallet2,
mask2_i,
test_dir,
"wallet2",
None,
&mut wallet_proxy,
true
);
let mask2 = (&mask2_i).as_ref();
// Set the wallet proxy listener running
thread::spawn(move || {
if let Err(e) = wallet_proxy.run() {
error!("Wallet Proxy error: {}", e);
}
});
// few values to keep things shorter
let reward = core::consensus::REWARD;
// add some accounts
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
api.create_account_path(m, "mining")?;
api.create_account_path(m, "listener")?;
Ok(())
})?;
// Get some mining done
{
wallet_inst!(wallet1, w);
w.set_parent_key_id_by_name("mining")?;
// Set the wallet proxy listener running
thread::spawn(move || {
if let Err(e) = wallet_proxy.run() {
error!("Wallet Proxy error: {}", e);
}
let mut bh = 10u64;
let _ = test_framework::award_blocks_to_wallet(
&chain,
wallet1.clone(),
mask1,
bh as usize,
false,
);
});
// Sanity check wallet 1 contents
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward);
Ok(())
})?;
// few values to keep things shorter
let reward = core::consensus::REWARD;
let mut slate = Slate::blank(2);
// add some accounts
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
api.create_account_path(m, "mining")?;
api.create_account_path(m, "listener")?;
Ok(())
})?;
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
// Wallet 2 inititates an invoice transaction, requesting payment
let args = IssueInvoiceTxArgs {
amount: reward * 2,
..Default::default()
};
slate = api.issue_invoice_tx(m, args)?;
Ok(())
})?;
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
// Wallet 1 receives the invoice transaction
let args = InitTxArgs {
src_acct_name: None,
amount: slate.amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
slate = api.process_invoice_tx(m, &slate, args)?;
api.tx_lock_outputs(m, &slate, 0)?;
Ok(())
})?;
// wallet 2 finalizes and posts
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
// Wallet 2 receives the invoice transaction
slate = api.finalize_invoice_tx(&slate)?;
Ok(())
})?;
// wallet 1 posts so wallet 2 doesn't get the mined amount
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
api.post_tx(m, &slate.tx, false)?;
Ok(())
})?;
bh += 1;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
bh += 3;
// Check transaction log for wallet 2
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
let (_, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
assert!(refreshed);
assert!(txs.len() == 1);
println!(
"last confirmed height: {}, bh: {}",
wallet2_info.last_confirmed_height, bh
);
assert!(refreshed);
assert_eq!(wallet2_info.amount_currently_spendable, slate.amount);
Ok(())
})?;
// Check transaction log for wallet 1, ensure only 1 entry
// exists
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
assert!(refreshed);
assert_eq!(txs.len() as u64, bh + 1);
println!(
"Wallet 1: last confirmed height: {}, bh: {}",
wallet1_info.last_confirmed_height, bh
);
Ok(())
})?;
// Test self-sending
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
// Wallet 1 inititates an invoice transaction, requesting payment
let args = IssueInvoiceTxArgs {
amount: reward * 2,
..Default::default()
};
slate = api.issue_invoice_tx(m, args)?;
// Wallet 1 receives the invoice transaction
let args = InitTxArgs {
src_acct_name: None,
amount: slate.amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
slate = api.process_invoice_tx(m, &slate, args)?;
api.tx_lock_outputs(m, &slate, 0)?;
Ok(())
})?;
// wallet 1 finalizes and posts
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
// Wallet 2 receives the invoice transaction
slate = api.finalize_invoice_tx(&slate)?;
Ok(())
})?;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
//bh += 3;
// let logging finish
thread::sleep(Duration::from_millis(200));
// Get some mining done
{
wallet_inst!(wallet1, w);
w.set_parent_key_id_by_name("mining")?;
}
let mut bh = 10u64;
let _ =
test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, bh as usize, false);
// Sanity check wallet 1 contents
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
let (wallet1_refreshed, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
assert!(wallet1_refreshed);
assert_eq!(wallet1_info.last_confirmed_height, bh);
assert_eq!(wallet1_info.total, bh * reward);
Ok(())
})?;
let mut slate = Slate::blank(2);
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
// Wallet 2 inititates an invoice transaction, requesting payment
let args = IssueInvoiceTxArgs {
amount: reward * 2,
..Default::default()
};
slate = api.issue_invoice_tx(m, args)?;
Ok(())
})?;
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
// Wallet 1 receives the invoice transaction
let args = InitTxArgs {
src_acct_name: None,
amount: slate.amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
slate = api.process_invoice_tx(m, &slate, args)?;
api.tx_lock_outputs(m, &slate, 0)?;
Ok(())
})?;
// wallet 2 finalizes and posts
wallet::controller::foreign_single_use(wallet2.clone(), mask2_i.clone(), |api| {
// Wallet 2 receives the invoice transaction
slate = api.finalize_invoice_tx(&slate)?;
Ok(())
})?;
// wallet 1 posts so wallet 2 doesn't get the mined amount
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
api.post_tx(m, &slate.tx, false)?;
Ok(())
})?;
bh += 1;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
bh += 3;
// Check transaction log for wallet 2
wallet::controller::owner_single_use(wallet2.clone(), mask2, |api, m| {
let (_, wallet2_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
assert!(refreshed);
assert!(txs.len() == 1);
println!(
"last confirmed height: {}, bh: {}",
wallet2_info.last_confirmed_height, bh
);
assert!(refreshed);
assert_eq!(wallet2_info.amount_currently_spendable, slate.amount);
Ok(())
})?;
// Check transaction log for wallet 1, ensure only 1 entry
// exists
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
let (_, wallet1_info) = api.retrieve_summary_info(m, true, 1)?;
let (refreshed, txs) = api.retrieve_txs(m, true, None, None)?;
assert!(refreshed);
assert_eq!(txs.len() as u64, bh + 1);
println!(
"Wallet 1: last confirmed height: {}, bh: {}",
wallet1_info.last_confirmed_height, bh
);
Ok(())
})?;
// Test self-sending
wallet::controller::owner_single_use(wallet1.clone(), mask1, |api, m| {
// Wallet 1 inititates an invoice transaction, requesting payment
let args = IssueInvoiceTxArgs {
amount: reward * 2,
..Default::default()
};
slate = api.issue_invoice_tx(m, args)?;
// Wallet 1 receives the invoice transaction
let args = InitTxArgs {
src_acct_name: None,
amount: slate.amount,
minimum_confirmations: 2,
max_outputs: 500,
num_change_outputs: 1,
selection_strategy_is_use_all: true,
..Default::default()
};
slate = api.process_invoice_tx(m, &slate, args)?;
api.tx_lock_outputs(m, &slate, 0)?;
Ok(())
})?;
// wallet 1 finalizes and posts
wallet::controller::foreign_single_use(wallet1.clone(), mask1_i.clone(), |api| {
// Wallet 2 receives the invoice transaction
slate = api.finalize_invoice_tx(&slate)?;
Ok(())
})?;
let _ = test_framework::award_blocks_to_wallet(&chain, wallet1.clone(), mask1, 3, false);
//bh += 3;
// let logging finish
thread::sleep(Duration::from_millis(200));
clean_output_dir(test_dir);
Ok(())
}
#[test]
fn wallet_invoice_tx() -> Result<(), libwallet::Error> {
let test_dir = "test_output/invoice_tx";
invoice_tx_impl(test_dir)
setup(test_dir);
invoice_tx_impl(test_dir)?;
clean_output_dir(test_dir);
Ok(())
}
+3 -3
View File
@@ -28,12 +28,10 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
/// self send impl
fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -257,7 +255,9 @@ fn file_repost_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error>
#[test]
fn wallet_file_repost() {
let test_dir = "test_output/file_repost";
setup(test_dir);
if let Err(e) = file_repost_test_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
+3 -3
View File
@@ -30,7 +30,7 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
fn restore_wallet(base_dir: &'static str, wallet_dir: &str) -> Result<(), libwallet::Error> {
let source_seed = format!("{}/{}/wallet_data/wallet.seed", base_dir, wallet_dir);
@@ -196,8 +196,6 @@ fn compare_wallet_restore(
/// Build up 2 wallets, perform a few transactions on them
/// Then attempt to restore them in separate directories and check contents are the same
fn setup_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -417,6 +415,7 @@ fn perform_restore(test_dir: &'static str) -> Result<(), libwallet::Error> {
#[test]
fn wallet_restore() {
let test_dir = "test_output/wallet_restore";
setup(test_dir);
if let Err(e) = setup_restore(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
@@ -425,4 +424,5 @@ fn wallet_restore() {
}
// let logging finish
thread::sleep(Duration::from_millis(200));
clean_output_dir(test_dir);
}
+3 -2
View File
@@ -27,11 +27,10 @@ use std::time::Duration;
#[macro_use]
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
/// self send impl
fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -138,7 +137,9 @@ fn self_send_test_impl(test_dir: &'static str) -> Result<(), libwallet::Error> {
#[test]
fn wallet_self_send() {
let test_dir = "test_output/self_send";
setup(test_dir);
if let Err(e) = self_send_test_impl(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
+5 -3
View File
@@ -28,13 +28,12 @@ use std::thread;
use std::time::Duration;
mod common;
use common::{create_wallet_proxy, setup};
use common::{clean_output_dir, create_wallet_proxy, setup};
/// Exercises the Transaction API fully with a test NodeClient operating
/// directly on a chain instance
/// Callable with any type of wallet
fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -350,7 +349,6 @@ fn basic_transaction_api(test_dir: &'static str) -> Result<(), libwallet::Error>
/// Test rolling back transactions and outputs when a transaction is never
/// posted to a chain
fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
setup(test_dir);
// Create a new proxy to simulate server and wallet responses
let mut wallet_proxy = create_wallet_proxy(test_dir);
let chain = wallet_proxy.chain.clone();
@@ -528,15 +526,19 @@ fn tx_rollback(test_dir: &'static str) -> Result<(), libwallet::Error> {
#[test]
fn db_wallet_basic_transaction_api() {
let test_dir = "test_output/basic_transaction_api";
setup(test_dir);
if let Err(e) = basic_transaction_api(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}
#[test]
fn db_wallet_tx_rollback() {
let test_dir = "test_output/tx_rollback";
setup(test_dir);
if let Err(e) = tx_rollback(test_dir) {
panic!("Libwallet Error: {} - {}", e, e.backtrace().unwrap());
}
clean_output_dir(test_dir);
}