Skip to content

Commit

Permalink
Give feedback to user about state of monero refresh and retry if fails
Browse files Browse the repository at this point in the history
This commit changes the following behaviour in the refresh functionality of the monero wallet
- Allows for multiple retries because in some cases users have experienced an issue where the wallet rpc returns `no connection to daemon` even though the daemon is available. I'm not 100% sure why this happens but retrying often fixes the issue
- Attempt to print the current sync height while the wallet is syncing. This only works to some degree because the `monero-wallet-rpc` stops responding (or takes a long time to respond) while it's refreshing
- The `monero-wallet-rpc` is started with the `--no-initial-sync` flag which ensures that as soon as it's started, it's ready to respond to requests
  • Loading branch information
binarybaron committed Dec 14, 2023
1 parent dc1ad6d commit c499e9d
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 6 deletions.
70 changes: 66 additions & 4 deletions swap/src/monero/wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use anyhow::{Context, Result};
use monero_rpc::wallet::{BlockHeight, MoneroWalletRpc as _, Refreshed};
use monero_rpc::{jsonrpc, wallet};
use std::str::FromStr;
use std::time::Duration;
use std::time::{Duration};
use tokio::sync::Mutex;
use tokio::time::Interval;
use url::Url;
Expand Down Expand Up @@ -45,6 +45,7 @@ impl Wallet {
pub async fn connect(client: wallet::Client, name: String, env_config: Config) -> Result<Self> {
let main_address =
monero::Address::from_str(client.get_address(0).await?.address.as_str())?;

Ok(Self {
inner: Mutex::new(client),
network: env_config.monero_network,
Expand Down Expand Up @@ -144,7 +145,7 @@ impl Wallet {
.await?;

// Try to send all the funds from the generated wallet to the default wallet
match wallet.refresh().await {
match self.refresh(3).await {
Ok(_) => match wallet.sweep_all(self.main_address.to_string()).await {
Ok(sweep_all) => {
for tx in sweep_all.tx_hash_list {
Expand Down Expand Up @@ -261,8 +262,69 @@ impl Wallet {
self.main_address
}

pub async fn refresh(&self) -> Result<Refreshed> {
Ok(self.inner.lock().await.refresh().await?)
pub async fn refresh(&self, max_retries: usize) -> Result<Refreshed> {
const GET_HEIGHT_INTERVAL: Duration = Duration::from_secs(5);
const RETRY_INTERVAL: Duration = Duration::from_secs(2);

let inner = self.inner.lock().await;

// Cloning this is relatively cheap because reqwest::Client is a wrapper around an Arc
let inner_clone = inner.clone();
let wallet_name_clone = self.name.clone();

let refresh_task = tokio::task::spawn(async move {
loop {
let height = inner_clone.get_height().await;

match height {
Err(error) => {
tracing::warn!(name = %wallet_name_clone, %error, "Failed to get current Monero wallet sync height");
}
Ok(height) => {
tracing::debug!(name = %wallet_name_clone, current_sync_height = height.height, "Syncing Monero wallet");
}
}

tokio::time::sleep(GET_HEIGHT_INTERVAL).await;
}
});

let refresh_result = tokio::select! {
biased;
_ = refresh_task => {
unreachable!("Current sync height refresh task should never finish")
}
refresh_result = async {
for i in 1..=max_retries {
tracing::info!(name = %self.name, try_number=i, "Syncing Monero wallet");

let result = inner.refresh().await;

match result {
Ok(refreshed) => {
tracing::info!(name = %self.name, "Monero wallet synced");
return Ok(refreshed);
}
Err(error) => {
let retries_left = max_retries - i;
tracing::warn!(%retries_left, name = %self.name, %error, "Failed to sync Monero wallet");

if retries_left == 0 {
return Err(error);
}
}
}

tokio::time::sleep(RETRY_INTERVAL).await;
}

unreachable!("Loop should always return before it breaks")
} => {
refresh_result
}
};

Ok(refresh_result?)
}
}

Expand Down
1 change: 1 addition & 0 deletions swap/src/monero/wallet_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ impl WalletRpc {
.arg("--disable-rpc-login")
.arg("--wallet-dir")
.arg(self.working_dir.join("monero-data"))
.arg("--no-initial-sync")
.spawn()?;

let stdout = child
Expand Down
2 changes: 1 addition & 1 deletion swap/src/protocol/bob/swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ async fn next_state(
}

// Ensure that the generated wallet is synced so we have a proper balance
monero_wallet.refresh().await?;
monero_wallet.refresh(3).await?;
// Sweep (transfer all funds) to the given address
let tx_hashes = monero_wallet.sweep_all(monero_receive_address).await?;

Expand Down
2 changes: 1 addition & 1 deletion swap/tests/harness/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,7 @@ impl Wallet for monero::Wallet {
type Amount = monero::Amount;

async fn refresh(&self) -> Result<()> {
self.refresh().await?;
self.refresh(1).await?;

Ok(())
}
Expand Down

0 comments on commit c499e9d

Please sign in to comment.