use crate::keychain::Keychain;
use crate::libwallet::api_impl::foreign;
use crate::libwallet::{
BlockFees, CbData, Error, NodeClient, NodeVersionInfo, Slate, SlatePurpose, SlateVersion,
VersionInfo, VersionedSlate, WalletInst, WalletLCProvider,
};
use crate::util::secp::key::SecretKey;
use crate::util::Mutex;
use ed25519_dalek::PublicKey as DalekPublicKey;
use std::sync::Arc;
pub type ForeignCheckMiddleware =
fn(ForeignCheckMiddlewareFn, Option<NodeVersionInfo>, Option<&Slate>) -> Result<(), Error>;
pub enum ForeignCheckMiddlewareFn {
CheckVersion,
BuildCoinbase,
VerifySlateMessages,
ReceiveTx,
FinalizeInvoiceTx,
}
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>,
}
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>,
) -> Self {
Foreign {
wallet_inst,
doctest_mode: false,
middleware,
keychain_mask,
}
}
pub fn check_version(&self) -> Result<VersionInfo, Error> {
let version = foreign::check_version()?;
Ok(version)
}
pub fn get_proof_address(&self) -> Result<String, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
foreign::get_proof_address(&mut **w, (&self.keychain_mask).as_ref())
}
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 verify_slate_messages(&self, slate: &Slate) -> Result<(), 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::VerifySlateMessages,
w.w2n_client().get_version_info(),
Some(slate),
)?;
}
foreign::verify_slate_messages(slate)
}
pub fn receive_tx(
&self,
slate: &Slate,
address: Option<String>,
dest_acct_name: &Option<String>,
message: 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 (slate, _context) = foreign::receive_tx(
&mut **w,
(&self.keychain_mask).as_ref(),
slate,
address,
None,
None,
dest_acct_name,
message,
self.doctest_mode,
true,
)?;
Ok(slate)
}
pub fn finalize_invoice_tx(&self, slate: &Slate) -> 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),
)?;
}
foreign::finalize_invoice_tx(
&mut **w,
(&self.keychain_mask).as_ref(),
slate,
true,
self.doctest_mode,
)
}
pub fn receive_swap_message(&self, swap_message: &String) -> Result<(), Error> {
foreign::receive_swap_message(
self.wallet_inst.clone(),
(&self.keychain_mask).as_ref(),
swap_message,
)
}
pub fn marketplace_message(&self, message: &String) -> Result<String, Error> {
foreign::marketplace_message(
self.wallet_inst.clone(),
(&self.keychain_mask).as_ref(),
message,
)
}
pub fn decrypt_slate(
&self,
encrypted_slate: VersionedSlate,
) -> Result<(Slate, SlatePurpose, Option<DalekPublicKey>), Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
let (slate, content, sender, _receiver) = foreign::decrypt_slate(
&mut **w,
(&self.keychain_mask).as_ref(),
encrypted_slate,
None,
)?;
Ok((slate, content, sender))
}
pub fn encrypt_slate(
&self,
slate: &Slate,
version: Option<SlateVersion>,
content: SlatePurpose,
slatepack_recipient: Option<DalekPublicKey>,
address_index: Option<u32>,
use_test_rng: bool,
) -> Result<VersionedSlate, Error> {
let mut w_lock = self.wallet_inst.lock();
let w = w_lock.lc_provider()?.wallet_inst()?;
let vslate = foreign::encrypt_slate(
&mut **w,
(&self.keychain_mask).as_ref(),
slate,
version,
content,
slatepack_recipient,
address_index,
use_test_rng,
)?;
Ok(vslate)
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! doctest_helper_setup_doc_env_foreign {
($wallet:ident, $wallet_config:ident) => {
use mwc_wallet_api as api;
use mwc_wallet_config as config;
use mwc_wallet_impls as impls;
use mwc_wallet_libwallet as libwallet;
use mwc_wallet_util::mwc_core;
use mwc_wallet_util::mwc_keychain as keychain;
use mwc_wallet_util::mwc_util as util;
use keychain::ExtKeychain;
use mwc_core::global;
use tempfile::tempdir;
use std::sync::Arc;
use util::{Mutex, ZeroingString};
use api::{Foreign, Owner};
use config::{parse_node_address_string, WalletConfig};
use impls::{DefaultLCProvider, DefaultWalletImpl, HTTPNodeClient};
use libwallet::{BlockFees, IssueInvoiceTxArgs, Slate, WalletInst};
if cfg!(windows) {
return;
}
global::set_local_chain_type(global::ChainTypes::AutomatedTesting);
if cfg!(windows) {
return;
}
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_list = parse_node_address_string(wallet_config.check_node_api_http_addr.clone());
let node_client = HTTPNodeClient::new(node_list, None).unwrap();
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, None);
let mut $wallet = Arc::new(Mutex::new(wallet));
};
}