Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Monero wallet refresh fix #1487

Merged
merged 12 commits into from
Mar 25, 2024
68 changes: 65 additions & 3 deletions swap/src/monero/wallet.rs
Original file line number Diff line number Diff line change
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_attempts: 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::debug!(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_attempts {
tracing::info!(name = %self.name, attempt=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 attempts_left = max_attempts - i;
tracing::warn!(attempt=i, %attempts_left, name = %self.name, %error, "Failed to sync Monero wallet");

if attempts_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
34 changes: 24 additions & 10 deletions swap/src/monero/wallet_rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,28 @@ const MONERO_DAEMONS: [MoneroDaemon; 17] = [
compile_error!("unsupported operating system");

#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-x64-v0.18.1.2.tar.bz2";
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-x64-v0.18.3.1.tar.bz2";

#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-armv8-v0.18.0.0.tar.bz2";
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-mac-armv8-v0.18.3.1.tar.bz2";

#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.1.2.tar.bz2";
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-linux-x64-v0.18.3.1.tar.bz2";

#[cfg(all(target_os = "linux", target_arch = "arm"))]
const DOWNLOAD_URL: &str =
"https://downloads.getmonero.org/cli/monero-linux-armv7-v0.18.1.2.tar.bz2";
"https://downloads.getmonero.org/cli/monero-linux-armv7-v0.18.3.1.tar.bz2";

#[cfg(target_os = "windows")]
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.18.1.2.zip";
const DOWNLOAD_URL: &str = "https://downloads.getmonero.org/cli/monero-win-x64-v0.18.3.1.zip";

#[cfg(any(target_os = "macos", target_os = "linux"))]
const PACKED_FILE: &str = "monero-wallet-rpc";

#[cfg(target_os = "windows")]
const PACKED_FILE: &str = "monero-wallet-rpc.exe";

const WALLET_RPC_VERSION: &str = "v0.18.1.2";
const WALLET_RPC_VERSION: &str = "v0.18.3.1";

#[derive(Debug, Clone, Copy, thiserror::Error)]
#[error("monero wallet rpc executable not found in downloaded archive")]
Expand Down Expand Up @@ -221,9 +221,10 @@ impl WalletRpc {
.parse::<u64>()?;

tracing::info!(
"Downloading monero-wallet-rpc ({}) from {}",
content_length.big_byte(2),
DOWNLOAD_URL
progress="0%",
size=%content_length.big_byte(2),
download_url=DOWNLOAD_URL,
"Downloading monero-wallet-rpc",
);

let byte_stream = response
Expand All @@ -250,12 +251,24 @@ impl WalletRpc {
let total = 3 * content_length;
let percent = 100 * received as u64 / total;
if percent != notified && percent % 10 == 0 {
tracing::debug!("{}%", percent);
tracing::info!(
progress=format!("{}%", percent),
size=%content_length.big_byte(2),
download_url=DOWNLOAD_URL,
"Downloading monero-wallet-rpc",
);
notified = percent;
}
file.write_all(&bytes).await?;
}

tracing::info!(
progress="100%",
size=%content_length.big_byte(2),
download_url=DOWNLOAD_URL,
"Downloading monero-wallet-rpc",
);

file.flush().await?;

tracing::debug!("Extracting archive");
Expand Down Expand Up @@ -309,6 +322,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
5 changes: 4 additions & 1 deletion swap/src/protocol/bob/swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,9 @@ async fn next_state(
let (spend_key, view_key) = state.xmr_keys();

let wallet_file_name = swap_id.to_string();

tracing::info!(%wallet_file_name, "Generating and opening Monero wallet from the extracted keys to redeem the Monero");

if let Err(e) = monero_wallet
.create_from_and_load(
wallet_file_name.clone(),
Expand All @@ -247,7 +250,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
Loading