From cf0c6c52605629c206c53f95eaa60b18b7e4581c Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 26 Mar 2024 15:41:08 -0500 Subject: [PATCH 1/4] Only select gateways we can actually find --- src/mint.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/mint.rs b/src/mint.rs index dc1239f..0a88942 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -97,26 +97,24 @@ pub(crate) async fn setup_multimint( pub(crate) async fn select_gateway(client: &ClientHandleArc) -> Option { let ln = client.get_first_module::(); - let mut gateway_id = None; + let mut selected_gateway = None; for gateway in ln.list_gateways().await { // first try to find a vetted gateway if gateway.vetted { - gateway_id = Some(gateway.info.gateway_id); - break; // if vetted gateway found, use it + // if we can select the gateway, return it + if let Some(gateway) = ln.select_gateway(&gateway.info.gateway_id).await { + return Some(gateway); + } } // if no vetted gateway found, try to find a gateway with reasonable fees let fees = gateway.info.fees; if fees.base_msat >= 1_000 && fees.proportional_millionths >= 100 { - gateway_id = Some(gateway.info.gateway_id); - } - } - - if let Some(gateway_id) = gateway_id { - if let Some(gateway) = ln.select_gateway(&gateway_id).await { - return Some(gateway); + if let Some(g) = ln.select_gateway(&gateway.info.gateway_id).await { + selected_gateway = Some(g); + } } } - None + selected_gateway } From 9826a8b37f7f4cbb3aee5c54d3e18928b7919655 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 26 Mar 2024 16:16:36 -0500 Subject: [PATCH 2/4] Always update gateway cache before selecting gateway --- src/mint.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/mint.rs b/src/mint.rs index 0a88942..37a94b7 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -51,6 +51,12 @@ impl MultiMintWrapperTrait for MultiMintWrapper { .await .expect("just registered"); + // update gateway cache, so we can find the best gateways + let ln = client.get_first_module::(); + if let Err(e) = ln.update_gateway_cache(true).await { + error!("Failed to update gateway cache: {e}"); + } + if let Some(gateway) = select_gateway(&client).await { self.gateways.write().await.insert(id, gateway); } else { @@ -76,6 +82,12 @@ pub(crate) async fn setup_multimint( // select gateway for each federation for (id, client) in clients.iter() { + // update gateway cache, so we can find the best gateways + let ln = client.get_first_module::(); + if let Err(e) = ln.update_gateway_cache(true).await { + error!("Failed to update gateway cache: {e}"); + } + match select_gateway(client).await { Some(gateway) => { gateways.insert(*id, gateway); From 447bd35615027f5229673f58905b1c6d6af5e81b Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 26 Mar 2024 16:19:15 -0500 Subject: [PATCH 3/4] Remove gateway cache --- src/lnurlp.rs | 2 +- src/mint.rs | 17 ++++------------- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/lnurlp.rs b/src/lnurlp.rs index f15fd87..d7d3421 100644 --- a/src/lnurlp.rs +++ b/src/lnurlp.rs @@ -105,7 +105,7 @@ pub async fn lnurl_callback( let gateway = state .mm - .get_gateway(&federation_id) + .get_gateway(federation_id) .await .ok_or(anyhow!("Not gateway configured for federation"))?; diff --git a/src/mint.rs b/src/mint.rs index 37a94b7..fc27f0a 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -18,14 +18,12 @@ pub(crate) trait MultiMintWrapperTrait { async fn check_has_federation(&self, id: FederationId) -> bool; async fn get_federation_client(&self, id: FederationId) -> Option; async fn register_new_federation(&self, invite_code: InviteCode) -> anyhow::Result<()>; - async fn get_gateway(&self, id: &FederationId) -> Option; + async fn get_gateway(&self, id: FederationId) -> Option; } #[derive(Clone)] struct MultiMintWrapper { fm: Arc>, - /// Our preferred lightning gateway for each federation - gateways: Arc>>, } #[async_trait] @@ -57,18 +55,12 @@ impl MultiMintWrapperTrait for MultiMintWrapper { error!("Failed to update gateway cache: {e}"); } - if let Some(gateway) = select_gateway(&client).await { - self.gateways.write().await.insert(id, gateway); - } else { - error!("No suitable gateway found for federation {id}"); - } - Ok(()) } - async fn get_gateway(&self, id: &FederationId) -> Option { - let lock = self.gateways.read().await; - lock.get(id).cloned() + async fn get_gateway(&self, id: FederationId) -> Option { + let client = self.get_federation_client(id).await?; + select_gateway(&client).await } } @@ -101,7 +93,6 @@ pub(crate) async fn setup_multimint( let mmw = MultiMintWrapper { fm: Arc::new(RwLock::new(mm)), - gateways: Arc::new(RwLock::new(HashMap::new())), }; Ok(Arc::new(mmw)) From ea7e47376bd1c72bb8d9722e6b585b2ce9c706c2 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 26 Mar 2024 16:24:55 -0500 Subject: [PATCH 4/4] Update gateway cache every hour --- src/lnurlp.rs | 7 +++---- src/mint.rs | 27 ++++++++++++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/lnurlp.rs b/src/lnurlp.rs index d7d3421..4277ce8 100644 --- a/src/lnurlp.rs +++ b/src/lnurlp.rs @@ -2,6 +2,7 @@ use std::str::FromStr; use crate::{ invoice::{spawn_invoice_subscription, InvoiceState}, + mint::select_gateway, models::{invoice::NewInvoice, zaps::NewZap}, routes::{LnurlCallbackParams, LnurlCallbackResponse, LnurlVerifyResponse}, State, @@ -103,11 +104,9 @@ pub async fn lnurl_callback( let invoice_index = user.invoice_index; - let gateway = state - .mm - .get_gateway(federation_id) + let gateway = select_gateway(&client) .await - .ok_or(anyhow!("Not gateway configured for federation"))?; + .ok_or(anyhow!("No gateway found for federation"))?; let (op_id, pr, preimage) = ln .create_bolt11_invoice_for_user_tweaked( diff --git a/src/mint.rs b/src/mint.rs index fc27f0a..5fb1e45 100644 --- a/src/mint.rs +++ b/src/mint.rs @@ -5,6 +5,7 @@ use fedimint_ln_client::LightningClientModule; use fedimint_ln_common::LightningGateway; use log::error; use std::collections::HashMap; +use std::time::Duration; use std::{path::PathBuf, sync::Arc}; use tokio::sync::RwLock; @@ -18,7 +19,6 @@ pub(crate) trait MultiMintWrapperTrait { async fn check_has_federation(&self, id: FederationId) -> bool; async fn get_federation_client(&self, id: FederationId) -> Option; async fn register_new_federation(&self, invite_code: InviteCode) -> anyhow::Result<()>; - async fn get_gateway(&self, id: FederationId) -> Option; } #[derive(Clone)] @@ -57,11 +57,6 @@ impl MultiMintWrapperTrait for MultiMintWrapper { Ok(()) } - - async fn get_gateway(&self, id: FederationId) -> Option { - let client = self.get_federation_client(id).await?; - select_gateway(&client).await - } } pub(crate) async fn setup_multimint( @@ -95,7 +90,25 @@ pub(crate) async fn setup_multimint( fm: Arc::new(RwLock::new(mm)), }; - Ok(Arc::new(mmw)) + let mmw = Arc::new(mmw); + + // spawn thread to update gateways periodically, check every hour + let mmw_clone = mmw.clone(); + tokio::spawn(async move { + loop { + tokio::time::sleep(Duration::from_secs(60 * 60)).await; + let mm = mmw_clone.fm.read().await; + let clients = mm.clients.lock().await; + for (_, client) in clients.iter() { + let ln = client.get_first_module::(); + if let Err(e) = ln.update_gateway_cache(true).await { + error!("Failed to update gateway cache: {e}"); + } + } + } + }); + + Ok(mmw) } pub(crate) async fn select_gateway(client: &ClientHandleArc) -> Option {