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;
pub type ForeignCheckMiddleware =
fn(ForeignCheckMiddlewareFn, Option<NodeVersionInfo>, Option<&Slate>) -> Result<(), Error>;
pub enum ForeignCheckMiddlewareFn {
CheckVersion,
BuildCoinbase,
VerifySlateMessages,
ReceiveTx,
FinalizeInvoiceTx,
FinalizeTx,
}
pub struct Foreign<'a, L, C, K>
where
L: WalletLCProvider<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
pub wallet_inst: Arc<Mutex<Box<dyn WalletInst<'a, L, C, K>>>>,
pub doctest_mode: bool,
middleware: Option<ForeignCheckMiddleware>,
keychain_mask: Option<SecretKey>,
tor_config: Mutex<Option<TorConfig>>,
}
impl<'a, L, C, K> Foreign<'a, L, C, K>
where
L: WalletLCProvider<'a, C, K>,
C: NodeClient + 'a,
K: Keychain + 'a,
{
pub fn new(
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,
middleware,
keychain_mask,
tor_config: Mutex::new(None),
}
}
pub fn set_tor_config(&self, tor_config: Option<TorConfig>) {
let mut lock = self.tor_config.lock();
*lock = tor_config;
}
pub fn check_version(&self) -> Result<VersionInfo, Error> {
if let Some(m) = self.middleware.as_ref() {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
m(
ForeignCheckMiddlewareFn::CheckVersion,
w.w2n_client().get_version_info(),
None,
)?;
}
Ok(foreign::check_version())
}
pub fn build_coinbase(&self, block_fees: &BlockFees) -> Result<CbData, 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() {
m(
ForeignCheckMiddlewareFn::BuildCoinbase,
w.w2n_client().get_version_info(),
None,
)?;
}
foreign::build_coinbase(
&mut **w,
(&self.keychain_mask).as_ref(),
block_fees,
self.doctest_mode,
)
}
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() {
m(
ForeignCheckMiddlewareFn::ReceiveTx,
w.w2n_client().get_version_info(),
Some(slate),
)?;
}
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),
}
}
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() {
m(
ForeignCheckMiddlewareFn::FinalizeInvoiceTx,
w.w2n_client().get_version_info(),
Some(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,
)
}
}
#[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_core;
use grin_wallet_util::grin_keychain as keychain;
use grin_wallet_util::grin_util as util;
use grin_core::global;
use keychain::ExtKeychain;
use tempfile::tempdir;
use std::sync::Arc;
use util::{Mutex, ZeroingString};
use api::{Foreign, Owner};
use config::WalletConfig;
use impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient};
use libwallet::{BlockFees, IssueInvoiceTxArgs, Slate, WalletInst};
if cfg!(windows) {
return;
}
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
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 = ZeroingString::from("");
let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None);
let mut wallet = Box::new(
DefaultWalletImpl::<'static, HTTPNodeClient>::new(node_client.clone()).unwrap(),
)
as Box<
WalletInst<
'static,
DefaultLCProvider<HTTPNodeClient, ExtKeychain>,
HTTPNodeClient,
ExtKeychain,
>,
>;
let lc = wallet.lc_provider().unwrap();
let _ = lc.set_top_level_directory(&wallet_config.data_file_dir);
lc.open_wallet(None, pw, false, false);
let mut $wallet = Arc::new(Mutex::new(wallet));
};
}