Skip to content

Commit

Permalink
Merge pull request #9 from MutinyWallet/gateway-fixes
Browse files Browse the repository at this point in the history
Recheck for gateways if there isn't one saved
  • Loading branch information
TonyGiorgio authored Mar 26, 2024
2 parents cc2ff73 + ea7e473 commit b143fea
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 29 deletions.
7 changes: 3 additions & 4 deletions src/lnurlp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
64 changes: 39 additions & 25 deletions src/mint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -18,14 +19,11 @@ pub(crate) trait MultiMintWrapperTrait {
async fn check_has_federation(&self, id: FederationId) -> bool;
async fn get_federation_client(&self, id: FederationId) -> Option<ClientHandleArc>;
async fn register_new_federation(&self, invite_code: InviteCode) -> anyhow::Result<()>;
async fn get_gateway(&self, id: &FederationId) -> Option<LightningGateway>;
}

#[derive(Clone)]
struct MultiMintWrapper {
fm: Arc<RwLock<MultiMint>>,
/// Our preferred lightning gateway for each federation
gateways: Arc<RwLock<HashMap<FederationId, LightningGateway>>>,
}

#[async_trait]
Expand All @@ -51,19 +49,14 @@ impl MultiMintWrapperTrait for MultiMintWrapper {
.await
.expect("just registered");

if let Some(gateway) = select_gateway(&client).await {
self.gateways.write().await.insert(id, gateway);
} else {
error!("No suitable gateway found for federation {id}");
// update gateway cache, so we can find the best gateways
let ln = client.get_first_module::<LightningClientModule>();
if let Err(e) = ln.update_gateway_cache(true).await {
error!("Failed to update gateway cache: {e}");
}

Ok(())
}

async fn get_gateway(&self, id: &FederationId) -> Option<LightningGateway> {
let lock = self.gateways.read().await;
lock.get(id).cloned()
}
}

pub(crate) async fn setup_multimint(
Expand All @@ -76,6 +69,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::<LightningClientModule>();
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);
Expand All @@ -89,34 +88,49 @@ 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))
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::<LightningClientModule>();
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<LightningGateway> {
let ln = client.get_first_module::<LightningClientModule>();
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
}

0 comments on commit b143fea

Please sign in to comment.