diff --git a/src/bin/directoryd.rs b/src/bin/directoryd.rs index e81422a8..a0f6c375 100644 --- a/src/bin/directoryd.rs +++ b/src/bin/directoryd.rs @@ -11,7 +11,7 @@ use std::{path::PathBuf, str::FromStr, sync::Arc}; author = option_env ! ("CARGO_PKG_AUTHORS").unwrap_or(""))] struct Cli { /// Optional network type. - #[clap(long, short = 'n', default_value = "clearnet", possible_values = &["tor", "clearnet"])] + #[clap(long, short = 'n', default_value = "tor", possible_values = &["tor", "clearnet"])] network: String, /// Optional DNS data directory. Default value : "~/.coinswap/directory" #[clap(long, short = 'd')] diff --git a/src/bin/maker-cli.rs b/src/bin/maker-cli.rs index 458328c0..9ed04e13 100644 --- a/src/bin/maker-cli.rs +++ b/src/bin/maker-cli.rs @@ -37,7 +37,7 @@ enum Commands { FidelityBalance, /// Gets a new address NewAddress, - // Send to an external wallet address. + // Send to an external address and returns the transaction hex. SendToAddress { address: String, amount: u64, @@ -45,8 +45,10 @@ enum Commands { }, /// Returns the tor address GetTorAddress, - /// Returns the data dir + /// Returns the data directory path GetDataDir, + /// Stops the maker server + Stop, } fn main() -> Result<(), MakerError> { @@ -95,12 +97,17 @@ fn main() -> Result<(), MakerError> { fee, })?; } + // TODO: Test Coverage Commands::GetTorAddress => { send_rpc_req(&RpcMsgReq::GetTorAddress)?; } + // TODO: Test Coverage Commands::GetDataDir => { send_rpc_req(&RpcMsgReq::GetDataDir)?; } + Commands::Stop => { + send_rpc_req(&RpcMsgReq::Stop)?; + } } Ok(()) @@ -116,7 +123,7 @@ fn send_rpc_req(req: &RpcMsgReq) -> Result<(), MakerError> { let response_bytes = read_message(&mut stream)?; let response: RpcMsgResp = serde_cbor::from_slice(&response_bytes)?; - println!("{:?}", response); + println!("{}", response); Ok(()) } diff --git a/src/bin/makerd.rs b/src/bin/makerd.rs index 89c1aa8c..17dc715f 100644 --- a/src/bin/makerd.rs +++ b/src/bin/makerd.rs @@ -16,7 +16,7 @@ use std::{path::PathBuf, str::FromStr, sync::Arc}; author = option_env ! ("CARGO_PKG_AUTHORS").unwrap_or(""))] struct Cli { /// Optional Connection Network Type - #[clap(long, default_value = "clearnet", possible_values = &["tor", "clearnet"])] + #[clap(long, default_value = "tor", possible_values = &["tor", "clearnet"])] network: String, /// Optional DNS data directory. Default value : "~/.coinswap/maker" #[clap(long, short = 'd')] diff --git a/src/maker/api.rs b/src/maker/api.rs index d634f550..70101d21 100644 --- a/src/maker/api.rs +++ b/src/maker/api.rs @@ -108,6 +108,8 @@ pub struct Maker { pub highest_fidelity_proof: RwLock>, /// Is setup complete pub is_setup_complete: AtomicBool, + /// Path for the data directory. + pub data_dir: PathBuf, } #[allow(clippy::too_many_arguments)] @@ -141,15 +143,7 @@ impl Maker { }; // Get provided data directory or the default data directory. - let data_dir = if cfg!(feature = "integration-test") { - // We only append port number in data-dir for integration test - let port = port.expect("port value expected in Int tests"); - data_dir.map_or(get_maker_dir().join(port.to_string()), |d| { - d.join("maker").join(port.to_string()) - }) - } else { - data_dir.unwrap_or(get_maker_dir()) - }; + let data_dir = data_dir.unwrap_or(get_maker_dir()); let wallet_dir = data_dir.join("wallets"); @@ -222,9 +216,14 @@ impl Maker { connection_state: Mutex::new(HashMap::new()), highest_fidelity_proof: RwLock::new(None), is_setup_complete: AtomicBool::new(false), + data_dir, }) } + pub fn get_data_dir(&self) -> &PathBuf { + &self.data_dir + } + /// Returns a reference to the Maker's wallet. pub fn get_wallet(&self) -> &RwLock { &self.wallet diff --git a/src/maker/config.rs b/src/maker/config.rs index a3a85844..ca8c1cbd 100644 --- a/src/maker/config.rs +++ b/src/maker/config.rs @@ -43,7 +43,7 @@ impl Default for MakerConfig { time_relative_fee_ppb: Amount::from_sat(100_000), min_size: 10_000, socks_port: 19050, - directory_server_address: "directoryhiddenserviceaddress.onion:8080".to_string(), + directory_server_address: "127.0.0.1:8080".to_string(), fidelity_value: 5_000_000, // 5 million sats fidelity_timelock: 26_000, // Approx 6 months of blocks connection_type: ConnectionType::TOR, diff --git a/src/maker/rpc/messages.rs b/src/maker/rpc/messages.rs index d0416d57..595d21ab 100644 --- a/src/maker/rpc/messages.rs +++ b/src/maker/rpc/messages.rs @@ -1,3 +1,5 @@ +use std::{fmt::Display, path::PathBuf}; + use bitcoind::bitcoincore_rpc::json::ListUnspentResultEntry; use serde::{Deserialize, Serialize}; @@ -20,6 +22,7 @@ pub enum RpcMsgReq { }, GetTorAddress, GetDataDir, + Stop, } #[derive(Serialize, Deserialize, Debug)] @@ -36,5 +39,27 @@ pub enum RpcMsgResp { NewAddressResp(String), SendToAddressResp(String), GetTorAddressResp(String), - GetDataDirResp(String), + GetDataDirResp(PathBuf), + Shutdown, +} + +impl Display for RpcMsgResp { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Pong => write!(f, "Pong"), + Self::NewAddressResp(addr) => write!(f, "{}", addr), + Self::SeedBalanceResp(bal) => write!(f, "{} sats", bal), + Self::ContractBalanceResp(bal) => write!(f, "{} sats", bal), + Self::SwapBalanceResp(bal) => write!(f, "{} sats", bal), + Self::FidelityBalanceResp(bal) => write!(f, "{} sats", bal), + Self::SeedUtxoResp { utxos } => write!(f, "{:?}", utxos), + Self::SwapUtxoResp { utxos } => write!(f, "{:?}", utxos), + Self::FidelityUtxoResp { utxos } => write!(f, "{:?}", utxos), + Self::ContractUtxoResp { utxos } => write!(f, "{:?}", utxos), + Self::SendToAddressResp(tx_hex) => write!(f, "{:?}", tx_hex), + Self::GetTorAddressResp(addr) => write!(f, "{:?}", addr), + Self::GetDataDirResp(path) => write!(f, "{:?}", path), + Self::Shutdown => write!(f, "Shutdown Initiated"), + } + } } diff --git a/src/maker/rpc/server.rs b/src/maker/rpc/server.rs index 7a023f0d..f0b84952 100644 --- a/src/maker/rpc/server.rs +++ b/src/maker/rpc/server.rs @@ -1,6 +1,8 @@ use std::{ - io::ErrorKind, + fs::File, + io::{ErrorKind, Read}, net::{TcpListener, TcpStream}, + path::PathBuf, sync::{atomic::Ordering::Relaxed, Arc}, thread::sleep, time::Duration, @@ -10,7 +12,7 @@ use bitcoin::{Address, Amount}; use crate::{ maker::{error::MakerError, rpc::messages::RpcMsgResp, Maker}, - utill::{get_maker_dir, get_tor_addrs, read_message, send_message}, + utill::{read_message, send_message, ConnectionType}, wallet::{Destination, SendAmount}, }; use std::str::FromStr; @@ -144,16 +146,37 @@ fn handle_request(maker: &Arc, socket: &mut TcpStream) -> Result<(), Make }; } RpcMsgReq::GetDataDir => { - let path = get_maker_dir().display().to_string(); - let resp = RpcMsgResp::GetDataDirResp(path); + let path = maker.get_data_dir(); + let resp = RpcMsgResp::GetDataDirResp(path.clone()); if let Err(e) = send_message(socket, &resp) { log::info!("Error sending RPC response {:?}", e); }; } RpcMsgReq::GetTorAddress => { - let path = get_maker_dir().join("tor"); - let resp = RpcMsgResp::GetTorAddressResp(get_tor_addrs(&path)?); - if let Err(e) = send_message(socket, &resp) { + if maker.config.connection_type == ConnectionType::CLEARNET { + let resp = RpcMsgResp::GetTorAddressResp("Maker Tor is not running".to_string()); + if let Err(e) = send_message(socket, &resp) { + log::info!("Error sending RPC response {:?}", e); + }; + } else { + let maker_hs_path_str = + format!("/tmp/tor-rust-maker{}/hs-dir/hostname", maker.config.port); + let maker_hs_path = PathBuf::from(maker_hs_path_str); + let mut maker_file = File::open(maker_hs_path)?; + let mut maker_onion_addr: String = String::new(); + maker_file.read_to_string(&mut maker_onion_addr)?; + maker_onion_addr.pop(); + let maker_address = format!("{}:{}", maker_onion_addr, maker.config.port); + + let resp = RpcMsgResp::GetTorAddressResp(maker_address); + if let Err(e) = send_message(socket, &resp) { + log::info!("Error sending RPC response {:?}", e); + }; + } + } + RpcMsgReq::Stop => { + maker.shutdown.store(true, Relaxed); + if let Err(e) = send_message(socket, &RpcMsgResp::Shutdown) { log::info!("Error sending RPC response {:?}", e); }; } diff --git a/src/wallet/fidelity.rs b/src/wallet/fidelity.rs index c0bf97d0..331bff26 100644 --- a/src/wallet/fidelity.rs +++ b/src/wallet/fidelity.rs @@ -393,7 +393,7 @@ impl Wallet { break ht; } else { log::info!( - "Fildelity Transaction {} seen in mempool, waiting for confirmation.", + "Fidelity Transaction {} seen in mempool, waiting for confirmation.", txid ); diff --git a/tests/abort1.rs b/tests/abort1.rs index c6dc9f4b..3ad6599e 100644 --- a/tests/abort1.rs +++ b/tests/abort1.rs @@ -31,7 +31,6 @@ fn test_stop_taker_after_setup() { // Initiate test framework, Makers. // Taker has a special behavior DropConnectionAfterFullSetup. let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, makers_config_map.into(), Some(TakerBehavior::DropConnectionAfterFullSetup), ConnectionType::CLEARNET, diff --git a/tests/abort2_case1.rs b/tests/abort2_case1.rs index 1d5e9e34..0d5961ee 100644 --- a/tests/abort2_case1.rs +++ b/tests/abort2_case1.rs @@ -32,12 +32,8 @@ fn test_abort_case_2_move_on_with_other_makers() { // Initiate test framework, Makers. // Taker has normal behavior. - let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, taker, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); warn!( "Running Test: Maker 6102 closes before sending sender's sigs. Taker moves on with other Makers." diff --git a/tests/abort2_case2.rs b/tests/abort2_case2.rs index b8197732..14bc7a71 100644 --- a/tests/abort2_case2.rs +++ b/tests/abort2_case2.rs @@ -39,12 +39,8 @@ fn test_abort_case_2_recover_if_no_makers_found() { // Initiate test framework, Makers. // Taker has normal behavior. - let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, taker, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); // Fund the Taker and Makers with 3 utxos of 0.05 btc each. for _ in 0..3 { diff --git a/tests/abort2_case3.rs b/tests/abort2_case3.rs index 2a10c971..e2095db5 100644 --- a/tests/abort2_case3.rs +++ b/tests/abort2_case3.rs @@ -33,12 +33,8 @@ fn maker_drops_after_sending_senders_sigs() { // Initiate test framework, Makers. // Taker has normal behavior. - let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, taker, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); warn!( "Running Test: Maker 6102 Closes after sending sender's signature. This is really bad. Recovery is the only option." diff --git a/tests/abort3_case1.rs b/tests/abort3_case1.rs index 3c25eb38..60b7e2e2 100644 --- a/tests/abort3_case1.rs +++ b/tests/abort3_case1.rs @@ -35,12 +35,8 @@ fn abort3_case1_close_at_contract_sigs_for_recvr_and_sender() { // Initiate test framework, Makers. // Taker has normal behavior. - let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, taker, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); warn!("Running Test: Maker closes connection after receiving a ContractSigsForRecvrAndSender"); diff --git a/tests/abort3_case2.rs b/tests/abort3_case2.rs index 17968945..3ec86b41 100644 --- a/tests/abort3_case2.rs +++ b/tests/abort3_case2.rs @@ -32,12 +32,8 @@ fn abort3_case2_close_at_contract_sigs_for_recvr() { // Initiate test framework, Makers. // Taker has normal behavior. - let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, taker, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); warn!("Running Test: Maker closes connection after sending a ContractSigsForRecvr"); diff --git a/tests/abort3_case3.rs b/tests/abort3_case3.rs index aac34922..e79f7169 100644 --- a/tests/abort3_case3.rs +++ b/tests/abort3_case3.rs @@ -32,12 +32,8 @@ fn abort3_case3_close_at_hash_preimage_handover() { // Initiate test framework, Makers. // Taker has normal behavior. - let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, taker, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); warn!("Running Test: Maker closes conneciton at hash preimage handling"); diff --git a/tests/dns.rs b/tests/dns.rs index 787e5605..d8dbadc4 100644 --- a/tests/dns.rs +++ b/tests/dns.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "integration-test")] use std::{ io::{BufRead, BufReader, Write}, net::TcpStream, @@ -13,35 +14,42 @@ use std::{ fn start_server() -> (Child, Receiver) { let (log_sender, log_receiver): (Sender, Receiver) = mpsc::channel(); let mut directoryd_process = Command::new("./target/debug/directoryd") + .args(&["-n", "clearnet"]) .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) .spawn() .unwrap(); let stdout = directoryd_process.stdout.take().unwrap(); + let std_err = directoryd_process.stderr.take().unwrap(); thread::spawn(move || { let reader = BufReader::new(stdout); reader.lines().map_while(Result::ok).for_each(|line| { + println!("{}", line); log_sender.send(line).unwrap_or_else(|e| { println!("Failed to send log: {}", e); }); }); }); + thread::spawn(move || { + let reader = BufReader::new(std_err); + reader.lines().map_while(Result::ok).for_each(|line| { + panic!("Error : {}", line); + }) + }); + (directoryd_process, log_receiver) } fn wait_for_server_start(log_receiver: &Receiver) { - let mut server_started = false; - while let Ok(log_message) = log_receiver.recv_timeout(Duration::from_secs(5)) { + loop { + let log_message = log_receiver.recv().unwrap(); if log_message.contains("RPC socket binding successful") { - server_started = true; + log::info!("DNS server started"); break; } } - assert!( - server_started, - "Server did not start within the expected time" - ); } fn send_addresses(addresses: &[&str]) { diff --git a/tests/fidelity.rs b/tests/fidelity.rs index 3cb5395e..0d4c92c6 100644 --- a/tests/fidelity.rs +++ b/tests/fidelity.rs @@ -25,12 +25,8 @@ fn test_fidelity() { // ---- Setup ---- let makers_config_map = [((6102, None), MakerBehavior::Normal)]; - let (test_framework, _, makers, directory_server_instance) = TestFramework::init( - None, - makers_config_map.into(), - None, - ConnectionType::CLEARNET, - ); + let (test_framework, _, makers, directory_server_instance) = + TestFramework::init(makers_config_map.into(), None, ConnectionType::CLEARNET); let maker = makers.first().unwrap(); diff --git a/tests/maker-cli.rs b/tests/maker-cli.rs new file mode 100644 index 00000000..60a16aa5 --- /dev/null +++ b/tests/maker-cli.rs @@ -0,0 +1,335 @@ +#![cfg(feature = "integration-test")] +use bitcoin::{Address, Amount, Network}; +use bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD}; +use coinswap::utill::setup_logger; +use std::{ + fs, + io::{BufRead, BufReader}, + path::PathBuf, + process::{Child, Command}, + str::FromStr, + sync::mpsc::{self, Receiver, Sender}, + thread, + time::Duration, +}; + +mod test_framework; +use test_framework::{get_random_tmp_dir, init_bitcoind}; + +struct MakerCli { + data_dir: PathBuf, + bitcoind: BitcoinD, +} + +impl MakerCli { + fn new() -> Self { + setup_logger(log::LevelFilter::Info); + // Setup directory + let temp_dir = get_random_tmp_dir(); + // Remove if previously existing + if temp_dir.exists() { + fs::remove_dir_all::(temp_dir.clone()).unwrap(); + } + log::info!("temporary directory : {}", temp_dir.display()); + + let bitcoind = init_bitcoind(&temp_dir); + + let mining_address = bitcoind + .client + .get_new_address(None, None) + .unwrap() + .require_network(Network::Regtest) + .unwrap(); + bitcoind + .client + .generate_to_address(101, &mining_address) + .unwrap(); + + let data_dir = temp_dir.join("maker"); + fs::create_dir_all(&data_dir).unwrap(); + + MakerCli { data_dir, bitcoind } + } + + fn start_makerd(&self) -> (Receiver, Child, Child) { + let (log_sender, log_receiver): (Sender, Receiver) = mpsc::channel(); + + let mut directoryd_process = Command::new("./target/debug/directoryd") + .stdout(std::process::Stdio::piped()) + .spawn() + .unwrap(); + + let stdout = directoryd_process.stdout.take().unwrap(); + thread::spawn(move || { + let reader = BufReader::new(stdout); + reader.lines().map_while(Result::ok).for_each(|line| { + println!("{}", line); + log_sender.send(line).unwrap_or_else(|e| { + println!("Failed to send log: {}", e); + }); + }); + }); + + while let Ok(log_message) = log_receiver.recv_timeout(Duration::from_secs(5)) { + if log_message.contains("RPC socket binding successful") { + println!("DNS Started"); + break; + } + } + + log::info!("DNS Server started"); + + let (maker_log_sender, maker_log_recvr) = mpsc::channel(); + let data_dir = self.data_dir.clone(); + + let cookie_file_path = self.bitcoind.params.cookie_file.clone(); + let rpc_auth = fs::read_to_string(cookie_file_path).expect("failed to read from file"); + let rpc_address = self.bitcoind.params.rpc_socket.to_string(); + + let mut makerd_process = Command::new("./target/debug/makerd") + .args([ + "--data-directory", + data_dir.to_str().unwrap(), + "-a", + &rpc_auth, + "-r", + &rpc_address, + "-w", + "maker-wallet", + ]) + .stdout(std::process::Stdio::piped()) + .stderr(std::process::Stdio::piped()) + .spawn() + .unwrap(); + + log::info!("Maker Server started"); + + let stdout = makerd_process.stdout.take().unwrap(); + let stderr = makerd_process.stderr.take().unwrap(); + let sender = maker_log_sender.clone(); + // start the thread to get the logs + thread::spawn(move || { + let reader = BufReader::new(stdout); + reader.lines().map_while(Result::ok).for_each(|line| { + println!("{}", line); + sender.send(line).unwrap_or_else(|e| { + println!("Failed to send log: {}", e); + }); + }); + }); + + // Panic if anything is found in std error. + thread::spawn(move || { + let reader = BufReader::new(stderr); + reader.lines().map_while(Result::ok).for_each(|line| { + panic!("Error: {}", line); + }); + }); + + let (amount, addrs) = loop { + let log_message = maker_log_recvr.recv().unwrap(); + if log_message.contains("Send at least 0.05001000 BTC") { + let parts: Vec<&str> = log_message.split_whitespace().collect(); + let amount = Amount::from_str_in(parts[7], bitcoin::Denomination::Bitcoin).unwrap(); + let addr = Address::from_str(parts[10]).unwrap().assume_checked(); // Do it properly + break (amount, addr); + } else { + println!("Waiting for fidelity initialization.") + } + }; + + // Fund the fidelity + let fidelity_txid = self + .bitcoind + .client + .send_to_address( + &addrs, + amount.checked_add(Amount::from_btc(0.01).unwrap()).unwrap(), + None, + None, + None, + None, + None, + None, + ) + .unwrap(); + + log::info!("Sent the Funding Tx: {}", fidelity_txid); + + // Wait for mempool + loop { + let log_message = maker_log_recvr.recv().unwrap(); + if log_message.contains("seen in mempool, waiting for confirmation") { + break; + } + } + + log::info!("Confirming the fidelity tx"); + + // Wait for confirmation + let mining_address = self + .bitcoind + .client + .get_new_address(None, None) + .unwrap() + .require_network(Network::Regtest) + .unwrap(); + + self.bitcoind + .client + .generate_to_address(1, &mining_address) + .unwrap(); + + // Wait final setup + loop { + let log_message = maker_log_recvr.recv().unwrap(); + if log_message.contains("Maker setup is ready") { + break; + } + } + + log::info!("Maker setup is ready"); + + (maker_log_recvr, makerd_process, directoryd_process) + } + + fn execute_maker_cli(&self, args: &[&str]) -> String { + let output = Command::new("./target/debug/maker-cli") + .args(args) + .output() + .unwrap(); + + // Capture the standard output and error from the command execution + let mut value = output.stdout; + let error = output.stderr; + + // Panic if there is any error output + if !error.is_empty() { + panic!("Error: {:?}", String::from_utf8(error).unwrap()); + } + + // Remove the `\n` at the end of the output + value.pop(); + + // Convert the output bytes to a UTF-8 string + let output_string = std::str::from_utf8(&value).unwrap().to_string(); + + output_string + } +} + +#[test] +fn test_makecli_get_new_address() { + let maker_cli = MakerCli::new(); + let (rx, mut makerd_proc, mut directoryd_proc) = maker_cli.start_makerd(); + + // Address check + let addr_resp = maker_cli.execute_maker_cli(&["new-address"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: NewAddress") { + log::info!("RPC Message received"); + break; + } + } + assert!(Address::from_str(&addr_resp).is_ok()); + + // Balance checks + let seed_balance = maker_cli.execute_maker_cli(&["seed-balance"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: SeedBalance") { + log::info!("RPC Message received"); + break; + } + } + let contract_balance = maker_cli.execute_maker_cli(&["contract-balance"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: ContractBalance") { + log::info!("RPC Message received"); + break; + } + } + let fidelity_balance = maker_cli.execute_maker_cli(&["fidelity-balance"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: FidelityBalance") { + log::info!("RPC Message received"); + break; + } + } + let swap_balance = maker_cli.execute_maker_cli(&["swap-balance"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: SwapBalance") { + log::info!("RPC Message received"); + break; + } + } + assert_eq!(seed_balance, "1000000 sats"); + assert_eq!(swap_balance, "0 sats"); + assert_eq!(fidelity_balance, "5000000 sats"); + assert_eq!(contract_balance, "0 sats"); + + // UTXO checks + let seed_utxo = maker_cli.execute_maker_cli(&["seed-utxo"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: SeedUtxo") { + log::info!("RPC Message received"); + break; + } + } + let swap_utxo = maker_cli.execute_maker_cli(&["swap-utxo"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: SwapUtxo") { + log::info!("RPC Message received"); + break; + } + } + let contract_utxo = maker_cli.execute_maker_cli(&["contract-utxo"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: ContractUtxo") { + log::info!("RPC Message received"); + break; + } + } + let fidelity_utxo = maker_cli.execute_maker_cli(&["fidelity-utxo"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: FidelityUtxo") { + log::info!("RPC Message received"); + break; + } + } + + assert_eq!(seed_utxo.matches("ListUnspentResultEntry").count(), 1); + assert!(seed_utxo.contains("amount: 1000000 SAT")); + assert_eq!(fidelity_utxo.matches("ListUnspentResultEntry").count(), 1); + assert!(fidelity_utxo.contains("amount: 5000000 SAT")); + assert_eq!(swap_utxo.matches("ListUnspentResultEntry").count(), 0); + assert_eq!(contract_utxo.matches("ListUnspentResultEntry").count(), 0); + + let data_dir = maker_cli.execute_maker_cli(&["get-data-dir"]); + let tor_addr = maker_cli.execute_maker_cli(&["get-tor-address"]); + + assert!(data_dir.contains("/tmp/.coinswap/")); + assert!(tor_addr.contains(".onion:6102")); + + // Stop everything + let stop = maker_cli.execute_maker_cli(&["stop"]); + loop { + let log_message = rx.recv().unwrap(); + if log_message.contains(" RPC request received: Stop") { + log::info!("RPC Message received"); + break; + } + } + assert_eq!(stop, "Shutdown Initiated"); + directoryd_proc.kill().unwrap(); + directoryd_proc.wait().unwrap(); + makerd_proc.wait().unwrap(); +} diff --git a/tests/malice1.rs b/tests/malice1.rs index 558c8ea6..7f5cc133 100644 --- a/tests/malice1.rs +++ b/tests/malice1.rs @@ -30,7 +30,6 @@ fn malice1_taker_broadcast_contract_prematurely() { // Initiate test framework, Makers. // Taker has normal behavior. let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, makers_config_map.into(), Some(TakerBehavior::BroadcastContractAfterFullSetup), ConnectionType::CLEARNET, diff --git a/tests/malice2.rs b/tests/malice2.rs index b0530918..19c408b0 100644 --- a/tests/malice2.rs +++ b/tests/malice2.rs @@ -30,7 +30,6 @@ fn malice2_maker_broadcast_contract_prematurely() { // Initiate test framework, Makers. // Taker has normal behavior. let (test_framework, taker, makers, directory_server_instance) = TestFramework::init( - None, makers_config_map.into(), Some(TakerBehavior::Normal), ConnectionType::CLEARNET, diff --git a/tests/standard_swap.rs b/tests/standard_swap.rs index d3286e70..90787eb2 100644 --- a/tests/standard_swap.rs +++ b/tests/standard_swap.rs @@ -35,7 +35,7 @@ fn test_standard_coinswap() { // Initiate test framework, Makers and a Taker with default behavior. let (test_framework, taker, makers, directory_server_instance) = - TestFramework::init(None, makers_config_map.into(), None, connection_type); + TestFramework::init(makers_config_map.into(), None, connection_type); warn!("Running Test: Standard Coinswap Procedure"); diff --git a/tests/taker_cli.rs b/tests/taker_cli.rs index 73cb7601..6ad1a103 100644 --- a/tests/taker_cli.rs +++ b/tests/taker_cli.rs @@ -1,3 +1,4 @@ +#![cfg(feature = "integration-test")] use bitcoin::{address::NetworkChecked, Address, Amount, Transaction}; use bitcoind::{bitcoincore_rpc::RpcApi, tempfile::env::temp_dir, BitcoinD, Conf}; diff --git a/tests/test_framework/mod.rs b/tests/test_framework/mod.rs index 9f116611..1e23e750 100644 --- a/tests/test_framework/mod.rs +++ b/tests/test_framework/mod.rs @@ -18,7 +18,7 @@ use bitcoin::{ use std::{ collections::HashMap, fs, - path::PathBuf, + path::{Path, PathBuf}, sync::{ atomic::{AtomicBool, Ordering::Relaxed}, Arc, RwLock, @@ -29,7 +29,7 @@ use std::{ use bitcoind::{ bitcoincore_rpc::{Auth, Client, RpcApi}, - BitcoinD, Conf, + BitcoinD, }; use coinswap::{ maker::{Maker, MakerBehavior}, @@ -39,7 +39,7 @@ use coinswap::{ wallet::RPCConfig, }; -fn get_random_tmp_dir() -> PathBuf { +pub fn get_random_tmp_dir() -> PathBuf { let s: String = thread_rng() .sample_iter(&Alphanumeric) .take(8) @@ -49,6 +49,46 @@ fn get_random_tmp_dir() -> PathBuf { PathBuf::from(path) } +pub fn init_bitcoind(datadir: &Path) -> BitcoinD { + // Initiate the bitcoind backend. + let mut conf = bitcoind::Conf::default(); + conf.args.push("-txindex=1"); //txindex is must, or else wallet sync won't work. + conf.staticdir = Some(datadir.join(".bitcoin")); + log::info!("bitcoind datadir: {:?}", conf.staticdir.as_ref().unwrap()); + log::info!("bitcoind configuration: {:?}", conf.args); + + let os = std::env::consts::OS; + let arch = std::env::consts::ARCH; + let key = "BITCOIND_EXE"; + let curr_dir_path = std::env::current_dir().unwrap(); + + let bitcoind_path = match (os, arch) { + ("macos", "aarch64") => curr_dir_path.join("bin").join("bitcoind_macos"), + _ => curr_dir_path.join("bin").join("bitcoind"), + }; + std::env::set_var(key, bitcoind_path); + let exe_path = bitcoind::exe_path().unwrap(); + + log::info!("Executable path: {:?}", exe_path); + + let bitcoind = BitcoinD::with_conf(exe_path, &conf).unwrap(); + + // Generate initial 101 blocks + let mining_address = bitcoind + .client + .get_new_address(None, None) + .unwrap() + .require_network(bitcoind::bitcoincore_rpc::bitcoin::Network::Regtest) + .unwrap(); + bitcoind + .client + .generate_to_address(101, &mining_address) + .unwrap(); + log::info!("bitcoind initiated!!"); + + bitcoind +} + /// The Test Framework. /// /// Handles initializing, operating and cleaning up of all backend processes. Bitcoind, Taker and Makers. @@ -71,7 +111,6 @@ impl TestFramework { /// If no bitcoind conf is provide a default value will be used. #[allow(clippy::type_complexity)] pub fn init( - bitcoind_conf: Option>, makers_config_map: HashMap<(u16, Option), MakerBehavior>, taker_behavior: Option, connection_type: ConnectionType, @@ -93,40 +132,8 @@ impl TestFramework { } log::info!("temporary directory : {}", temp_dir.display()); - // Initiate the bitcoind backend. - let mut conf = bitcoind_conf.unwrap_or_default(); - conf.args.push("-txindex=1"); //txindex is must, or else wallet sync won't work. - conf.staticdir = Some(temp_dir.join(".bitcoin")); - log::info!("bitcoind configuration: {:?}", conf.args); - - let os = std::env::consts::OS; - let arch = std::env::consts::ARCH; - let key = "BITCOIND_EXE"; - let curr_dir_path = std::env::current_dir().unwrap(); - - let bitcoind_path = match (os, arch) { - ("macos", "aarch64") => curr_dir_path.join("bin").join("bitcoind_macos"), - _ => curr_dir_path.join("bin").join("bitcoind"), - }; - std::env::set_var(key, bitcoind_path); - let exe_path = bitcoind::exe_path().unwrap(); + let bitcoind = init_bitcoind(&temp_dir); - log::info!("Executable path: {:?}", exe_path); - - let bitcoind = BitcoinD::with_conf(exe_path, &conf).unwrap(); - - // Generate initial 101 blocks - let mining_address = bitcoind - .client - .get_new_address(None, None) - .unwrap() - .require_network(bitcoind::bitcoincore_rpc::bitcoin::Network::Regtest) - .unwrap(); - bitcoind - .client - .generate_to_address(101, &mining_address) - .unwrap(); - log::info!("bitcoind initiated!!"); let shutdown = AtomicBool::new(false); let test_framework = Arc::new(Self { bitcoind, @@ -175,7 +182,7 @@ impl TestFramework { thread::sleep(Duration::from_secs(5)); // Sleep for some time avoid resource unavailable error. Arc::new( Maker::init( - Some(temp_dir.clone()), + Some(temp_dir.join(port.0.to_string()).clone()), Some(maker_id), Some(maker_rpc_config), Some(port.0),