179: Watch only tmp monero wallet r=da-kami a=da-kami

When initializing Monero wallet, try to open temporary wallet, if opening errors then try to create it. If creating errors then fail with message asking the user to configure the wallet RPC.
If opening / creation succeeds get the block_height to verify that connection to wallet works, then proceed to swap. 

Note: RPC error handling is hacky, but I don't see the value of investing time into that at this point. The problem is, that we don't deal with the json rpc errors properly for calls were we don't serialize the result into an object (because the response is empty). Eventually we should switch to using https://github.com/thomaseizinger/rust-jsonrpc-client but that does not support parameters `by-name` yet, see: https://github.com/thomaseizinger/rust-jsonrpc-client/issues/20

Co-authored-by: Daniel Karzel <daniel@comit.network>
This commit is contained in:
bors[bot] 2021-02-10 04:09:11 +00:00 committed by GitHub
commit 639b3169d8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 98 additions and 11 deletions

View File

@ -1,6 +1,5 @@
use crate::rpc::{Request, Response};
use anyhow::Result;
use anyhow::{bail, Result};
use reqwest::Url;
use serde::{Deserialize, Serialize};
use tracing::debug;
@ -121,6 +120,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 {
@ -140,6 +166,10 @@ impl Client {
debug!("create wallet RPC response: {}", response);
if response.contains("error") {
bail!("Failed to create wallet")
}
Ok(())
}
@ -348,6 +378,11 @@ pub struct SubAddressAccount {
pub unlocked_balance: u64,
}
#[derive(Serialize, Debug, Clone)]
struct OpenWalletParams {
filename: String,
}
#[derive(Serialize, Debug, Clone)]
struct CreateWalletParams {
filename: String,

View File

@ -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_BLOCKCHAIN_MONITORING_WALLET_NAME: &str = "swap-tool-blockchain-monitoring-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_monitoring_wallet_response = monero_wallet
.open_wallet(MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME)
.await;
if open_monitoring_wallet_response.is_err() {
monero_wallet
.create_wallet(MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME)
.await
.context(format!(
"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 Monero wallet for blockchain monitoring with name {}",
MONERO_BLOCKCHAIN_MONITORING_WALLET_NAME
);
} else {
info!(
"Opened Monero wallet for blockchain monitoring with name {}",
MONERO_BLOCKCHAIN_MONITORING_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))
}

View File

@ -207,6 +207,16 @@ 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<()>;
}
#[derive(thiserror::Error, Debug, Clone, PartialEq)]
#[error("Overflow, cannot convert {0} to u64")]
pub struct OverflowError(pub String);

View File

@ -1,6 +1,6 @@
use crate::monero::{
Amount, 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,22 @@ 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<()> {
self.inner.create_wallet(file_name).await?;
Ok(())
}
}
// TODO: For retry, use `backoff::ExponentialBackoff` in production as opposed
// to `ConstantBackoff`.
#[async_trait]