From 62605a318aaf7a72e72dc9b3e92441ede24d9b6b Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Tue, 9 Feb 2021 13:57:53 +1100 Subject: [PATCH 1/5] Add CreateWallet trait to expose create_wallet --- monero-harness/src/rpc/wallet.rs | 6 +++++- swap/src/monero.rs | 5 +++++ swap/src/monero/wallet.rs | 12 ++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/monero-harness/src/rpc/wallet.rs b/monero-harness/src/rpc/wallet.rs index d31a8b21..1f7920bc 100644 --- a/monero-harness/src/rpc/wallet.rs +++ b/monero-harness/src/rpc/wallet.rs @@ -1,6 +1,6 @@ use crate::rpc::{Request, Response}; -use anyhow::Result; +use anyhow::{bail, Result}; use reqwest::Url; use serde::{Deserialize, Serialize}; use tracing::debug; @@ -140,6 +140,10 @@ impl Client { debug!("create wallet RPC response: {}", response); + if response.contains("error") { + bail!("Failed to create wallet") + } + Ok(()) } diff --git a/swap/src/monero.rs b/swap/src/monero.rs index caec8864..3b33d2c4 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -207,6 +207,11 @@ pub trait CreateWalletForOutput { ) -> anyhow::Result<()>; } +#[async_trait] +pub trait CreateWallet { + async fn create_wallet(&self, file_name: &str) -> anyhow::Result<()>; +} + #[derive(thiserror::Error, Debug, Clone, PartialEq)] #[error("Overflow, cannot convert {0} to u64")] pub struct OverflowError(pub String); diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index d9d7ea73..b2d5d330 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -1,6 +1,6 @@ use crate::monero::{ - Amount, CreateWalletForOutput, InsufficientFunds, PrivateViewKey, PublicViewKey, Transfer, - TransferProof, TxHash, WatchForTransfer, + Amount, CreateWallet, CreateWalletForOutput, InsufficientFunds, PrivateViewKey, PublicViewKey, + Transfer, TransferProof, TxHash, WatchForTransfer, }; use ::monero::{Address, Network, PrivateKey, PublicKey}; use anyhow::Result; @@ -94,6 +94,14 @@ impl CreateWalletForOutput for Wallet { } } +#[async_trait] +impl CreateWallet for Wallet { + async fn create_wallet(&self, file_name: &str) -> Result<()> { + self.inner.create_wallet(file_name).await?; + Ok(()) + } +} + // TODO: For retry, use `backoff::ExponentialBackoff` in production as opposed // to `ConstantBackoff`. #[async_trait] From dac4443bbde2119abbfdefdad864cb2d1d4a5d37 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Tue, 9 Feb 2021 14:32:33 +1100 Subject: [PATCH 2/5] Add functionality to open monero wallet through rpc --- monero-harness/src/rpc/wallet.rs | 32 ++++++++++++++++++++++++++++++++ swap/src/monero.rs | 5 +++++ swap/src/monero/wallet.rs | 12 ++++++++++-- 3 files changed, 47 insertions(+), 2 deletions(-) diff --git a/monero-harness/src/rpc/wallet.rs b/monero-harness/src/rpc/wallet.rs index 1f7920bc..a84f4290 100644 --- a/monero-harness/src/rpc/wallet.rs +++ b/monero-harness/src/rpc/wallet.rs @@ -121,6 +121,33 @@ impl Client { Ok(r.result) } + /// Opens a wallet using `filename`. + pub async fn open_wallet(&self, filename: &str) -> Result<()> { + let params = OpenWalletParams { + filename: filename.to_owned(), + }; + let request = Request::new("open_wallet", params); + + let response = self + .inner + .post(self.url.clone()) + .json(&request) + .send() + .await? + .text() + .await?; + + debug!("open wallet RPC response: {}", response); + + // TODO: Proper error handling once switching to https://github.com/thomaseizinger/rust-jsonrpc-client/ + // Currently blocked by https://github.com/thomaseizinger/rust-jsonrpc-client/issues/20 + if response.contains("error") { + bail!("Failed to open wallet") + } + + Ok(()) + } + /// Creates a wallet using `filename`. pub async fn create_wallet(&self, filename: &str) -> Result<()> { let params = CreateWalletParams { @@ -352,6 +379,11 @@ pub struct SubAddressAccount { pub unlocked_balance: u64, } +#[derive(Serialize, Debug, Clone)] +struct OpenWalletParams { + filename: String, +} + #[derive(Serialize, Debug, Clone)] struct CreateWalletParams { filename: String, diff --git a/swap/src/monero.rs b/swap/src/monero.rs index 3b33d2c4..9d7bdec9 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -207,6 +207,11 @@ pub trait CreateWalletForOutput { ) -> anyhow::Result<()>; } +#[async_trait] +pub trait OpenWallet { + async fn open_wallet(&self, file_name: &str) -> anyhow::Result<()>; +} + #[async_trait] pub trait CreateWallet { async fn create_wallet(&self, file_name: &str) -> anyhow::Result<()>; diff --git a/swap/src/monero/wallet.rs b/swap/src/monero/wallet.rs index b2d5d330..a53c06c3 100644 --- a/swap/src/monero/wallet.rs +++ b/swap/src/monero/wallet.rs @@ -1,6 +1,6 @@ use crate::monero::{ - Amount, CreateWallet, CreateWalletForOutput, InsufficientFunds, PrivateViewKey, PublicViewKey, - Transfer, TransferProof, TxHash, WatchForTransfer, + Amount, CreateWallet, CreateWalletForOutput, InsufficientFunds, OpenWallet, PrivateViewKey, + PublicViewKey, Transfer, TransferProof, TxHash, WatchForTransfer, }; use ::monero::{Address, Network, PrivateKey, PublicKey}; use anyhow::Result; @@ -94,6 +94,14 @@ impl CreateWalletForOutput for Wallet { } } +#[async_trait] +impl OpenWallet for Wallet { + async fn open_wallet(&self, file_name: &str) -> Result<()> { + self.inner.open_wallet(file_name).await?; + Ok(()) + } +} + #[async_trait] impl CreateWallet for Wallet { async fn create_wallet(&self, file_name: &str) -> Result<()> { From 1e29433bd2daf57bf9c877a0f04f34f23c9e5c90 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Tue, 9 Feb 2021 15:34:12 +1100 Subject: [PATCH 3/5] Open or create temporary Monero wallet upon wallet initialization --- swap/src/main.rs | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/swap/src/main.rs b/swap/src/main.rs index a088ed5e..91aa32ab 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -18,6 +18,7 @@ use crate::{ initial_setup, query_user_for_initial_testnet_config, read_config, ConfigNotInitialized, }, execution_params::GetExecutionParams, + monero::{CreateWallet, OpenWallet}, protocol::bob::cancel::CancelError, }; use anyhow::{Context, Result}; @@ -49,9 +50,11 @@ mod serde_peer_id; #[macro_use] extern crate prettytable; +const MONERO_WATCH_ONLY_TEMP_WALLET_NAME: &str = "swap-tool-watch-only-tmp-wallet"; + #[tokio::main] async fn main() -> Result<()> { - init_tracing(LevelFilter::Info).expect("initialize tracing"); + init_tracing(LevelFilter::Debug).expect("initialize tracing"); let opt = Options::from_args(); @@ -326,12 +329,35 @@ async fn init_wallets( bitcoin_balance ); - let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url, monero_network); - let monero_balance = monero_wallet.get_balance().await?; - info!( - "Connection to Monero wallet succeeded, balance: {}", - monero_balance - ); + let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url.clone(), monero_network); + + // Setup the temporary Monero wallet necessary for monitoring the blockchain + let open_tmp_wallet_response = monero_wallet + .open_wallet(MONERO_WATCH_ONLY_TEMP_WALLET_NAME) + .await; + if open_tmp_wallet_response.is_err() { + monero_wallet + .create_wallet(MONERO_WATCH_ONLY_TEMP_WALLET_NAME) + .await + .context(format!( + "Unable to create temporary Monero wallet.\ + Please ensure that the monero-wallet-rpc is available at {}", + config.monero.wallet_rpc_url + ))?; + + info!( + "Created temporary Monero wallet {}", + MONERO_WATCH_ONLY_TEMP_WALLET_NAME + ); + } else { + info!( + "Opened temporary Monero wallet {}", + MONERO_WATCH_ONLY_TEMP_WALLET_NAME + ); + } + + let _test_wallet_connection = monero_wallet.inner.block_height().await?; + info!("The Monero wallet RPC is set up correctly!"); Ok((bitcoin_wallet, monero_wallet)) } From 0a0bce155261b7eb1c6fcf96dba63594ac08d1ff Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 10 Feb 2021 15:06:26 +1100 Subject: [PATCH 4/5] Rename temporary wallet to blockchain monitoring wallet --- swap/src/main.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/swap/src/main.rs b/swap/src/main.rs index 91aa32ab..bd7ec818 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -50,7 +50,7 @@ mod serde_peer_id; #[macro_use] extern crate prettytable; -const MONERO_WATCH_ONLY_TEMP_WALLET_NAME: &str = "swap-tool-watch-only-tmp-wallet"; +const MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-monitoring-wallet"; #[tokio::main] async fn main() -> Result<()> { @@ -332,27 +332,27 @@ async fn init_wallets( let monero_wallet = monero::Wallet::new(config.monero.wallet_rpc_url.clone(), monero_network); // Setup the temporary Monero wallet necessary for monitoring the blockchain - let open_tmp_wallet_response = monero_wallet - .open_wallet(MONERO_WATCH_ONLY_TEMP_WALLET_NAME) + let open_monitoring_wallet_response = monero_wallet + .open_wallet(MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME) .await; - if open_tmp_wallet_response.is_err() { + if open_monitoring_wallet_response.is_err() { monero_wallet - .create_wallet(MONERO_WATCH_ONLY_TEMP_WALLET_NAME) + .create_wallet(MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME) .await .context(format!( - "Unable to create temporary Monero wallet.\ + "Unable to create Monero wallet for blockchain monitoring.\ Please ensure that the monero-wallet-rpc is available at {}", config.monero.wallet_rpc_url ))?; info!( - "Created temporary Monero wallet {}", - MONERO_WATCH_ONLY_TEMP_WALLET_NAME + "Created Monero wallet for blockchain monitoring with name {}", + MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME ); } else { info!( - "Opened temporary Monero wallet {}", - MONERO_WATCH_ONLY_TEMP_WALLET_NAME + "Opened Monero wallet for blockchain monitoring with name {}", + MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME ); } From 56a59bc41ce6621090ba5599ebef27477438e890 Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Wed, 10 Feb 2021 15:07:37 +1100 Subject: [PATCH 5/5] Remove newline in use statements --- monero-harness/src/rpc/wallet.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/monero-harness/src/rpc/wallet.rs b/monero-harness/src/rpc/wallet.rs index a84f4290..cd92588c 100644 --- a/monero-harness/src/rpc/wallet.rs +++ b/monero-harness/src/rpc/wallet.rs @@ -1,5 +1,4 @@ use crate::rpc::{Request, Response}; - use anyhow::{bail, Result}; use reqwest::Url; use serde::{Deserialize, Serialize};