From 7b101a9c98c03595b7814681d65fd60eb7b165bc Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Thu, 29 Oct 2020 12:52:00 +1100 Subject: [PATCH 01/15] upgrade testcontainers --- monero-harness/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monero-harness/Cargo.toml b/monero-harness/Cargo.toml index 226866f7..7dc6cd23 100644 --- a/monero-harness/Cargo.toml +++ b/monero-harness/Cargo.toml @@ -13,7 +13,7 @@ reqwest = { version = "0.10", default-features = false, features = ["json", "nat serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" spectral = "0.6" -testcontainers = "0.10" +testcontainers = "0.11" tokio = { version = "0.2", default-features = false, features = ["blocking", "macros", "rt-core", "time"] } tracing = "0.1" url = "2" From 0dcb4e56bef73747117a40e941e761f42a2674dc Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Thu, 29 Oct 2020 12:52:29 +1100 Subject: [PATCH 02/15] Have monerod running in own container --- monero-harness/src/image.rs | 11 +- monero-harness/src/lib.rs | 211 +++++++----------------------------- 2 files changed, 48 insertions(+), 174 deletions(-) diff --git a/monero-harness/src/image.rs b/monero-harness/src/image.rs index 1998b4bc..11e68cd0 100644 --- a/monero-harness/src/image.rs +++ b/monero-harness/src/image.rs @@ -124,6 +124,12 @@ pub struct Args { wallets: Vec, } +#[derive(Debug)] +pub enum MoneroArgs { + MonerodArgs(MonerodArgs), + WalletArgs(WalletArgs), +} + #[derive(Debug, Clone)] pub struct MonerodArgs { pub regtest: bool, @@ -282,10 +288,7 @@ impl IntoIterator for Args { args.push("/bin/bash".into()); args.push("-c".into()); - let wallet_args: Vec = self.wallets.iter().map(|wallet| wallet.args()).collect(); - let wallet_args = wallet_args.join(" & "); - - let cmd = format!("{} & {} ", self.monerod.args(), wallet_args); + let cmd = format!("{} ", self.monerod.args()); args.push(cmd); args.into_iter() diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index 4c7e262b..da654d5a 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -27,7 +27,7 @@ pub mod rpc; use anyhow::{anyhow, Result}; use serde::Deserialize; use std::time::Duration; -use testcontainers::{clients::Cli, core::Port, Container, Docker}; +use testcontainers::{clients::Cli, core::Port, Container, Docker, RunArgs}; use tokio::time; use crate::{ @@ -44,15 +44,9 @@ const BLOCK_TIME_SECS: u64 = 1; /// Poll interval when checking if the wallet has synced with monerod. const WAIT_WALLET_SYNC_MILLIS: u64 = 1000; -/// Wallet sub-account indices. -const ACCOUNT_INDEX_PRIMARY: u32 = 0; - #[derive(Copy, Clone, Debug)] pub struct Monero { monerod_rpc_port: u16, - miner_wallet_rpc_port: u16, - alice_wallet_rpc_port: u16, - bob_wallet_rpc_port: u16, } impl<'c> Monero { @@ -60,59 +54,18 @@ impl<'c> Monero { pub fn new(cli: &'c Cli) -> Result<(Self, Container<'c, Cli, image::Monero>)> { let monerod_rpc_port: u16 = port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; - let miner_wallet_rpc_port: u16 = - port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; - let alice_wallet_rpc_port: u16 = - port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; - let bob_wallet_rpc_port: u16 = - port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; - - let image = image::Monero::default() - .with_mapped_port(Port { - local: monerod_rpc_port, - internal: MONEROD_RPC_PORT, - }) - .with_mapped_port(Port { - local: miner_wallet_rpc_port, - internal: MINER_WALLET_RPC_PORT, - }) - .with_wallet("miner", MINER_WALLET_RPC_PORT) - .with_mapped_port(Port { - local: alice_wallet_rpc_port, - internal: ALICE_WALLET_RPC_PORT, - }) - .with_wallet("alice", ALICE_WALLET_RPC_PORT) - .with_mapped_port(Port { - local: bob_wallet_rpc_port, - internal: BOB_WALLET_RPC_PORT, - }) - .with_wallet("bob", BOB_WALLET_RPC_PORT); - - println!("running image ..."); - let docker = cli.run(image); - println!("image ran"); - Ok(( - Self { - monerod_rpc_port, - miner_wallet_rpc_port, - alice_wallet_rpc_port, - bob_wallet_rpc_port, - }, - docker, - )) - } - - pub fn miner_wallet_rpc_client(&self) -> wallet::Client { - wallet::Client::localhost(self.miner_wallet_rpc_port) - } + let image = image::Monero::default().with_mapped_port(Port { + local: monerod_rpc_port, + internal: MONEROD_RPC_PORT, + }); - pub fn alice_wallet_rpc_client(&self) -> wallet::Client { - wallet::Client::localhost(self.alice_wallet_rpc_port) - } + let run_args = RunArgs::default() + .with_name("monerod") + .with_network("monero"); + let docker = cli.run_with_args(image, run_args); - pub fn bob_wallet_rpc_client(&self) -> wallet::Client { - wallet::Client::localhost(self.bob_wallet_rpc_port) + Ok((Self { monerod_rpc_port }, docker)) } pub fn monerod_rpc_client(&self) -> monerod::Client { @@ -124,122 +77,40 @@ impl<'c> Monero { /// sub-accounts, one for Alice and one for Bob. If alice/bob_funding is /// some, the value needs to be > 0. pub async fn init(&self, alice_funding: u64, bob_funding: u64) -> Result<()> { - let miner_wallet = self.miner_wallet_rpc_client(); - let alice_wallet = self.alice_wallet_rpc_client(); - let bob_wallet = self.bob_wallet_rpc_client(); - let monerod = self.monerod_rpc_client(); - - miner_wallet.create_wallet("miner_wallet").await?; - alice_wallet.create_wallet("alice_wallet").await?; - bob_wallet.create_wallet("bob_wallet").await?; - - let miner = self.get_address_miner().await?.address; - let alice = self.get_address_alice().await?.address; - let bob = self.get_address_bob().await?.address; - - let _ = monerod.generate_blocks(70, &miner).await?; - self.wait_for_miner_wallet_block_height().await?; - - if alice_funding > 0 { - self.fund_account(&alice, &miner, alice_funding).await?; - self.wait_for_alice_wallet_block_height().await?; - let balance = self.get_balance_alice().await?; - debug_assert!(balance == alice_funding); - } - - if bob_funding > 0 { - self.fund_account(&bob, &miner, bob_funding).await?; - self.wait_for_bob_wallet_block_height().await?; - let balance = self.get_balance_bob().await?; - debug_assert!(balance == bob_funding); - } - - let _ = tokio::spawn(mine(monerod.clone(), miner)); - - Ok(()) - } - - async fn fund_account(&self, address: &str, miner: &str, funding: u64) -> Result<()> { - let monerod = self.monerod_rpc_client(); - - self.transfer_from_primary(funding, address).await?; - let _ = monerod.generate_blocks(10, miner).await?; - self.wait_for_miner_wallet_block_height().await?; - - Ok(()) - } - - async fn wait_for_miner_wallet_block_height(&self) -> Result<()> { - self.wait_for_wallet_height(self.miner_wallet_rpc_client()) - .await - } - - pub async fn wait_for_alice_wallet_block_height(&self) -> Result<()> { - self.wait_for_wallet_height(self.alice_wallet_rpc_client()) - .await - } - - pub async fn wait_for_bob_wallet_block_height(&self) -> Result<()> { - self.wait_for_wallet_height(self.bob_wallet_rpc_client()) - .await - } - - // It takes a little while for the wallet to sync with monerod. - async fn wait_for_wallet_height(&self, wallet: wallet::Client) -> Result<()> { - let monerod = self.monerod_rpc_client(); - let height = monerod.get_block_count().await?; + // let miner_wallet = self.miner_wallet_rpc_client(); + // let alice_wallet = self.alice_wallet_rpc_client(); + // let bob_wallet = self.bob_wallet_rpc_client(); + // let monerod = self.monerod_rpc_client(); + // + // miner_wallet.create_wallet("miner_wallet").await?; + // alice_wallet.create_wallet("alice_wallet").await?; + // bob_wallet.create_wallet("bob_wallet").await?; + // + // let miner = self.get_address_miner().await?.address; + // let alice = self.get_address_alice().await?.address; + // let bob = self.get_address_bob().await?.address; + // + // let _ = monerod.generate_blocks(70, &miner).await?; + // self.wait_for_miner_wallet_block_height().await?; + // + // if alice_funding > 0 { + // self.fund_account(&alice, &miner, alice_funding).await?; + // self.wait_for_alice_wallet_block_height().await?; + // let balance = self.get_balance_alice().await?; + // debug_assert!(balance == alice_funding); + // } + // + // if bob_funding > 0 { + // self.fund_account(&bob, &miner, bob_funding).await?; + // self.wait_for_bob_wallet_block_height().await?; + // let balance = self.get_balance_bob().await?; + // debug_assert!(balance == bob_funding); + // } + // + // let _ = tokio::spawn(mine(monerod.clone(), miner)); - while wallet.block_height().await?.height < height { - time::delay_for(Duration::from_millis(WAIT_WALLET_SYNC_MILLIS)).await; - } Ok(()) } - - /// Get addresses for the primary account. - async fn get_address_miner(&self) -> Result { - let wallet = self.miner_wallet_rpc_client(); - wallet.get_address(ACCOUNT_INDEX_PRIMARY).await - } - - /// Get addresses for the Alice's account. - async fn get_address_alice(&self) -> Result { - let wallet = self.alice_wallet_rpc_client(); - wallet.get_address(ACCOUNT_INDEX_PRIMARY).await - } - - /// Get addresses for the Bob's account. - async fn get_address_bob(&self) -> Result { - let wallet = self.bob_wallet_rpc_client(); - wallet.get_address(ACCOUNT_INDEX_PRIMARY).await - } - - /// Gets the balance of Alice's account. - async fn get_balance_alice(&self) -> Result { - let wallet = self.alice_wallet_rpc_client(); - wallet.get_balance(ACCOUNT_INDEX_PRIMARY).await - } - - /// Gets the balance of Bob's account. - async fn get_balance_bob(&self) -> Result { - let wallet = self.bob_wallet_rpc_client(); - wallet.get_balance(ACCOUNT_INDEX_PRIMARY).await - } - - /// Transfers moneroj from the primary account. - async fn transfer_from_primary(&self, amount: u64, address: &str) -> Result { - let wallet = self.miner_wallet_rpc_client(); - wallet - .transfer(ACCOUNT_INDEX_PRIMARY, amount, address) - .await - } -} - -/// Mine a block ever BLOCK_TIME_SECS seconds. -async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> { - loop { - time::delay_for(Duration::from_secs(BLOCK_TIME_SECS)).await; - monerod.generate_blocks(1, &reward_address).await?; - } } // We should be able to use monero-rs for this but it does not include all From f5643a4ea464e413cc5515fd2d6ee17e1ea675f6 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Mon, 2 Nov 2020 10:02:28 +1100 Subject: [PATCH 03/15] Miner working --- Cargo.toml | 2 +- monero-harness/Cargo.toml | 1 + monero-harness/src/image.rs | 82 ++++++++++++------ monero-harness/src/lib.rs | 128 ++++++++++++++++++---------- monero-harness/src/rpc/monerod.rs | 15 +++- monero-harness/tests/client.rs | 31 ------- monero-harness/tests/monerod.rs | 54 +++++++++--- monero-harness/tests/wallet.rs | 137 +++++++++++++++--------------- 8 files changed, 267 insertions(+), 183 deletions(-) delete mode 100644 monero-harness/tests/client.rs diff --git a/Cargo.toml b/Cargo.toml index 9d880136..12da321f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["monero-harness", "xmr-btc", "swap"] +members = ["monero-harness"] diff --git a/monero-harness/Cargo.toml b/monero-harness/Cargo.toml index 7dc6cd23..060df781 100644 --- a/monero-harness/Cargo.toml +++ b/monero-harness/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] anyhow = "1" +digest_auth = "0.2.3" futures = "0.3" port_check = "0.1" rand = "0.7" diff --git a/monero-harness/src/image.rs b/monero-harness/src/image.rs index 11e68cd0..8e6b7385 100644 --- a/monero-harness/src/image.rs +++ b/monero-harness/src/image.rs @@ -4,10 +4,10 @@ use testcontainers::{ Image, }; +pub const MONEROD_DAEMON_CONTAINER_NAME: &str = "monerod"; +pub const MONEROD_DEFAULT_NETWORK: &str = "monero_network"; pub const MONEROD_RPC_PORT: u16 = 48081; -pub const MINER_WALLET_RPC_PORT: u16 = 48083; -pub const ALICE_WALLET_RPC_PORT: u16 = 48084; -pub const BOB_WALLET_RPC_PORT: u16 = 48085; +pub const WALLET_RPC_PORT: u16 = 48083; #[derive(Debug)] pub struct Monero { @@ -15,6 +15,7 @@ pub struct Monero { args: Args, ports: Option>, entrypoint: Option, + wait_for_message: String, } impl Image for Monero { @@ -31,9 +32,7 @@ impl Image for Monero { container .logs() .stdout - .wait_for_message( - "The daemon is running offline and will not attempt to sync to the Monero network", - ) + .wait_for_message(&self.wait_for_message) .unwrap(); let additional_sleep_period = @@ -85,6 +84,9 @@ impl Default for Monero { args: Args::default(), ports: None, entrypoint: Some("".into()), + wait_for_message: + "The daemon is running offline and will not attempt to sync to the Monero network" + .to_string(), } } } @@ -104,32 +106,47 @@ impl Monero { self } - pub fn with_wallet(self, name: &str, rpc_port: u16) -> Self { - let wallet = WalletArgs::new(name, rpc_port); - let mut wallet_args = self.args.wallets; - wallet_args.push(wallet); + pub fn wallet(name: &str) -> Self { + let wallet = WalletArgs::new(name, WALLET_RPC_PORT); + let default = Monero::default(); Self { args: Args { - monerod: self.args.monerod, - wallets: wallet_args, + image_args: ImageArgs::WalletArgs(wallet), }, - ..self + wait_for_message: "Run server thread name: RPC".to_string(), + ..default } } } -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct Args { - monerod: MonerodArgs, - wallets: Vec, + image_args: ImageArgs, } -#[derive(Debug)] -pub enum MoneroArgs { +impl Default for Args { + fn default() -> Self { + Self { + image_args: ImageArgs::MonerodArgs(MonerodArgs::default()), + } + } +} + +#[derive(Clone, Debug)] +pub enum ImageArgs { MonerodArgs(MonerodArgs), WalletArgs(WalletArgs), } +impl ImageArgs { + fn args(&self) -> String { + match self { + ImageArgs::MonerodArgs(monerod_args) => monerod_args.args(), + ImageArgs::WalletArgs(wallet_args) => wallet_args.args(), + } + } +} + #[derive(Debug, Clone)] pub struct MonerodArgs { pub regtest: bool, @@ -143,13 +160,14 @@ pub struct MonerodArgs { pub rpc_bind_port: u16, pub fixed_difficulty: u32, pub data_dir: String, + pub log_level: u32, } #[derive(Debug, Clone)] pub struct WalletArgs { pub disable_rpc_login: bool, pub confirm_external_bind: bool, - pub wallet_dir: String, + pub wallet_file: String, pub rpc_bind_ip: String, pub rpc_bind_port: u16, pub daemon_address: String, @@ -171,6 +189,7 @@ impl Default for MonerodArgs { rpc_bind_port: MONEROD_RPC_PORT, fixed_difficulty: 1, data_dir: "/monero".to_string(), + log_level: 2, } } } @@ -224,17 +243,23 @@ impl MonerodArgs { args.push(format!("--fixed-difficulty {}", self.fixed_difficulty)); } + if self.log_level != 0 { + args.push(format!("--log-level {}", self.log_level)); + } + + // args.push(format!("--disable-rpc-login")); + args.join(" ") } } impl WalletArgs { - pub fn new(wallet_dir: &str, rpc_port: u16) -> Self { - let daemon_address = format!("localhost:{}", MONEROD_RPC_PORT); + pub fn new(wallet_name: &str, rpc_port: u16) -> Self { + let daemon_address = format!("{}:{}", MONEROD_DAEMON_CONTAINER_NAME, MONEROD_RPC_PORT); WalletArgs { disable_rpc_login: true, confirm_external_bind: true, - wallet_dir: wallet_dir.into(), + wallet_file: wallet_name.into(), rpc_bind_ip: "0.0.0.0".into(), rpc_bind_port: rpc_port, daemon_address, @@ -254,8 +279,10 @@ impl WalletArgs { args.push("--confirm-external-bind".to_string()) } - if !self.wallet_dir.is_empty() { - args.push(format!("--wallet-dir {}", self.wallet_dir)); + if !self.wallet_file.is_empty() { + args.push(format!("--wallet-dir /monero")); + // args.push(format!("--wallet-file {}", self.wallet_file)); + // args.push(format!("--password {}", self.wallet_file)); } if !self.rpc_bind_ip.is_empty() { @@ -273,6 +300,11 @@ impl WalletArgs { if self.log_level != 0 { args.push(format!("--log-level {}", self.log_level)); } + // args.push(format!("--daemon-login username:password")); + // docker run --rm -d --net host -e DAEMON_HOST=node.xmr.to -e DAEMON_PORT=18081 + // -e RPC_BIND_PORT=18083 -e RPC_USER=user -e RPC_PASSWD=passwd -v + // :/monero xmrto/monero monero-wallet-rpc + // --wallet-file wallet --password-file wallet.passwd args.join(" ") } @@ -288,7 +320,7 @@ impl IntoIterator for Args { args.push("/bin/bash".into()); args.push("-c".into()); - let cmd = format!("{} ", self.monerod.args()); + let cmd = format!("{} ", self.image_args.args()); args.push(cmd); args.into_iter() diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index da654d5a..b15a7a43 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -24,14 +24,16 @@ pub mod image; pub mod rpc; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use serde::Deserialize; use std::time::Duration; use testcontainers::{clients::Cli, core::Port, Container, Docker, RunArgs}; use tokio::time; use crate::{ - image::{ALICE_WALLET_RPC_PORT, BOB_WALLET_RPC_PORT, MINER_WALLET_RPC_PORT, MONEROD_RPC_PORT}, + image::{ + MONEROD_DAEMON_CONTAINER_NAME, MONEROD_DEFAULT_NETWORK, MONEROD_RPC_PORT, WALLET_RPC_PORT, + }, rpc::{ monerod, wallet::{self, GetAddress, Transfer}, @@ -44,14 +46,15 @@ const BLOCK_TIME_SECS: u64 = 1; /// Poll interval when checking if the wallet has synced with monerod. const WAIT_WALLET_SYNC_MILLIS: u64 = 1000; -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] pub struct Monero { - monerod_rpc_port: u16, + rpc_port: u16, + name: String, } impl<'c> Monero { /// Starts a new regtest monero container. - pub fn new(cli: &'c Cli) -> Result<(Self, Container<'c, Cli, image::Monero>)> { + pub fn new_monerod(cli: &'c Cli) -> Result<(Self, Container<'c, Cli, image::Monero>)> { let monerod_rpc_port: u16 = port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; @@ -61,56 +64,91 @@ impl<'c> Monero { }); let run_args = RunArgs::default() - .with_name("monerod") - .with_network("monero"); + .with_name(MONEROD_DAEMON_CONTAINER_NAME) + .with_network(MONEROD_DEFAULT_NETWORK); + let docker = cli.run_with_args(image, run_args); + + Ok(( + Self { + rpc_port: monerod_rpc_port, + name: "monerod".to_string(), + }, + docker, + )) + } + + pub async fn new_wallet( + cli: &'c Cli, + name: &str, + ) -> Result<(Self, Container<'c, Cli, image::Monero>)> { + let wallet_rpc_port: u16 = + port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; + + let image = image::Monero::wallet(&name).with_mapped_port(Port { + local: wallet_rpc_port, + internal: WALLET_RPC_PORT, + }); + + let run_args = RunArgs::default() + .with_name(name) + .with_network(MONEROD_DEFAULT_NETWORK); let docker = cli.run_with_args(image, run_args); - Ok((Self { monerod_rpc_port }, docker)) + // create new wallet + wallet::Client::localhost(wallet_rpc_port) + .create_wallet(name) + .await + .unwrap(); + + Ok(( + Self { + rpc_port: wallet_rpc_port, + name: name.to_string(), + }, + docker, + )) } pub fn monerod_rpc_client(&self) -> monerod::Client { - monerod::Client::localhost(self.monerod_rpc_port) + monerod::Client::localhost(self.rpc_port) } - /// Initialise by creating a wallet, generating some `blocks`, and starting - /// a miner thread that mines to the primary account. Also create two - /// sub-accounts, one for Alice and one for Bob. If alice/bob_funding is - /// some, the value needs to be > 0. - pub async fn init(&self, alice_funding: u64, bob_funding: u64) -> Result<()> { - // let miner_wallet = self.miner_wallet_rpc_client(); - // let alice_wallet = self.alice_wallet_rpc_client(); - // let bob_wallet = self.bob_wallet_rpc_client(); - // let monerod = self.monerod_rpc_client(); - // - // miner_wallet.create_wallet("miner_wallet").await?; - // alice_wallet.create_wallet("alice_wallet").await?; - // bob_wallet.create_wallet("bob_wallet").await?; - // - // let miner = self.get_address_miner().await?.address; - // let alice = self.get_address_alice().await?.address; - // let bob = self.get_address_bob().await?.address; - // - // let _ = monerod.generate_blocks(70, &miner).await?; - // self.wait_for_miner_wallet_block_height().await?; - // - // if alice_funding > 0 { - // self.fund_account(&alice, &miner, alice_funding).await?; - // self.wait_for_alice_wallet_block_height().await?; - // let balance = self.get_balance_alice().await?; - // debug_assert!(balance == alice_funding); - // } - // - // if bob_funding > 0 { - // self.fund_account(&bob, &miner, bob_funding).await?; - // self.wait_for_bob_wallet_block_height().await?; - // let balance = self.get_balance_bob().await?; - // debug_assert!(balance == bob_funding); - // } - // - // let _ = tokio::spawn(mine(monerod.clone(), miner)); + pub fn wallet_rpc_client(&self) -> wallet::Client { + wallet::Client::localhost(self.rpc_port) + } + /// Spawns a task to mine blocks in a regular interval to the provided + /// address + pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> { + let monerod = self.monerod_rpc_client(); + // generate the first 70 as bulk + let block = monerod.generate_blocks(70, &miner_wallet_address).await?; + println!("Generated {:?} blocks", block); + let _ = tokio::spawn(mine(monerod.clone(), miner_wallet_address.to_string())); Ok(()) } + + // It takes a little while for the wallet to sync with monerod. + pub async fn wait_for_wallet_height(&self, height: u32) -> Result<()> { + let mut retry: u8 = 0; + while self.wallet_rpc_client().block_height().await?.height < height { + if retry >= 30 { + // ~30 seconds + bail!("Wallet could not catch up with monerod after 30 retries.") + } + time::delay_for(Duration::from_millis(WAIT_WALLET_SYNC_MILLIS)).await; + retry += 1; + } + Ok(()) + } +} + +/// Mine a block ever BLOCK_TIME_SECS seconds. +async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> { + loop { + time::delay_for(Duration::from_secs(BLOCK_TIME_SECS)).await; + monerod.generate_blocks(1, &reward_address).await?; + } } // We should be able to use monero-rs for this but it does not include all diff --git a/monero-harness/src/rpc/monerod.rs b/monero-harness/src/rpc/monerod.rs index aa00a62d..91318c40 100644 --- a/monero-harness/src/rpc/monerod.rs +++ b/monero-harness/src/rpc/monerod.rs @@ -4,6 +4,7 @@ use crate::{ }; use anyhow::Result; +use digest_auth::AuthContext; use reqwest::Url; use serde::{Deserialize, Serialize}; use tracing::debug; @@ -36,11 +37,23 @@ impl Client { amount_of_blocks, wallet_address: wallet_address.to_owned(), }; + let url = self.url.clone(); + // // Step 1: Get the auth header + // let res = self.inner.get(url.clone()).send().await?; + // let headers = res.headers(); + // let wwwauth = headers["www-authenticate"].to_str()?; + // + // // Step 2: Given the auth header, sign the digest for the real req. + // let tmp_url = url.clone(); + // let context = AuthContext::new("username", "password", tmp_url.path()); + // let mut prompt = digest_auth::parse(wwwauth)?; + // let answer = prompt.respond(&context)?.to_header_string(); + let request = Request::new("generateblocks", params); let response = self .inner - .post(self.url.clone()) + .post(url) .json(&request) .send() .await? diff --git a/monero-harness/tests/client.rs b/monero-harness/tests/client.rs deleted file mode 100644 index 15e0a19f..00000000 --- a/monero-harness/tests/client.rs +++ /dev/null @@ -1,31 +0,0 @@ -use monero_harness::Monero; -use spectral::prelude::*; -use testcontainers::clients::Cli; - -const ALICE_FUND_AMOUNT: u64 = 1_000_000_000_000; -const BOB_FUND_AMOUNT: u64 = 0; - -#[tokio::test] -async fn init_accounts_for_alice_and_bob() { - let tc = Cli::default(); - let (monero, _container) = Monero::new(&tc).unwrap(); - monero - .init(ALICE_FUND_AMOUNT, BOB_FUND_AMOUNT) - .await - .unwrap(); - - let got_balance_alice = monero - .alice_wallet_rpc_client() - .get_balance(0) - .await - .expect("failed to get alice's balance"); - - let got_balance_bob = monero - .bob_wallet_rpc_client() - .get_balance(0) - .await - .expect("failed to get bob's balance"); - - assert_that!(got_balance_alice).is_equal_to(ALICE_FUND_AMOUNT); - assert_that!(got_balance_bob).is_equal_to(BOB_FUND_AMOUNT); -} diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index 01d4e269..5a0666a3 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -1,21 +1,51 @@ use monero_harness::Monero; use spectral::prelude::*; +use std::time::Duration; use testcontainers::clients::Cli; - -fn init_cli() -> Cli { - Cli::default() -} +use tokio::time; #[tokio::test] -async fn connect_to_monerod() { - let tc = init_cli(); - let (monero, _container) = Monero::new(&tc).unwrap(); - let cli = monero.monerod_rpc_client(); +async fn init_miner_and_mine_to_miner_address() { + let tc = Cli::default(); + let (monerod, _monerod_container) = Monero::new_monerod(&tc).unwrap(); + + let (miner_wallet, _wallet_container) = Monero::new_wallet(&tc, "miner").await.unwrap(); + + let address = miner_wallet + .wallet_rpc_client() + .get_address(0) + .await + .unwrap() + .address; + + monerod.start_miner(&address).await.unwrap(); + + let block_height = monerod + .monerod_rpc_client() + .get_block_count() + .await + .unwrap(); + + miner_wallet + .wait_for_wallet_height(block_height) + .await + .unwrap(); + + let got_miner_balance = miner_wallet + .wallet_rpc_client() + .get_balance(0) + .await + .unwrap(); + assert_that!(got_miner_balance).is_greater_than(0); + + time::delay_for(Duration::from_millis(1010)).await; - let header = cli - .get_block_header_by_height(0) + // after a bit more than 1 sec another block should have been mined + let block_height = monerod + .monerod_rpc_client() + .get_block_count() .await - .expect("failed to get block 0"); + .unwrap(); - assert_that!(header.height).is_equal_to(0); + assert_that(&block_height).is_greater_than(70); } diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index eca88be3..7eaf1d57 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -5,84 +5,85 @@ use testcontainers::clients::Cli; #[tokio::test] async fn wallet_and_accounts() { let tc = Cli::default(); - let (monero, _container) = Monero::new(&tc).unwrap(); - let cli = monero.miner_wallet_rpc_client(); - - println!("creating wallet ..."); - - let _ = cli - .create_wallet("wallet") - .await - .expect("failed to create wallet"); - - let got = cli.get_balance(0).await.expect("failed to get balance"); - let want = 0; - - assert_that!(got).is_equal_to(want); + let (monero, _monerod_container) = Monero::new_monerod(&tc).unwrap(); + let (wallet, _wallet_container) = Monero::new_wallet(&tc, "wallet").unwrap(); + // let cli = monero.miner_wallet_rpc_client(); + // + // println!("creating wallet ..."); + // + // let _ = cli + // .create_wallet("wallet") + // .await + // .expect("failed to create wallet"); + // + // let got = cli.get_balance(0).await.expect("failed to get balance"); + // let want = 0; + // + // assert_that!(got).is_equal_to(want); } #[tokio::test] async fn create_account_and_retrieve_it() { let tc = Cli::default(); - let (monero, _container) = Monero::new(&tc).unwrap(); - let cli = monero.miner_wallet_rpc_client(); - - let label = "Iron Man"; // This is intentionally _not_ Alice or Bob. - - let _ = cli - .create_wallet("wallet") - .await - .expect("failed to create wallet"); - - let _ = cli - .create_account(label) - .await - .expect("failed to create account"); - - let mut found: bool = false; - let accounts = cli - .get_accounts("") // Empty filter. - .await - .expect("failed to get accounts"); - for account in accounts.subaddress_accounts { - if account.label == label { - found = true; - } - } - assert!(found); + let (monero, _container) = Monero::new_monerod(&tc).unwrap(); + // let cli = monero.miner_wallet_rpc_client(); + // + // let label = "Iron Man"; // This is intentionally _not_ Alice or Bob. + // + // let _ = cli + // .create_wallet("wallet") + // .await + // .expect("failed to create wallet"); + // + // let _ = cli + // .create_account(label) + // .await + // .expect("failed to create account"); + // + // let mut found: bool = false; + // let accounts = cli + // .get_accounts("") // Empty filter. + // .await + // .expect("failed to get accounts"); + // for account in accounts.subaddress_accounts { + // if account.label == label { + // found = true; + // } + // } + // assert!(found); } #[tokio::test] async fn transfer_and_check_tx_key() { - let fund_alice = 1_000_000_000_000; + let fund_alice: u64 = 1_000_000_000_000; let fund_bob = 0; let tc = Cli::default(); - let (monero, _container) = Monero::new(&tc).unwrap(); - let _ = monero.init(fund_alice, fund_bob).await; - - let address_bob = monero - .bob_wallet_rpc_client() - .get_address(0) - .await - .expect("failed to get Bob's address") - .address; - - let transfer_amount = 100; - let transfer = monero - .alice_wallet_rpc_client() - .transfer(0, transfer_amount, &address_bob) - .await - .expect("transfer failed"); - - let tx_id = transfer.tx_hash; - let tx_key = transfer.tx_key; - - let cli = monero.miner_wallet_rpc_client(); - let res = cli - .check_tx_key(&tx_id, &tx_key, &address_bob) - .await - .expect("failed to check tx by key"); - - assert_that!(res.received).is_equal_to(transfer_amount); + let (monero, _container) = Monero::new_monerod(&tc).unwrap(); + // let _ = monero.init(fund_alice, fund_bob).await; + // + // let address_bob = monero + // .bob_wallet_rpc_client() + // .get_address(0) + // .await + // .expect("failed to get Bob's address") + // .address; + // + // let transfer_amount = 100; + // let transfer = monero + // .alice_wallet_rpc_client() + // .transfer(0, transfer_amount, &address_bob) + // .await + // .expect("transfer failed"); + // + // let tx_id = transfer.tx_hash; + // let tx_key = transfer.tx_key; + // + // let cli = monero.miner_wallet_rpc_client(); + // let res = cli + // .check_tx_key(&tx_id, &tx_key, &address_bob) + // .await + // .expect("failed to check tx by key"); + // + // assert_that!(res.received).is_equal_to(transfer_amount); } From 738c67a42158af2323988bdc05bbcbe1debc4bf9 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Mon, 2 Nov 2020 14:42:08 +1100 Subject: [PATCH 04/15] Simple fund and send in test --- monero-harness/src/image.rs | 19 +--- monero-harness/src/lib.rs | 13 ++- monero-harness/src/rpc/monerod.rs | 1 - monero-harness/src/rpc/wallet.rs | 24 +++++ monero-harness/tests/wallet.rs | 148 ++++++++++++++---------------- 5 files changed, 110 insertions(+), 95 deletions(-) diff --git a/monero-harness/src/image.rs b/monero-harness/src/image.rs index 8e6b7385..81b2333f 100644 --- a/monero-harness/src/image.rs +++ b/monero-harness/src/image.rs @@ -84,9 +84,7 @@ impl Default for Monero { args: Args::default(), ports: None, entrypoint: Some("".into()), - wait_for_message: - "The daemon is running offline and will not attempt to sync to the Monero network" - .to_string(), + wait_for_message: "core RPC server started ok".to_string(), } } } @@ -167,7 +165,7 @@ pub struct MonerodArgs { pub struct WalletArgs { pub disable_rpc_login: bool, pub confirm_external_bind: bool, - pub wallet_file: String, + pub wallet_dir: String, pub rpc_bind_ip: String, pub rpc_bind_port: u16, pub daemon_address: String, @@ -259,7 +257,7 @@ impl WalletArgs { WalletArgs { disable_rpc_login: true, confirm_external_bind: true, - wallet_file: wallet_name.into(), + wallet_dir: wallet_name.into(), rpc_bind_ip: "0.0.0.0".into(), rpc_bind_port: rpc_port, daemon_address, @@ -279,10 +277,8 @@ impl WalletArgs { args.push("--confirm-external-bind".to_string()) } - if !self.wallet_file.is_empty() { - args.push(format!("--wallet-dir /monero")); - // args.push(format!("--wallet-file {}", self.wallet_file)); - // args.push(format!("--password {}", self.wallet_file)); + if !self.wallet_dir.is_empty() { + args.push(format!("--wallet-dir {}", self.wallet_dir)); } if !self.rpc_bind_ip.is_empty() { @@ -300,11 +296,6 @@ impl WalletArgs { if self.log_level != 0 { args.push(format!("--log-level {}", self.log_level)); } - // args.push(format!("--daemon-login username:password")); - // docker run --rm -d --net host -e DAEMON_HOST=node.xmr.to -e DAEMON_PORT=18081 - // -e RPC_BIND_PORT=18083 -e RPC_USER=user -e RPC_PASSWD=passwd -v - // :/monero xmrto/monero monero-wallet-rpc - // --wallet-file wallet --password-file wallet.passwd args.join(" ") } diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index b15a7a43..a2f5d935 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -36,7 +36,7 @@ use crate::{ }, rpc::{ monerod, - wallet::{self, GetAddress, Transfer}, + wallet::{self, Transfer}, }, }; @@ -77,6 +77,8 @@ impl<'c> Monero { )) } + /// Starts a new wallet container which is attached to + /// MONEROD_DEFAULT_NETWORK and MONEROD_DAEMON_CONTAINER_NAME pub async fn new_wallet( cli: &'c Cli, name: &str, @@ -141,6 +143,15 @@ impl<'c> Monero { } Ok(()) } + + /// Sends amount to address + pub async fn transfer(&self, address: &str, amount: u64) -> Result { + let miner_wallet = self.wallet_rpc_client(); + + let transfer = miner_wallet.transfer(0, amount, address).await?; + + Ok(transfer) + } } /// Mine a block ever BLOCK_TIME_SECS seconds. diff --git a/monero-harness/src/rpc/monerod.rs b/monero-harness/src/rpc/monerod.rs index 91318c40..d3558495 100644 --- a/monero-harness/src/rpc/monerod.rs +++ b/monero-harness/src/rpc/monerod.rs @@ -4,7 +4,6 @@ use crate::{ }; use anyhow::Result; -use digest_auth::AuthContext; use reqwest::Url; use serde::{Deserialize, Serialize}; use tracing::debug; diff --git a/monero-harness/src/rpc/wallet.rs b/monero-harness/src/rpc/wallet.rs index a81702ac..97c2804d 100644 --- a/monero-harness/src/rpc/wallet.rs +++ b/monero-harness/src/rpc/wallet.rs @@ -264,6 +264,24 @@ impl Client { let r: Response = serde_json::from_str(&response)?; Ok(r.result) } + + pub async fn refresh(&self) -> Result { + let request = Request::new("refresh", ""); + + let response = self + .inner + .post(self.url.clone()) + .json(&request) + .send() + .await? + .text() + .await?; + + debug!("refresh RPC response: {}", response); + + let r: Response = serde_json::from_str(&response)?; + Ok(r.result) + } } #[derive(Serialize, Debug, Clone)] @@ -393,3 +411,9 @@ pub struct GenerateFromKeys { pub address: String, pub info: String, } + +#[derive(Clone, Copy, Debug, Deserialize)] +pub struct Refreshed { + pub blocks_fetched: u32, + pub received_money: bool, +} diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index 7eaf1d57..64a69cad 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -3,87 +3,77 @@ use spectral::prelude::*; use testcontainers::clients::Cli; #[tokio::test] -async fn wallet_and_accounts() { - let tc = Cli::default(); - let (monero, _monerod_container) = Monero::new_monerod(&tc).unwrap(); - let (wallet, _wallet_container) = Monero::new_wallet(&tc, "wallet").unwrap(); - // let cli = monero.miner_wallet_rpc_client(); - // - // println!("creating wallet ..."); - // - // let _ = cli - // .create_wallet("wallet") - // .await - // .expect("failed to create wallet"); - // - // let got = cli.get_balance(0).await.expect("failed to get balance"); - // let want = 0; - // - // assert_that!(got).is_equal_to(want); -} - -#[tokio::test] -async fn create_account_and_retrieve_it() { - let tc = Cli::default(); - let (monero, _container) = Monero::new_monerod(&tc).unwrap(); - // let cli = monero.miner_wallet_rpc_client(); - // - // let label = "Iron Man"; // This is intentionally _not_ Alice or Bob. - // - // let _ = cli - // .create_wallet("wallet") - // .await - // .expect("failed to create wallet"); - // - // let _ = cli - // .create_account(label) - // .await - // .expect("failed to create account"); - // - // let mut found: bool = false; - // let accounts = cli - // .get_accounts("") // Empty filter. - // .await - // .expect("failed to get accounts"); - // for account in accounts.subaddress_accounts { - // if account.label == label { - // found = true; - // } - // } - // assert!(found); -} - -#[tokio::test] -async fn transfer_and_check_tx_key() { +async fn fund_transfer_and_check_tx_key() { let fund_alice: u64 = 1_000_000_000_000; let fund_bob = 0; let tc = Cli::default(); - let (monero, _container) = Monero::new_monerod(&tc).unwrap(); - // let _ = monero.init(fund_alice, fund_bob).await; - // - // let address_bob = monero - // .bob_wallet_rpc_client() - // .get_address(0) - // .await - // .expect("failed to get Bob's address") - // .address; - // - // let transfer_amount = 100; - // let transfer = monero - // .alice_wallet_rpc_client() - // .transfer(0, transfer_amount, &address_bob) - // .await - // .expect("transfer failed"); - // - // let tx_id = transfer.tx_hash; - // let tx_key = transfer.tx_key; - // - // let cli = monero.miner_wallet_rpc_client(); - // let res = cli - // .check_tx_key(&tx_id, &tx_key, &address_bob) - // .await - // .expect("failed to check tx by key"); - // - // assert_that!(res.received).is_equal_to(transfer_amount); + let (monerod, _monerod_container) = Monero::new_monerod(&tc).unwrap(); + + let (miner_wallet, _wallet_container) = Monero::new_wallet(&tc, "miner").await.unwrap(); + let (alice_wallet, _alice_wallet_container) = Monero::new_wallet(&tc, "alice").await.unwrap(); + let (bob_wallet, _bob_wallet_container) = Monero::new_wallet(&tc, "bob").await.unwrap(); + + let address = miner_wallet + .wallet_rpc_client() + .get_address(0) + .await + .unwrap() + .address; + + monerod.start_miner(&address).await.unwrap(); + + let block_height = monerod + .monerod_rpc_client() + .get_block_count() + .await + .unwrap(); + + miner_wallet + .wait_for_wallet_height(block_height) + .await + .unwrap(); + + let alice_address = alice_wallet + .wallet_rpc_client() + .get_address(0) + .await + .unwrap() + .address; + + let transfer = miner_wallet + .transfer(&alice_address, fund_alice) + .await + .unwrap(); + + monerod + .monerod_rpc_client() + .generate_blocks(10, &address) + .await + .unwrap(); + + let refreshed = alice_wallet.wallet_rpc_client().refresh().await.unwrap(); + assert_that(&refreshed.received_money).is_true(); + + let got_alice_balance = alice_wallet + .wallet_rpc_client() + .get_balance(0) + .await + .unwrap(); + + let got_bob_balance = bob_wallet.wallet_rpc_client().get_balance(0).await.unwrap(); + + assert_that(&got_alice_balance).is_equal_to(fund_alice); + assert_that(&got_bob_balance).is_equal_to(fund_bob); + + let tx_id = transfer.tx_hash; + let tx_key = transfer.tx_key; + + let res = alice_wallet + .wallet_rpc_client() + .check_tx_key(&tx_id, &tx_key, &alice_address) + .await + .expect("failed to check tx by key"); + + assert_that!(res.received).is_equal_to(fund_alice); } From 3a348003110c6eff33958cb7f821ed98c5b2f7a0 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Mon, 2 Nov 2020 16:00:35 +1100 Subject: [PATCH 05/15] Refactor into monero helper struct --- monero-harness/src/image.rs | 7 +- monero-harness/src/lib.rs | 175 ++++++++++++++++++++++++++------ monero-harness/tests/monerod.rs | 37 +------ monero-harness/tests/wallet.rs | 64 +++--------- 4 files changed, 168 insertions(+), 115 deletions(-) diff --git a/monero-harness/src/image.rs b/monero-harness/src/image.rs index 81b2333f..4d699fc9 100644 --- a/monero-harness/src/image.rs +++ b/monero-harness/src/image.rs @@ -104,8 +104,8 @@ impl Monero { self } - pub fn wallet(name: &str) -> Self { - let wallet = WalletArgs::new(name, WALLET_RPC_PORT); + pub fn wallet(name: &str, daemon_address: String) -> Self { + let wallet = WalletArgs::new(name, daemon_address, WALLET_RPC_PORT); let default = Monero::default(); Self { args: Args { @@ -252,8 +252,7 @@ impl MonerodArgs { } impl WalletArgs { - pub fn new(wallet_name: &str, rpc_port: u16) -> Self { - let daemon_address = format!("{}:{}", MONEROD_DAEMON_CONTAINER_NAME, MONEROD_RPC_PORT); + pub fn new(wallet_name: &str, daemon_address: String, rpc_port: u16) -> Self { WalletArgs { disable_rpc_login: true, confirm_external_bind: true, diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index a2f5d935..d9e5612b 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -36,7 +36,7 @@ use crate::{ }, rpc::{ monerod, - wallet::{self, Transfer}, + wallet::{self, GetAddress, Transfer}, }, }; @@ -48,13 +48,117 @@ const WAIT_WALLET_SYNC_MILLIS: u64 = 1000; #[derive(Clone, Debug)] pub struct Monero { + monerod: Monerod, + wallets: Vec, + miner_address: String, +} +impl<'c> Monero { + /// Starts a new regtest monero container setup consisting out of 1 monerod + /// node and n wallets. The containers will be prefixed with + /// `container_prefix` if provided. There will be 1 miner wallet started + /// automatically. Default monerod container name will be: `monerod` + /// Default miner wallet container name will be: `miner` + /// Default network `monero` + pub async fn new( + cli: &'c Cli, + container_prefix: Option, + network_prefix: Option, + additional_wallets: Vec, + ) -> Result<(Self, Vec>)> { + let monerod_name = format!( + "{}{}", + container_prefix.unwrap_or_else(|| "".to_string()), + MONEROD_DAEMON_CONTAINER_NAME + ); + let network = format!( + "{}{}", + network_prefix.unwrap_or_else(|| "".to_string()), + MONEROD_DEFAULT_NETWORK + ); + + tracing::info!("Starting monerod..."); + let (monerod, monerod_container) = Monerod::new(cli, monerod_name, network)?; + let mut containers = vec![monerod_container]; + let mut wallets = vec![]; + + tracing::info!("Starting miner..."); + let (miner_wallet, miner_container) = MoneroWalletRpc::new(cli, "miner", &monerod).await?; + let miner_address = miner_wallet.address().await?.address; + + monerod.start_miner(&miner_address).await?; + + tracing::info!("Waiting for miner wallet to catch up..."); + let block_height = monerod.inner().get_block_count().await?; + miner_wallet + .wait_for_wallet_height(block_height) + .await + .unwrap(); + + wallets.push(miner_wallet); + containers.push(miner_container); + for wallet in additional_wallets.iter() { + tracing::info!("Starting wallet: {}...", wallet); + let (wallet, container) = MoneroWalletRpc::new(cli, wallet, &monerod).await?; + wallets.push(wallet); + containers.push(container); + } + + Ok(( + Self { + monerod, + wallets, + miner_address, + }, + containers, + )) + } + + pub fn monerod(&self) -> &Monerod { + &self.monerod + } + + pub fn wallet(&self, name: &str) -> Result<&MoneroWalletRpc> { + let wallet = self + .wallets + .iter() + .find(|wallet| wallet.name.eq(name)) + .ok_or_else(|| anyhow!("Could not find wallet container."))?; + + Ok(wallet) + } + + pub async fn fund(&self, address: &str, amount: u64) -> Result { + let transfer = self.wallet("miner")?.transfer(address, amount).await?; + + self.monerod + .inner() + .generate_blocks(10, &self.miner_address) + .await?; + Ok(transfer) + } +} + +#[derive(Clone, Debug)] +pub struct Monerod { rpc_port: u16, name: String, + network: String, } -impl<'c> Monero { +#[derive(Clone, Debug)] +pub struct MoneroWalletRpc { + rpc_port: u16, + name: String, + network: String, +} + +impl<'c> Monerod { /// Starts a new regtest monero container. - pub fn new_monerod(cli: &'c Cli) -> Result<(Self, Container<'c, Cli, image::Monero>)> { + fn new( + cli: &'c Cli, + name: String, + network: String, + ) -> Result<(Self, Container<'c, Cli, image::Monero>)> { let monerod_rpc_port: u16 = port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; @@ -62,38 +166,58 @@ impl<'c> Monero { local: monerod_rpc_port, internal: MONEROD_RPC_PORT, }); - let run_args = RunArgs::default() - .with_name(MONEROD_DAEMON_CONTAINER_NAME) - .with_network(MONEROD_DEFAULT_NETWORK); + .with_name(name.clone()) + .with_network(network.clone()); let docker = cli.run_with_args(image, run_args); Ok(( Self { rpc_port: monerod_rpc_port, - name: "monerod".to_string(), + name, + network, }, docker, )) } + pub fn inner(&self) -> monerod::Client { + monerod::Client::localhost(self.rpc_port) + } + + /// Spawns a task to mine blocks in a regular interval to the provided + /// address + pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> { + let monerod = self.inner(); + // generate the first 70 as bulk + let block = monerod.generate_blocks(70, &miner_wallet_address).await?; + println!("Generated {:?} blocks", block); + let _ = tokio::spawn(mine(monerod.clone(), miner_wallet_address.to_string())); + Ok(()) + } +} + +impl<'c> MoneroWalletRpc { /// Starts a new wallet container which is attached to /// MONEROD_DEFAULT_NETWORK and MONEROD_DAEMON_CONTAINER_NAME - pub async fn new_wallet( + async fn new( cli: &'c Cli, name: &str, + monerod: &Monerod, ) -> Result<(Self, Container<'c, Cli, image::Monero>)> { let wallet_rpc_port: u16 = port_check::free_local_port().ok_or_else(|| anyhow!("Could not retrieve free port"))?; - let image = image::Monero::wallet(&name).with_mapped_port(Port { + let daemon_address = format!("{}:{}", monerod.name, MONEROD_RPC_PORT); + let image = image::Monero::wallet(&name, daemon_address).with_mapped_port(Port { local: wallet_rpc_port, internal: WALLET_RPC_PORT, }); + let network = monerod.network.clone(); let run_args = RunArgs::default() .with_name(name) - .with_network(MONEROD_DEFAULT_NETWORK); + .with_network(network.clone()); let docker = cli.run_with_args(image, run_args); // create new wallet @@ -106,34 +230,20 @@ impl<'c> Monero { Self { rpc_port: wallet_rpc_port, name: name.to_string(), + network, }, docker, )) } - pub fn monerod_rpc_client(&self) -> monerod::Client { - monerod::Client::localhost(self.rpc_port) - } - - pub fn wallet_rpc_client(&self) -> wallet::Client { + pub fn inner(&self) -> wallet::Client { wallet::Client::localhost(self.rpc_port) } - /// Spawns a task to mine blocks in a regular interval to the provided - /// address - pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> { - let monerod = self.monerod_rpc_client(); - // generate the first 70 as bulk - let block = monerod.generate_blocks(70, &miner_wallet_address).await?; - println!("Generated {:?} blocks", block); - let _ = tokio::spawn(mine(monerod.clone(), miner_wallet_address.to_string())); - Ok(()) - } - // It takes a little while for the wallet to sync with monerod. pub async fn wait_for_wallet_height(&self, height: u32) -> Result<()> { let mut retry: u8 = 0; - while self.wallet_rpc_client().block_height().await?.height < height { + while self.inner().block_height().await?.height < height { if retry >= 30 { // ~30 seconds bail!("Wallet could not catch up with monerod after 30 retries.") @@ -146,14 +256,21 @@ impl<'c> Monero { /// Sends amount to address pub async fn transfer(&self, address: &str, amount: u64) -> Result { - let miner_wallet = self.wallet_rpc_client(); + let miner_wallet = self.inner(); let transfer = miner_wallet.transfer(0, amount, address).await?; Ok(transfer) } -} + pub async fn address(&self) -> Result { + self.inner().get_address(0).await + } + + pub async fn balance(&self) -> Result { + self.inner().get_balance(0).await + } +} /// Mine a block ever BLOCK_TIME_SECS seconds. async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> { loop { diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index 5a0666a3..53a865e7 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -7,45 +7,18 @@ use tokio::time; #[tokio::test] async fn init_miner_and_mine_to_miner_address() { let tc = Cli::default(); - let (monerod, _monerod_container) = Monero::new_monerod(&tc).unwrap(); + let (monero, _monerod_container) = Monero::new(&tc, None, None, vec![]).await.unwrap(); - let (miner_wallet, _wallet_container) = Monero::new_wallet(&tc, "miner").await.unwrap(); + let monerod = monero.monerod(); + let miner_wallet = monero.wallet("miner").unwrap(); - let address = miner_wallet - .wallet_rpc_client() - .get_address(0) - .await - .unwrap() - .address; - - monerod.start_miner(&address).await.unwrap(); - - let block_height = monerod - .monerod_rpc_client() - .get_block_count() - .await - .unwrap(); - - miner_wallet - .wait_for_wallet_height(block_height) - .await - .unwrap(); - - let got_miner_balance = miner_wallet - .wallet_rpc_client() - .get_balance(0) - .await - .unwrap(); + let got_miner_balance = miner_wallet.balance().await.unwrap(); assert_that!(got_miner_balance).is_greater_than(0); time::delay_for(Duration::from_millis(1010)).await; // after a bit more than 1 sec another block should have been mined - let block_height = monerod - .monerod_rpc_client() - .get_block_count() - .await - .unwrap(); + let block_height = monerod.inner().get_block_count().await.unwrap(); assert_that(&block_height).is_greater_than(70); } diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index 64a69cad..a780f791 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -8,60 +8,24 @@ async fn fund_transfer_and_check_tx_key() { let fund_bob = 0; let tc = Cli::default(); - let (monerod, _monerod_container) = Monero::new_monerod(&tc).unwrap(); + let (monero, _containers) = Monero::new(&tc, Some("test".to_string()), None, vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); + let alice_wallet = monero.wallet("alice").unwrap(); + let bob_wallet = monero.wallet("bob").unwrap(); - let (miner_wallet, _wallet_container) = Monero::new_wallet(&tc, "miner").await.unwrap(); - let (alice_wallet, _alice_wallet_container) = Monero::new_wallet(&tc, "alice").await.unwrap(); - let (bob_wallet, _bob_wallet_container) = Monero::new_wallet(&tc, "bob").await.unwrap(); + let alice_address = alice_wallet.address().await.unwrap().address; - let address = miner_wallet - .wallet_rpc_client() - .get_address(0) - .await - .unwrap() - .address; - - monerod.start_miner(&address).await.unwrap(); - - let block_height = monerod - .monerod_rpc_client() - .get_block_count() - .await - .unwrap(); - - miner_wallet - .wait_for_wallet_height(block_height) - .await - .unwrap(); - - let alice_address = alice_wallet - .wallet_rpc_client() - .get_address(0) - .await - .unwrap() - .address; - - let transfer = miner_wallet - .transfer(&alice_address, fund_alice) - .await - .unwrap(); + let transfer = monero.fund(&alice_address, fund_alice).await.unwrap(); - monerod - .monerod_rpc_client() - .generate_blocks(10, &address) - .await - .unwrap(); - - let refreshed = alice_wallet.wallet_rpc_client().refresh().await.unwrap(); + let refreshed = alice_wallet.inner().refresh().await.unwrap(); assert_that(&refreshed.received_money).is_true(); - let got_alice_balance = alice_wallet - .wallet_rpc_client() - .get_balance(0) - .await - .unwrap(); - - let got_bob_balance = bob_wallet.wallet_rpc_client().get_balance(0).await.unwrap(); + let got_alice_balance = alice_wallet.balance().await.unwrap(); + let got_bob_balance = bob_wallet.balance().await.unwrap(); assert_that(&got_alice_balance).is_equal_to(fund_alice); assert_that(&got_bob_balance).is_equal_to(fund_bob); @@ -70,7 +34,7 @@ async fn fund_transfer_and_check_tx_key() { let tx_key = transfer.tx_key; let res = alice_wallet - .wallet_rpc_client() + .inner() .check_tx_key(&tx_id, &tx_key, &alice_address) .await .expect("failed to check tx by key"); From 3cc32002b0284e255c871cac0e01eb02d8abbd0c Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Mon, 2 Nov 2020 18:58:52 +1100 Subject: [PATCH 06/15] Refactor out some helper functions to generate blocks after funding --- monero-harness/src/lib.rs | 63 ++++++++++++++----------------- monero-harness/src/rpc/monerod.rs | 24 ++++++++++-- monero-harness/tests/wallet.rs | 30 ++++++++++----- 3 files changed, 69 insertions(+), 48 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index d9e5612b..699feb45 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -25,7 +25,6 @@ pub mod image; pub mod rpc; use anyhow::{anyhow, bail, Result}; -use serde::Deserialize; use std::time::Duration; use testcontainers::{clients::Cli, core::Port, Container, Docker, RunArgs}; use tokio::time; @@ -51,6 +50,7 @@ pub struct Monero { monerod: Monerod, wallets: Vec, miner_address: String, + container_prefix: String, } impl<'c> Monero { /// Starts a new regtest monero container setup consisting out of 1 monerod @@ -58,18 +58,16 @@ impl<'c> Monero { /// `container_prefix` if provided. There will be 1 miner wallet started /// automatically. Default monerod container name will be: `monerod` /// Default miner wallet container name will be: `miner` - /// Default network `monero` + /// Default network will be: `monero` pub async fn new( cli: &'c Cli, container_prefix: Option, network_prefix: Option, additional_wallets: Vec, ) -> Result<(Self, Vec>)> { - let monerod_name = format!( - "{}{}", - container_prefix.unwrap_or_else(|| "".to_string()), - MONEROD_DAEMON_CONTAINER_NAME - ); + let container_prefix = container_prefix.unwrap_or_else(|| "".to_string()); + + let monerod_name = format!("{}{}", container_prefix, MONEROD_DAEMON_CONTAINER_NAME); let network = format!( "{}{}", network_prefix.unwrap_or_else(|| "".to_string()), @@ -82,7 +80,8 @@ impl<'c> Monero { let mut wallets = vec![]; tracing::info!("Starting miner..."); - let (miner_wallet, miner_container) = MoneroWalletRpc::new(cli, "miner", &monerod).await?; + let miner = format!("{}{}", container_prefix, "miner"); + let (miner_wallet, miner_container) = MoneroWalletRpc::new(cli, &miner, &monerod).await?; let miner_address = miner_wallet.address().await?.address; monerod.start_miner(&miner_address).await?; @@ -98,7 +97,8 @@ impl<'c> Monero { containers.push(miner_container); for wallet in additional_wallets.iter() { tracing::info!("Starting wallet: {}...", wallet); - let (wallet, container) = MoneroWalletRpc::new(cli, wallet, &monerod).await?; + let wallet = format!("{}{}", container_prefix, wallet); + let (wallet, container) = MoneroWalletRpc::new(cli, &wallet, &monerod).await?; wallets.push(wallet); containers.push(container); } @@ -108,6 +108,7 @@ impl<'c> Monero { monerod, wallets, miner_address, + container_prefix, }, containers, )) @@ -118,22 +119,36 @@ impl<'c> Monero { } pub fn wallet(&self, name: &str) -> Result<&MoneroWalletRpc> { + let name = format!("{}{}", self.container_prefix, name); let wallet = self .wallets .iter() - .find(|wallet| wallet.name.eq(name)) + .find(|wallet| wallet.name.eq(&name)) .ok_or_else(|| anyhow!("Could not find wallet container."))?; Ok(wallet) } pub async fn fund(&self, address: &str, amount: u64) -> Result { - let transfer = self.wallet("miner")?.transfer(address, amount).await?; + self.transfer("miner", address, amount).await + } + + pub async fn transfer_from_alice(&self, address: &str, amount: u64) -> Result { + self.transfer("alice", address, amount).await + } + pub async fn transfer_from_bob(&self, address: &str, amount: u64) -> Result { + self.transfer("bob", address, amount).await + } + + async fn transfer(&self, from_wallet: &str, address: &str, amount: u64) -> Result { + let from = self.wallet(from_wallet)?; + let transfer = from.transfer(address, amount).await?; self.monerod .inner() .generate_blocks(10, &self.miner_address) .await?; + from.inner().refresh().await?; Ok(transfer) } } @@ -256,10 +271,8 @@ impl<'c> MoneroWalletRpc { /// Sends amount to address pub async fn transfer(&self, address: &str, amount: u64) -> Result { - let miner_wallet = self.inner(); - - let transfer = miner_wallet.transfer(0, amount, address).await?; - + let transfer = self.inner().transfer(0, amount, address).await?; + self.inner().refresh().await?; Ok(transfer) } @@ -268,6 +281,7 @@ impl<'c> MoneroWalletRpc { } pub async fn balance(&self) -> Result { + self.inner().refresh().await?; self.inner().get_balance(0).await } } @@ -278,22 +292,3 @@ async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> { monerod.generate_blocks(1, &reward_address).await?; } } - -// We should be able to use monero-rs for this but it does not include all -// the fields. -#[derive(Clone, Debug, Deserialize)] -pub struct BlockHeader { - pub block_size: u32, - pub depth: u32, - pub difficulty: u32, - pub hash: String, - pub height: u32, - pub major_version: u32, - pub minor_version: u32, - pub nonce: u32, - pub num_txes: u32, - pub orphan_status: bool, - pub prev_hash: String, - pub reward: u64, - pub timestamp: u32, -} diff --git a/monero-harness/src/rpc/monerod.rs b/monero-harness/src/rpc/monerod.rs index d3558495..e27f2556 100644 --- a/monero-harness/src/rpc/monerod.rs +++ b/monero-harness/src/rpc/monerod.rs @@ -1,7 +1,4 @@ -use crate::{ - rpc::{Request, Response}, - BlockHeader, -}; +use crate::rpc::{Request, Response}; use anyhow::Result; use reqwest::Url; @@ -137,3 +134,22 @@ struct BlockCount { count: u32, status: String, } + +// We should be able to use monero-rs for this but it does not include all +// the fields. +#[derive(Clone, Debug, Deserialize)] +pub struct BlockHeader { + pub block_size: u32, + pub depth: u32, + pub difficulty: u32, + pub hash: String, + pub height: u32, + pub major_version: u32, + pub minor_version: u32, + pub nonce: u32, + pub num_txes: u32, + pub orphan_status: bool, + pub prev_hash: String, + pub reward: u64, + pub timestamp: u32, +} diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index a780f791..7cd6c241 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -5,10 +5,10 @@ use testcontainers::clients::Cli; #[tokio::test] async fn fund_transfer_and_check_tx_key() { let fund_alice: u64 = 1_000_000_000_000; - let fund_bob = 0; + let fund_bob = 5_000_000_000; let tc = Cli::default(); - let (monero, _containers) = Monero::new(&tc, Some("test".to_string()), None, vec![ + let (monero, _containers) = Monero::new(&tc, Some("test_".to_string()), None, vec![ "alice".to_string(), "bob".to_string(), ]) @@ -18,26 +18,36 @@ async fn fund_transfer_and_check_tx_key() { let bob_wallet = monero.wallet("bob").unwrap(); let alice_address = alice_wallet.address().await.unwrap().address; + let bob_address = bob_wallet.address().await.unwrap().address; - let transfer = monero.fund(&alice_address, fund_alice).await.unwrap(); + // fund alice + monero.fund(&alice_address, fund_alice).await.unwrap(); + // check alice balance let refreshed = alice_wallet.inner().refresh().await.unwrap(); assert_that(&refreshed.received_money).is_true(); - let got_alice_balance = alice_wallet.balance().await.unwrap(); - let got_bob_balance = bob_wallet.balance().await.unwrap(); - assert_that(&got_alice_balance).is_equal_to(fund_alice); + + // transfer from alice to bob + let transfer = monero + .transfer_from_alice(&bob_address, fund_bob) + .await + .unwrap(); + + let refreshed = bob_wallet.inner().refresh().await.unwrap(); + assert_that(&refreshed.received_money).is_true(); + let got_bob_balance = bob_wallet.balance().await.unwrap(); assert_that(&got_bob_balance).is_equal_to(fund_bob); + // check if tx was actually seen let tx_id = transfer.tx_hash; let tx_key = transfer.tx_key; - - let res = alice_wallet + let res = bob_wallet .inner() - .check_tx_key(&tx_id, &tx_key, &alice_address) + .check_tx_key(&tx_id, &tx_key, &bob_address) .await .expect("failed to check tx by key"); - assert_that!(res.received).is_equal_to(fund_alice); + assert_that!(res.received).is_equal_to(fund_bob); } From 2d064f305f7d4d72131d6caa43bc1af4ae3ab1d9 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Mon, 2 Nov 2020 19:01:28 +1100 Subject: [PATCH 07/15] Re-enable other builds --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 12da321f..9d880136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["monero-harness"] +members = ["monero-harness", "xmr-btc", "swap"] From 0b9e8c145e15414f22cf9401510e37a99d61f59c Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Mon, 2 Nov 2020 21:12:38 +1100 Subject: [PATCH 08/15] Update xmr-btc lib to use new monero-harness --- monero-harness/src/lib.rs | 68 ++++++++++++++++++++++++---------- monero-harness/tests/wallet.rs | 21 +++++------ swap/Cargo.toml | 2 +- xmr-btc/Cargo.toml | 4 +- xmr-btc/tests/e2e.rs | 29 ++++++++++++--- xmr-btc/tests/harness/mod.rs | 4 +- xmr-btc/tests/on_chain.rs | 31 +++++++++++++--- 7 files changed, 113 insertions(+), 46 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index 699feb45..d1e45884 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -35,7 +35,7 @@ use crate::{ }, rpc::{ monerod, - wallet::{self, GetAddress, Transfer}, + wallet::{self, GetAddress, Refreshed, Transfer}, }, }; @@ -49,7 +49,6 @@ const WAIT_WALLET_SYNC_MILLIS: u64 = 1000; pub struct Monero { monerod: Monerod, wallets: Vec, - miner_address: String, container_prefix: String, } impl<'c> Monero { @@ -79,19 +78,9 @@ impl<'c> Monero { let mut containers = vec![monerod_container]; let mut wallets = vec![]; - tracing::info!("Starting miner..."); + tracing::info!("Starting miner wallet..."); let miner = format!("{}{}", container_prefix, "miner"); let (miner_wallet, miner_container) = MoneroWalletRpc::new(cli, &miner, &monerod).await?; - let miner_address = miner_wallet.address().await?.address; - - monerod.start_miner(&miner_address).await?; - - tracing::info!("Waiting for miner wallet to catch up..."); - let block_height = monerod.inner().get_block_count().await?; - miner_wallet - .wait_for_wallet_height(block_height) - .await - .unwrap(); wallets.push(miner_wallet); containers.push(miner_container); @@ -107,7 +96,6 @@ impl<'c> Monero { Self { monerod, wallets, - miner_address, container_prefix, }, containers, @@ -129,6 +117,46 @@ impl<'c> Monero { Ok(wallet) } + pub async fn init(&self, alice_amount: u64, bob_amount: u64) -> Result<()> { + let miner_wallet = self.wallet("miner")?; + let miner_address = miner_wallet.address().await?.address; + + let alice_wallet = self.wallet("alice")?; + let alice_address = alice_wallet.address().await?.address; + + let bob_wallet = self.wallet("bob")?; + let bob_address = bob_wallet.address().await?.address; + + // generate the first 70 as bulk + let monerod = &self.monerod; + let block = monerod.inner().generate_blocks(70, &miner_address).await?; + tracing::info!("Generated {:?} blocks", block); + miner_wallet.refresh().await?; + + if alice_amount > 0 { + miner_wallet.transfer(&alice_address, alice_amount).await?; + tracing::info!("Funded alice wallet with {}", alice_amount); + } + if bob_amount > 0 { + miner_wallet.transfer(&bob_address, bob_amount).await?; + tracing::info!("Funded bob wallet with {}", bob_amount); + } + + monerod.inner().generate_blocks(10, &miner_address).await?; + alice_wallet.refresh().await?; + bob_wallet.refresh().await?; + monerod.start_miner(&miner_address).await?; + + tracing::info!("Waiting for miner wallet to catch up..."); + let block_height = monerod.inner().get_block_count().await?; + miner_wallet + .wait_for_wallet_height(block_height) + .await + .unwrap(); + + Ok(()) + } + pub async fn fund(&self, address: &str, amount: u64) -> Result { self.transfer("miner", address, amount).await } @@ -144,9 +172,10 @@ impl<'c> Monero { async fn transfer(&self, from_wallet: &str, address: &str, amount: u64) -> Result { let from = self.wallet(from_wallet)?; let transfer = from.transfer(address, amount).await?; + let miner_address = self.wallet("miner")?.address().await?.address; self.monerod .inner() - .generate_blocks(10, &self.miner_address) + .generate_blocks(10, &miner_address) .await?; from.inner().refresh().await?; Ok(transfer) @@ -204,10 +233,7 @@ impl<'c> Monerod { /// address pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> { let monerod = self.inner(); - // generate the first 70 as bulk - let block = monerod.generate_blocks(70, &miner_wallet_address).await?; - println!("Generated {:?} blocks", block); - let _ = tokio::spawn(mine(monerod.clone(), miner_wallet_address.to_string())); + let _ = tokio::spawn(mine(monerod, miner_wallet_address.to_string())); Ok(()) } } @@ -284,6 +310,10 @@ impl<'c> MoneroWalletRpc { self.inner().refresh().await?; self.inner().get_balance(0).await } + + pub async fn refresh(&self) -> Result { + self.inner().refresh().await + } } /// Mine a block ever BLOCK_TIME_SECS seconds. async fn mine(monerod: monerod::Client, reward_address: String) -> Result<()> { diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index 7cd6c241..fc29ae5e 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -5,7 +5,8 @@ use testcontainers::clients::Cli; #[tokio::test] async fn fund_transfer_and_check_tx_key() { let fund_alice: u64 = 1_000_000_000_000; - let fund_bob = 5_000_000_000; + let fund_bob = 0; + let send_to_bob = 5_000_000_000; let tc = Cli::default(); let (monero, _containers) = Monero::new(&tc, Some("test_".to_string()), None, vec![ @@ -17,28 +18,24 @@ async fn fund_transfer_and_check_tx_key() { let alice_wallet = monero.wallet("alice").unwrap(); let bob_wallet = monero.wallet("bob").unwrap(); - let alice_address = alice_wallet.address().await.unwrap().address; - let bob_address = bob_wallet.address().await.unwrap().address; - // fund alice - monero.fund(&alice_address, fund_alice).await.unwrap(); + monero.init(fund_alice, fund_bob).await.unwrap(); // check alice balance - let refreshed = alice_wallet.inner().refresh().await.unwrap(); - assert_that(&refreshed.received_money).is_true(); + alice_wallet.inner().refresh().await.unwrap(); let got_alice_balance = alice_wallet.balance().await.unwrap(); assert_that(&got_alice_balance).is_equal_to(fund_alice); // transfer from alice to bob + let bob_address = bob_wallet.address().await.unwrap().address; let transfer = monero - .transfer_from_alice(&bob_address, fund_bob) + .transfer_from_alice(&bob_address, send_to_bob) .await .unwrap(); - let refreshed = bob_wallet.inner().refresh().await.unwrap(); - assert_that(&refreshed.received_money).is_true(); + bob_wallet.inner().refresh().await.unwrap(); let got_bob_balance = bob_wallet.balance().await.unwrap(); - assert_that(&got_bob_balance).is_equal_to(fund_bob); + assert_that(&got_bob_balance).is_equal_to(send_to_bob); // check if tx was actually seen let tx_id = transfer.tx_hash; @@ -49,5 +46,5 @@ async fn fund_transfer_and_check_tx_key() { .await .expect("failed to check tx by key"); - assert_that!(res.received).is_equal_to(fund_bob); + assert_that!(res.received).is_equal_to(send_to_bob); } diff --git a/swap/Cargo.toml b/swap/Cargo.toml index a92615f4..e89df6a3 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -12,7 +12,7 @@ atty = "0.2" backoff = { version = "0.2", features = ["tokio"] } base64 = "0.12" bitcoin = { version = "0.23", features = ["rand", "use-serde"] } # TODO: Upgrade other crates in this repo to use this version. -bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs", rev = "f1bbe6a4540d0741f1f4f22577cfeeadbfd7aaaf" } +bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs", rev = "3be644cd9512c157d3337a189298b8257ed54d04" } derivative = "2" futures = { version = "0.3", default-features = false } genawaiter = "0.99.1" diff --git a/xmr-btc/Cargo.toml b/xmr-btc/Cargo.toml index 7d13407d..40373456 100644 --- a/xmr-btc/Cargo.toml +++ b/xmr-btc/Cargo.toml @@ -28,12 +28,12 @@ tracing = "0.1" [dev-dependencies] backoff = { version = "0.2", features = ["tokio"] } base64 = "0.12" -bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs", rev = "f1bbe6a4540d0741f1f4f22577cfeeadbfd7aaaf" } +bitcoin-harness = { git = "https://github.com/coblox/bitcoin-harness-rs", rev = "3be644cd9512c157d3337a189298b8257ed54d04" } futures = "0.3" monero-harness = { path = "../monero-harness" } reqwest = { version = "0.10", default-features = false } serde_cbor = "0.11" tempfile = "3" -testcontainers = "0.10" +testcontainers = "0.11" tracing = "0.1" tracing-subscriber = "0.2" diff --git a/xmr-btc/tests/e2e.rs b/xmr-btc/tests/e2e.rs index 72795fb7..9822bc48 100644 --- a/xmr-btc/tests/e2e.rs +++ b/xmr-btc/tests/e2e.rs @@ -32,7 +32,13 @@ mod tests { .set_default(); let cli = Cli::default(); - let (monero, _container) = Monero::new(&cli).unwrap(); + let (monero, _container) = + Monero::new(&cli, Some("hp".to_string()), Some("hp".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let ( @@ -75,7 +81,7 @@ mod tests { let alice_final_xmr_balance = alice_node.monero_wallet.get_balance().await.unwrap(); - monero.wait_for_bob_wallet_block_height().await.unwrap(); + monero.wallet("bob").unwrap().refresh().await.unwrap(); let bob_final_xmr_balance = bob_node.monero_wallet.get_balance().await.unwrap(); @@ -106,7 +112,13 @@ mod tests { .set_default(); let cli = Cli::default(); - let (monero, _container) = Monero::new(&cli).unwrap(); + let (monero, _container) = + Monero::new(&cli, Some("br".to_string()), Some("br".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let ( @@ -158,7 +170,7 @@ mod tests { .await .unwrap(); - monero.wait_for_alice_wallet_block_height().await.unwrap(); + monero.wallet("alice").unwrap().refresh().await.unwrap(); let alice_final_xmr_balance = alice_node.monero_wallet.get_balance().await.unwrap(); let bob_final_xmr_balance = bob_node.monero_wallet.get_balance().await.unwrap(); @@ -182,7 +194,14 @@ mod tests { .set_default(); let cli = Cli::default(); - let (monero, _container) = Monero::new(&cli).unwrap(); + let (monero, _containers) = + Monero::new(&cli, Some("ap".to_string()), Some("ap".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); + let bitcoind = init_bitcoind(&cli).await; let ( diff --git a/xmr-btc/tests/harness/mod.rs b/xmr-btc/tests/harness/mod.rs index 3d189243..de57d34e 100644 --- a/xmr-btc/tests/harness/mod.rs +++ b/xmr-btc/tests/harness/mod.rs @@ -132,8 +132,8 @@ pub async fn init_test( let fund_bob = 0; monero.init(fund_alice, fund_bob).await.unwrap(); - let alice_monero_wallet = wallet::monero::Wallet(monero.alice_wallet_rpc_client()); - let bob_monero_wallet = wallet::monero::Wallet(monero.bob_wallet_rpc_client()); + let alice_monero_wallet = wallet::monero::Wallet(monero.wallet("alice").unwrap().inner()); + let bob_monero_wallet = wallet::monero::Wallet(monero.wallet("bob").unwrap().inner()); let alice_btc_wallet = wallet::bitcoin::Wallet::new("alice", &bitcoind.node_url) .await diff --git a/xmr-btc/tests/on_chain.rs b/xmr-btc/tests/on_chain.rs index e61db076..ae95a1f2 100644 --- a/xmr-btc/tests/on_chain.rs +++ b/xmr-btc/tests/on_chain.rs @@ -238,7 +238,14 @@ async fn swap_as_bob( #[tokio::test] async fn on_chain_happy_path() { let cli = Cli::default(); - let (monero, _container) = Monero::new(&cli).unwrap(); + let (monero, _container) = Monero::new( + &cli, + Some("ochp".to_string()), + Some("ochp".to_string()), + vec!["alice".to_string(), "bob".to_string()], + ) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let (alice_state0, bob_state0, mut alice_node, mut bob_node, initial_balances, swap_amounts) = @@ -304,7 +311,7 @@ async fn on_chain_happy_path() { let alice_final_xmr_balance = alice_monero_wallet.get_balance().await.unwrap(); - monero.wait_for_bob_wallet_block_height().await.unwrap(); + monero.wallet("bob").unwrap().refresh().await.unwrap(); let bob_final_xmr_balance = bob_monero_wallet.get_balance().await.unwrap(); assert_eq!( @@ -329,7 +336,14 @@ async fn on_chain_happy_path() { #[tokio::test] async fn on_chain_both_refund_if_alice_never_redeems() { let cli = Cli::default(); - let (monero, _container) = Monero::new(&cli).unwrap(); + let (monero, _container) = Monero::new( + &cli, + Some("ocbr".to_string()), + Some("ocbr".to_string()), + vec!["alice".to_string(), "bob".to_string()], + ) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let (alice_state0, bob_state0, mut alice_node, mut bob_node, initial_balances, swap_amounts) = @@ -396,7 +410,7 @@ async fn on_chain_both_refund_if_alice_never_redeems() { .await .unwrap(); - monero.wait_for_alice_wallet_block_height().await.unwrap(); + monero.wallet("alice").unwrap().refresh().await.unwrap(); let alice_final_xmr_balance = alice_monero_wallet.get_balance().await.unwrap(); let bob_final_xmr_balance = bob_monero_wallet.get_balance().await.unwrap(); @@ -419,7 +433,14 @@ async fn on_chain_both_refund_if_alice_never_redeems() { #[tokio::test] async fn on_chain_alice_punishes_if_bob_never_acts_after_fund() { let cli = Cli::default(); - let (monero, _container) = Monero::new(&cli).unwrap(); + let (monero, _container) = Monero::new( + &cli, + Some("ocap".to_string()), + Some("ocap".to_string()), + vec!["alice".to_string(), "bob".to_string()], + ) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let (alice_state0, bob_state0, mut alice_node, mut bob_node, initial_balances, swap_amounts) = From a04f04f1a56670e0808c71110804b68d58cb4e73 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 11:00:05 +1100 Subject: [PATCH 09/15] Fix failing test due to uninitialized miner --- monero-harness/src/lib.rs | 17 ++++++++--------- monero-harness/tests/monerod.rs | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index d1e45884..cdf8926f 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -121,12 +121,6 @@ impl<'c> Monero { let miner_wallet = self.wallet("miner")?; let miner_address = miner_wallet.address().await?.address; - let alice_wallet = self.wallet("alice")?; - let alice_address = alice_wallet.address().await?.address; - - let bob_wallet = self.wallet("bob")?; - let bob_address = bob_wallet.address().await?.address; - // generate the first 70 as bulk let monerod = &self.monerod; let block = monerod.inner().generate_blocks(70, &miner_address).await?; @@ -134,17 +128,22 @@ impl<'c> Monero { miner_wallet.refresh().await?; if alice_amount > 0 { + let alice_wallet = self.wallet("alice")?; + let alice_address = alice_wallet.address().await?.address; miner_wallet.transfer(&alice_address, alice_amount).await?; tracing::info!("Funded alice wallet with {}", alice_amount); + monerod.inner().generate_blocks(10, &miner_address).await?; + alice_wallet.refresh().await?; } if bob_amount > 0 { + let bob_wallet = self.wallet("bob")?; + let bob_address = bob_wallet.address().await?.address; miner_wallet.transfer(&bob_address, bob_amount).await?; tracing::info!("Funded bob wallet with {}", bob_amount); + monerod.inner().generate_blocks(10, &miner_address).await?; + bob_wallet.refresh().await?; } - monerod.inner().generate_blocks(10, &miner_address).await?; - alice_wallet.refresh().await?; - bob_wallet.refresh().await?; monerod.start_miner(&miner_address).await?; tracing::info!("Waiting for miner wallet to catch up..."); diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index 53a865e7..086e5006 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -9,6 +9,7 @@ async fn init_miner_and_mine_to_miner_address() { let tc = Cli::default(); let (monero, _monerod_container) = Monero::new(&tc, None, None, vec![]).await.unwrap(); + monero.init(0, 0).await.unwrap(); let monerod = monero.monerod(); let miner_wallet = monero.wallet("miner").unwrap(); From 306176b3e611575e8a09b656afb83e5dc9788ce9 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 11:21:44 +1100 Subject: [PATCH 10/15] PR feedback: Removed network prefix and use the same for container and network. Add sentence explaining prefix --- monero-harness/src/lib.rs | 28 ++++++++++------------- monero-harness/tests/monerod.rs | 2 +- monero-harness/tests/wallet.rs | 2 +- xmr-btc/tests/e2e.rs | 39 +++++++++++++++------------------ xmr-btc/tests/on_chain.rs | 30 ++++++++++--------------- 5 files changed, 44 insertions(+), 57 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index cdf8926f..dc3aa68c 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -49,29 +49,25 @@ const WAIT_WALLET_SYNC_MILLIS: u64 = 1000; pub struct Monero { monerod: Monerod, wallets: Vec, - container_prefix: String, + prefix: String, } impl<'c> Monero { /// Starts a new regtest monero container setup consisting out of 1 monerod - /// node and n wallets. The containers will be prefixed with - /// `container_prefix` if provided. There will be 1 miner wallet started + /// node and n wallets. The containers and network will be prefixed with + /// `prefix` if provided. There will be 1 miner wallet started /// automatically. Default monerod container name will be: `monerod` /// Default miner wallet container name will be: `miner` /// Default network will be: `monero` + /// Each default will be prefixed with `prefix`. pub async fn new( cli: &'c Cli, - container_prefix: Option, - network_prefix: Option, + prefix: Option, additional_wallets: Vec, ) -> Result<(Self, Vec>)> { - let container_prefix = container_prefix.unwrap_or_else(|| "".to_string()); + let prefix = prefix.unwrap_or_else(|| "".to_string()); - let monerod_name = format!("{}{}", container_prefix, MONEROD_DAEMON_CONTAINER_NAME); - let network = format!( - "{}{}", - network_prefix.unwrap_or_else(|| "".to_string()), - MONEROD_DEFAULT_NETWORK - ); + let monerod_name = format!("{}{}", prefix, MONEROD_DAEMON_CONTAINER_NAME); + let network = format!("{}{}", prefix, MONEROD_DEFAULT_NETWORK); tracing::info!("Starting monerod..."); let (monerod, monerod_container) = Monerod::new(cli, monerod_name, network)?; @@ -79,14 +75,14 @@ impl<'c> Monero { let mut wallets = vec![]; tracing::info!("Starting miner wallet..."); - let miner = format!("{}{}", container_prefix, "miner"); + let miner = format!("{}{}", prefix, "miner"); let (miner_wallet, miner_container) = MoneroWalletRpc::new(cli, &miner, &monerod).await?; wallets.push(miner_wallet); containers.push(miner_container); for wallet in additional_wallets.iter() { tracing::info!("Starting wallet: {}...", wallet); - let wallet = format!("{}{}", container_prefix, wallet); + let wallet = format!("{}{}", prefix, wallet); let (wallet, container) = MoneroWalletRpc::new(cli, &wallet, &monerod).await?; wallets.push(wallet); containers.push(container); @@ -96,7 +92,7 @@ impl<'c> Monero { Self { monerod, wallets, - container_prefix, + prefix, }, containers, )) @@ -107,7 +103,7 @@ impl<'c> Monero { } pub fn wallet(&self, name: &str) -> Result<&MoneroWalletRpc> { - let name = format!("{}{}", self.container_prefix, name); + let name = format!("{}{}", self.prefix, name); let wallet = self .wallets .iter() diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index 086e5006..b6acecd7 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -7,7 +7,7 @@ use tokio::time; #[tokio::test] async fn init_miner_and_mine_to_miner_address() { let tc = Cli::default(); - let (monero, _monerod_container) = Monero::new(&tc, None, None, vec![]).await.unwrap(); + let (monero, _monerod_container) = Monero::new(&tc, None, vec![]).await.unwrap(); monero.init(0, 0).await.unwrap(); let monerod = monero.monerod(); diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index fc29ae5e..ef48038b 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -9,7 +9,7 @@ async fn fund_transfer_and_check_tx_key() { let send_to_bob = 5_000_000_000; let tc = Cli::default(); - let (monero, _containers) = Monero::new(&tc, Some("test_".to_string()), None, vec![ + let (monero, _containers) = Monero::new(&tc, Some("test_".to_string()), vec![ "alice".to_string(), "bob".to_string(), ]) diff --git a/xmr-btc/tests/e2e.rs b/xmr-btc/tests/e2e.rs index 9822bc48..c20655b2 100644 --- a/xmr-btc/tests/e2e.rs +++ b/xmr-btc/tests/e2e.rs @@ -32,13 +32,12 @@ mod tests { .set_default(); let cli = Cli::default(); - let (monero, _container) = - Monero::new(&cli, Some("hp".to_string()), Some("hp".to_string()), vec![ - "alice".to_string(), - "bob".to_string(), - ]) - .await - .unwrap(); + let (monero, _container) = Monero::new(&cli, Some("hp".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let ( @@ -112,13 +111,12 @@ mod tests { .set_default(); let cli = Cli::default(); - let (monero, _container) = - Monero::new(&cli, Some("br".to_string()), Some("br".to_string()), vec![ - "alice".to_string(), - "bob".to_string(), - ]) - .await - .unwrap(); + let (monero, _container) = Monero::new(&cli, Some("br".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; let ( @@ -194,13 +192,12 @@ mod tests { .set_default(); let cli = Cli::default(); - let (monero, _containers) = - Monero::new(&cli, Some("ap".to_string()), Some("ap".to_string()), vec![ - "alice".to_string(), - "bob".to_string(), - ]) - .await - .unwrap(); + let (monero, _containers) = Monero::new(&cli, Some("ap".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); let bitcoind = init_bitcoind(&cli).await; diff --git a/xmr-btc/tests/on_chain.rs b/xmr-btc/tests/on_chain.rs index ae95a1f2..7bec0e9e 100644 --- a/xmr-btc/tests/on_chain.rs +++ b/xmr-btc/tests/on_chain.rs @@ -238,12 +238,10 @@ async fn swap_as_bob( #[tokio::test] async fn on_chain_happy_path() { let cli = Cli::default(); - let (monero, _container) = Monero::new( - &cli, - Some("ochp".to_string()), - Some("ochp".to_string()), - vec!["alice".to_string(), "bob".to_string()], - ) + let (monero, _container) = Monero::new(&cli, Some("ochp".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) .await .unwrap(); let bitcoind = init_bitcoind(&cli).await; @@ -336,12 +334,10 @@ async fn on_chain_happy_path() { #[tokio::test] async fn on_chain_both_refund_if_alice_never_redeems() { let cli = Cli::default(); - let (monero, _container) = Monero::new( - &cli, - Some("ocbr".to_string()), - Some("ocbr".to_string()), - vec!["alice".to_string(), "bob".to_string()], - ) + let (monero, _container) = Monero::new(&cli, Some("ocbr".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) .await .unwrap(); let bitcoind = init_bitcoind(&cli).await; @@ -433,12 +429,10 @@ async fn on_chain_both_refund_if_alice_never_redeems() { #[tokio::test] async fn on_chain_alice_punishes_if_bob_never_acts_after_fund() { let cli = Cli::default(); - let (monero, _container) = Monero::new( - &cli, - Some("ocap".to_string()), - Some("ocap".to_string()), - vec!["alice".to_string(), "bob".to_string()], - ) + let (monero, _container) = Monero::new(&cli, Some("ocap".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) .await .unwrap(); let bitcoind = init_bitcoind(&cli).await; From f0fbe785c8dffc74bcde658301c8a9c198e355bd Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 11:46:25 +1100 Subject: [PATCH 11/15] Remove Alice and Bob from utility struct --- monero-harness/src/lib.rs | 54 +++++++-------------------------- monero-harness/tests/monerod.rs | 3 +- monero-harness/tests/wallet.rs | 23 +++++++++++--- xmr-btc/tests/harness/mod.rs | 5 ++- 4 files changed, 35 insertions(+), 50 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index dc3aa68c..b51f6e81 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -113,7 +113,7 @@ impl<'c> Monero { Ok(wallet) } - pub async fn init(&self, alice_amount: u64, bob_amount: u64) -> Result<()> { + pub async fn init(&self, wallet_amount: Vec<(&str, u64)>) -> Result<()> { let miner_wallet = self.wallet("miner")?; let miner_address = miner_wallet.address().await?.address; @@ -123,21 +123,15 @@ impl<'c> Monero { tracing::info!("Generated {:?} blocks", block); miner_wallet.refresh().await?; - if alice_amount > 0 { - let alice_wallet = self.wallet("alice")?; - let alice_address = alice_wallet.address().await?.address; - miner_wallet.transfer(&alice_address, alice_amount).await?; - tracing::info!("Funded alice wallet with {}", alice_amount); - monerod.inner().generate_blocks(10, &miner_address).await?; - alice_wallet.refresh().await?; - } - if bob_amount > 0 { - let bob_wallet = self.wallet("bob")?; - let bob_address = bob_wallet.address().await?.address; - miner_wallet.transfer(&bob_address, bob_amount).await?; - tracing::info!("Funded bob wallet with {}", bob_amount); - monerod.inner().generate_blocks(10, &miner_address).await?; - bob_wallet.refresh().await?; + for (wallet, amount) in wallet_amount.iter() { + if *amount > 0 { + let wallet = self.wallet(wallet)?; + let address = wallet.address().await?.address; + miner_wallet.transfer(&address, *amount).await?; + tracing::info!("Funded {} wallet with {}", wallet.name, amount); + monerod.inner().generate_blocks(10, &miner_address).await?; + wallet.refresh().await?; + } } monerod.start_miner(&miner_address).await?; @@ -151,30 +145,6 @@ impl<'c> Monero { Ok(()) } - - pub async fn fund(&self, address: &str, amount: u64) -> Result { - self.transfer("miner", address, amount).await - } - - pub async fn transfer_from_alice(&self, address: &str, amount: u64) -> Result { - self.transfer("alice", address, amount).await - } - - pub async fn transfer_from_bob(&self, address: &str, amount: u64) -> Result { - self.transfer("bob", address, amount).await - } - - async fn transfer(&self, from_wallet: &str, address: &str, amount: u64) -> Result { - let from = self.wallet(from_wallet)?; - let transfer = from.transfer(address, amount).await?; - let miner_address = self.wallet("miner")?.address().await?.address; - self.monerod - .inner() - .generate_blocks(10, &miner_address) - .await?; - from.inner().refresh().await?; - Ok(transfer) - } } #[derive(Clone, Debug)] @@ -292,9 +262,7 @@ impl<'c> MoneroWalletRpc { /// Sends amount to address pub async fn transfer(&self, address: &str, amount: u64) -> Result { - let transfer = self.inner().transfer(0, amount, address).await?; - self.inner().refresh().await?; - Ok(transfer) + self.inner().transfer(0, amount, address).await } pub async fn address(&self) -> Result { diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index b6acecd7..f081c4b4 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -9,7 +9,8 @@ async fn init_miner_and_mine_to_miner_address() { let tc = Cli::default(); let (monero, _monerod_container) = Monero::new(&tc, None, vec![]).await.unwrap(); - monero.init(0, 0).await.unwrap(); + monero.init(vec![]).await.unwrap(); + let monerod = monero.monerod(); let miner_wallet = monero.wallet("miner").unwrap(); diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index ef48038b..17d70030 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -17,23 +17,36 @@ async fn fund_transfer_and_check_tx_key() { .unwrap(); let alice_wallet = monero.wallet("alice").unwrap(); let bob_wallet = monero.wallet("bob").unwrap(); + let miner_wallet = monero.wallet("miner").unwrap(); + + let miner_address = miner_wallet.address().await.unwrap().address; // fund alice - monero.init(fund_alice, fund_bob).await.unwrap(); + monero + .init(vec![("alice", fund_alice), ("bob", fund_bob)]) + .await + .unwrap(); // check alice balance - alice_wallet.inner().refresh().await.unwrap(); + alice_wallet.refresh().await.unwrap(); let got_alice_balance = alice_wallet.balance().await.unwrap(); assert_that(&got_alice_balance).is_equal_to(fund_alice); // transfer from alice to bob let bob_address = bob_wallet.address().await.unwrap().address; - let transfer = monero - .transfer_from_alice(&bob_address, send_to_bob) + let transfer = alice_wallet + .transfer(&bob_address, send_to_bob) + .await + .unwrap(); + + monero + .monerod() + .inner() + .generate_blocks(10, &miner_address) .await .unwrap(); - bob_wallet.inner().refresh().await.unwrap(); + bob_wallet.refresh().await.unwrap(); let got_bob_balance = bob_wallet.balance().await.unwrap(); assert_that(&got_bob_balance).is_equal_to(send_to_bob); diff --git a/xmr-btc/tests/harness/mod.rs b/xmr-btc/tests/harness/mod.rs index de57d34e..c80d02ad 100644 --- a/xmr-btc/tests/harness/mod.rs +++ b/xmr-btc/tests/harness/mod.rs @@ -130,7 +130,10 @@ pub async fn init_test( let fund_alice = TEN_XMR; let fund_bob = 0; - monero.init(fund_alice, fund_bob).await.unwrap(); + monero + .init(vec![("alice", fund_alice), ("bob", fund_bob)]) + .await + .unwrap(); let alice_monero_wallet = wallet::monero::Wallet(monero.wallet("alice").unwrap().inner()); let bob_monero_wallet = wallet::monero::Wallet(monero.wallet("bob").unwrap().inner()); From 1a38bf57f2f19ed0bb7d8f0b3462e9f82f706c12 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 11:49:53 +1100 Subject: [PATCH 12/15] Rename inner to client --- monero-harness/src/image.rs | 2 -- monero-harness/src/lib.rs | 24 ++++++++++++------------ monero-harness/tests/monerod.rs | 2 +- monero-harness/tests/wallet.rs | 4 ++-- xmr-btc/tests/harness/mod.rs | 4 ++-- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/monero-harness/src/image.rs b/monero-harness/src/image.rs index 4d699fc9..a491a345 100644 --- a/monero-harness/src/image.rs +++ b/monero-harness/src/image.rs @@ -245,8 +245,6 @@ impl MonerodArgs { args.push(format!("--log-level {}", self.log_level)); } - // args.push(format!("--disable-rpc-login")); - args.join(" ") } } diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index b51f6e81..98e9c01e 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -119,7 +119,7 @@ impl<'c> Monero { // generate the first 70 as bulk let monerod = &self.monerod; - let block = monerod.inner().generate_blocks(70, &miner_address).await?; + let block = monerod.client().generate_blocks(70, &miner_address).await?; tracing::info!("Generated {:?} blocks", block); miner_wallet.refresh().await?; @@ -129,7 +129,7 @@ impl<'c> Monero { let address = wallet.address().await?.address; miner_wallet.transfer(&address, *amount).await?; tracing::info!("Funded {} wallet with {}", wallet.name, amount); - monerod.inner().generate_blocks(10, &miner_address).await?; + monerod.client().generate_blocks(10, &miner_address).await?; wallet.refresh().await?; } } @@ -137,7 +137,7 @@ impl<'c> Monero { monerod.start_miner(&miner_address).await?; tracing::info!("Waiting for miner wallet to catch up..."); - let block_height = monerod.inner().get_block_count().await?; + let block_height = monerod.client().get_block_count().await?; miner_wallet .wait_for_wallet_height(block_height) .await @@ -190,14 +190,14 @@ impl<'c> Monerod { )) } - pub fn inner(&self) -> monerod::Client { + pub fn client(&self) -> monerod::Client { monerod::Client::localhost(self.rpc_port) } /// Spawns a task to mine blocks in a regular interval to the provided /// address pub async fn start_miner(&self, miner_wallet_address: &str) -> Result<()> { - let monerod = self.inner(); + let monerod = self.client(); let _ = tokio::spawn(mine(monerod, miner_wallet_address.to_string())); Ok(()) } @@ -242,14 +242,14 @@ impl<'c> MoneroWalletRpc { )) } - pub fn inner(&self) -> wallet::Client { + pub fn client(&self) -> wallet::Client { wallet::Client::localhost(self.rpc_port) } // It takes a little while for the wallet to sync with monerod. pub async fn wait_for_wallet_height(&self, height: u32) -> Result<()> { let mut retry: u8 = 0; - while self.inner().block_height().await?.height < height { + while self.client().block_height().await?.height < height { if retry >= 30 { // ~30 seconds bail!("Wallet could not catch up with monerod after 30 retries.") @@ -262,20 +262,20 @@ impl<'c> MoneroWalletRpc { /// Sends amount to address pub async fn transfer(&self, address: &str, amount: u64) -> Result { - self.inner().transfer(0, amount, address).await + self.client().transfer(0, amount, address).await } pub async fn address(&self) -> Result { - self.inner().get_address(0).await + self.client().get_address(0).await } pub async fn balance(&self) -> Result { - self.inner().refresh().await?; - self.inner().get_balance(0).await + self.client().refresh().await?; + self.client().get_balance(0).await } pub async fn refresh(&self) -> Result { - self.inner().refresh().await + self.client().refresh().await } } /// Mine a block ever BLOCK_TIME_SECS seconds. diff --git a/monero-harness/tests/monerod.rs b/monero-harness/tests/monerod.rs index f081c4b4..35f12744 100644 --- a/monero-harness/tests/monerod.rs +++ b/monero-harness/tests/monerod.rs @@ -20,7 +20,7 @@ async fn init_miner_and_mine_to_miner_address() { time::delay_for(Duration::from_millis(1010)).await; // after a bit more than 1 sec another block should have been mined - let block_height = monerod.inner().get_block_count().await.unwrap(); + let block_height = monerod.client().get_block_count().await.unwrap(); assert_that(&block_height).is_greater_than(70); } diff --git a/monero-harness/tests/wallet.rs b/monero-harness/tests/wallet.rs index 17d70030..44fc6ec5 100644 --- a/monero-harness/tests/wallet.rs +++ b/monero-harness/tests/wallet.rs @@ -41,7 +41,7 @@ async fn fund_transfer_and_check_tx_key() { monero .monerod() - .inner() + .client() .generate_blocks(10, &miner_address) .await .unwrap(); @@ -54,7 +54,7 @@ async fn fund_transfer_and_check_tx_key() { let tx_id = transfer.tx_hash; let tx_key = transfer.tx_key; let res = bob_wallet - .inner() + .client() .check_tx_key(&tx_id, &tx_key, &bob_address) .await .expect("failed to check tx by key"); diff --git a/xmr-btc/tests/harness/mod.rs b/xmr-btc/tests/harness/mod.rs index c80d02ad..3d789b8f 100644 --- a/xmr-btc/tests/harness/mod.rs +++ b/xmr-btc/tests/harness/mod.rs @@ -135,8 +135,8 @@ pub async fn init_test( .await .unwrap(); - let alice_monero_wallet = wallet::monero::Wallet(monero.wallet("alice").unwrap().inner()); - let bob_monero_wallet = wallet::monero::Wallet(monero.wallet("bob").unwrap().inner()); + let alice_monero_wallet = wallet::monero::Wallet(monero.wallet("alice").unwrap().client()); + let bob_monero_wallet = wallet::monero::Wallet(monero.wallet("bob").unwrap().client()); let alice_btc_wallet = wallet::bitcoin::Wallet::new("alice", &bitcoind.node_url) .await From 70d64f74aecc0c514f5acda82241f8826d544e94 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 11:56:13 +1100 Subject: [PATCH 13/15] Testcontainers upgrade --- swap/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/swap/Cargo.toml b/swap/Cargo.toml index e89df6a3..af99bcba 100644 --- a/swap/Cargo.toml +++ b/swap/Cargo.toml @@ -47,4 +47,4 @@ hyper = "0.13" port_check = "0.1" spectral = "0.6" tempfile = "3" -testcontainers = "0.10" +testcontainers = "0.11" From 981fcacc959718d3a18bddd442ba199ea5d4e025 Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 12:13:18 +1100 Subject: [PATCH 14/15] Make swap e2e test work with new monerod lib --- swap/tests/e2e.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/swap/tests/e2e.rs b/swap/tests/e2e.rs index cb49ef05..9c8eda1b 100644 --- a/swap/tests/e2e.rs +++ b/swap/tests/e2e.rs @@ -51,11 +51,21 @@ mod e2e_test { .await .unwrap(); - let (monero, _container) = Monero::new(&cli).unwrap(); - monero.init(xmr_alice, xmr_bob).await.unwrap(); + let (monero, _container) = Monero::new(&cli, Some("swap_".to_string()), vec![ + "alice".to_string(), + "bob".to_string(), + ]) + .await + .unwrap(); + monero + .init(vec![("alice", xmr_alice), ("bob", xmr_bob)]) + .await + .unwrap(); - let alice_xmr_wallet = Arc::new(swap::monero::Wallet(monero.alice_wallet_rpc_client())); - let bob_xmr_wallet = Arc::new(swap::monero::Wallet(monero.bob_wallet_rpc_client())); + let alice_xmr_wallet = Arc::new(swap::monero::Wallet( + monero.wallet("alice").unwrap().client(), + )); + let bob_xmr_wallet = Arc::new(swap::monero::Wallet(monero.wallet("bob").unwrap().client())); let alice_behaviour = alice::Alice::default(); let alice_transport = build(alice_behaviour.identity()).unwrap(); @@ -92,7 +102,7 @@ mod e2e_test { let xmr_alice_final = alice_xmr_wallet.as_ref().get_balance().await.unwrap(); - monero.wait_for_bob_wallet_block_height().await.unwrap(); + bob_xmr_wallet.as_ref().0.refresh().await.unwrap(); let xmr_bob_final = bob_xmr_wallet.as_ref().get_balance().await.unwrap(); assert_eq!( From bca439ada5fdbb8996e75ee4bacc20cf6f8404fb Mon Sep 17 00:00:00 2001 From: Philipp Hoenisch Date: Tue, 3 Nov 2020 12:25:22 +1100 Subject: [PATCH 15/15] Use random prefix --- monero-harness/src/lib.rs | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/monero-harness/src/lib.rs b/monero-harness/src/lib.rs index 98e9c01e..7d42a586 100644 --- a/monero-harness/src/lib.rs +++ b/monero-harness/src/lib.rs @@ -53,29 +53,28 @@ pub struct Monero { } impl<'c> Monero { /// Starts a new regtest monero container setup consisting out of 1 monerod - /// node and n wallets. The containers and network will be prefixed with - /// `prefix` if provided. There will be 1 miner wallet started - /// automatically. Default monerod container name will be: `monerod` - /// Default miner wallet container name will be: `miner` - /// Default network will be: `monero` - /// Each default will be prefixed with `prefix`. + /// node and n wallets. The containers and network will be prefixed, either + /// randomly generated or as defined in `prefix` if provided. There will + /// be 1 miner wallet started automatically. Default monerod container + /// name will be: `prefix`_`monerod` Default miner wallet container name + /// will be: `prefix`_`miner` Default network will be: `prefix`_`monero` pub async fn new( cli: &'c Cli, prefix: Option, additional_wallets: Vec, ) -> Result<(Self, Vec>)> { - let prefix = prefix.unwrap_or_else(|| "".to_string()); + let prefix = format!("{}_", prefix.unwrap_or_else(random_prefix)); let monerod_name = format!("{}{}", prefix, MONEROD_DAEMON_CONTAINER_NAME); let network = format!("{}{}", prefix, MONEROD_DEFAULT_NETWORK); - tracing::info!("Starting monerod..."); + tracing::info!("Starting monerod... {}", monerod_name); let (monerod, monerod_container) = Monerod::new(cli, monerod_name, network)?; let mut containers = vec![monerod_container]; let mut wallets = vec![]; - tracing::info!("Starting miner wallet..."); let miner = format!("{}{}", prefix, "miner"); + tracing::info!("Starting miner wallet... {}", miner); let (miner_wallet, miner_container) = MoneroWalletRpc::new(cli, &miner, &monerod).await?; wallets.push(miner_wallet); @@ -147,6 +146,21 @@ impl<'c> Monero { } } +fn random_prefix() -> String { + use rand::Rng; + const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz"; + const LEN: usize = 4; + let mut rng = rand::thread_rng(); + + let prefix: String = (0..LEN) + .map(|_| { + let idx = rng.gen_range(0, CHARSET.len()); + CHARSET[idx] as char + }) + .collect(); + prefix +} + #[derive(Clone, Debug)] pub struct Monerod { rpc_port: u16,