Skip to content
This repository was archived by the owner on Feb 3, 2025. It is now read-only.

Start up optimizations grab bag #1017

Merged
merged 6 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions mutiny-core/src/auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ use crate::{
networking::websocket::{SimpleWebSocket, WebSocketImpl},
utils,
};
use async_lock::RwLock;
use jwt_compact::UntrustedToken;
use lightning::util::logger::*;
use lightning::{log_error, log_info};
use lightning::{log_debug, log_error, log_info};
use lnurl::{lnurl::LnUrl, AsyncClient as LnUrlClient};
use reqwest::Client;
use reqwest::{Method, StatusCode, Url};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::str::FromStr;
use std::sync::{Arc, RwLock};
use std::sync::Arc;

#[derive(Debug, PartialEq, Serialize, Deserialize)]
struct CustomClaims {
Expand Down Expand Up @@ -54,8 +55,9 @@ impl MutinyAuthClient {
Ok(())
}

pub fn is_authenticated(&self) -> Option<String> {
if let Some(ref jwt) = *self.jwt.try_read().unwrap() {
pub async fn is_authenticated(&self) -> Option<String> {
let lock = self.jwt.read().await;
if let Some(jwt) = lock.as_ref() {
return Some(jwt.to_string()); // TODO parse and make sure still valid
}
None
Expand Down Expand Up @@ -92,7 +94,7 @@ impl MutinyAuthClient {
) -> Result<reqwest::Response, MutinyError> {
let mut request = self.http_client.request(method, url);

let mut jwt = self.is_authenticated();
let mut jwt = self.is_authenticated().await;
if jwt.is_none() {
jwt = Some(self.retrieve_new_jwt().await?);
}
Expand All @@ -110,6 +112,10 @@ impl MutinyAuthClient {
}

async fn retrieve_new_jwt(&self) -> Result<String, MutinyError> {
// get lock so we don't make multiple requests for the same token
let mut lock = self.jwt.write().await;
log_debug!(self.logger, "Retrieving new JWT token");

let mut url = Url::parse(&self.url).map_err(|_| MutinyError::LnUrlFailure)?;
let ws_scheme = match url.scheme() {
"http" => "ws",
Expand Down Expand Up @@ -165,7 +171,7 @@ impl MutinyAuthClient {
};

log_info!(self.logger, "Retrieved new JWT token");
*self.jwt.try_write()? = Some(jwt.clone());
*lock = Some(jwt.clone());
Ok(jwt)
}
}
Expand Down Expand Up @@ -201,7 +207,7 @@ mod tests {

// Test authenticate method
match auth_client.authenticate().await {
Ok(_) => assert!(auth_client.is_authenticated().is_some()),
Ok(_) => assert!(auth_client.is_authenticated().await.is_some()),
Err(e) => panic!("Authentication failed with error: {:?}", e),
};

Expand Down
111 changes: 62 additions & 49 deletions mutiny-core/src/federation.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::utils::spawn;
use crate::{
error::{MutinyError, MutinyStorageError},
event::PaymentInfo,
Expand Down Expand Up @@ -55,11 +56,15 @@ use fedimint_wallet_client::{WalletClientInit, WalletClientModule};
use futures::future::{self};
use futures_util::{pin_mut, StreamExt};
use hex::FromHex;
#[cfg(target_arch = "wasm32")]
use instant::Instant;
use lightning::{
ln::PaymentHash, log_debug, log_error, log_info, log_trace, log_warn, util::logger::Logger,
};
use lightning_invoice::{Bolt11Invoice, RoutingFees};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;
use std::{collections::HashMap, fmt::Debug, sync::Arc};
use std::{
str::FromStr,
Expand Down Expand Up @@ -192,35 +197,39 @@ impl<S: MutinyStorage> FederationClient<S> {
) -> Result<Self, MutinyError> {
log_info!(logger, "initializing a new federation client: {uuid}");

let federation_info = FederationInfo::from_invite_code(federation_code.clone())
.await
.map_err(|e| {
log_error!(logger, "Could not parse invite code: {}", e);
e
})?;

log_debug!(
logger,
"parsed federation invite code: {:?}",
federation_info.invite_code()
);
let federation_id = federation_code.federation_id();

let mut client_builder = fedimint_client::Client::builder();
client_builder.with_module(WalletClientInit(None));
client_builder.with_module(MintClientInit);
client_builder.with_module(LightningClientInit);

log_trace!(logger, "Building fedimint client db");
let fedimint_storage = FedimintStorage::new(
storage.clone(),
federation_info.federation_id().to_string(),
logger.clone(),
)
.await?;
let fedimint_storage =
FedimintStorage::new(storage.clone(), federation_id.to_string(), logger.clone())
.await?;
let db = fedimint_storage.clone().into();

if get_config_from_db(&db).await.is_none() {
client_builder.with_federation_info(federation_info.clone());
let download = Instant::now();
let federation_info = FederationInfo::from_invite_code(federation_code)
.await
.map_err(|e| {
log_error!(logger, "Could not parse invite code: {}", e);
e
})?;
log_trace!(
logger,
"Downloaded federation info in: {}ms",
download.elapsed().as_millis()
);

log_debug!(
logger,
"parsed federation invite code: {:?}",
federation_info.invite_code()
);
client_builder.with_federation_info(federation_info);
}

client_builder.with_database(db);
Expand All @@ -230,10 +239,7 @@ impl<S: MutinyStorage> FederationClient<S> {
let secret = create_federation_secret(xprivkey, network)?;

let fedimint_client = client_builder
.build(get_default_client_secret(
&secret,
&federation_info.federation_id(),
))
.build(get_default_client_secret(&secret, &federation_id))
.await?;

log_trace!(logger, "Retrieving fedimint wallet client module");
Expand All @@ -249,36 +255,43 @@ impl<S: MutinyStorage> FederationClient<S> {
return Err(MutinyError::NetworkMismatch);
}

// Set active gateway preference
let lightning_module = fedimint_client.get_first_module::<LightningClientModule>();
let gateways = lightning_module
.fetch_registered_gateways()
.await
.map_err(|e| {
log_warn!(
logger,
"Could not fetch gateways from federation {}: {e}",
federation_info.federation_id()
)
});

if let Ok(gateways) = gateways {
if let Some(a) = get_gateway_preference(gateways, fedimint_client.federation_id()) {
log_info!(
logger,
"Setting active gateway for federation {}: {:?}",
federation_info.federation_id(),
a
);
let _ = lightning_module.set_active_gateway(&a).await.map_err(|e| {
// Set active gateway preference in background
let client_clone = fedimint_client.clone();
let logger_clone = logger.clone();
spawn(async move {
let start = Instant::now();
let lightning_module = client_clone.get_first_module::<LightningClientModule>();
let gateways = lightning_module
.fetch_registered_gateways()
.await
.map_err(|e| {
log_warn!(
logger,
"Could not set gateway for federation {}: {e}",
federation_info.federation_id()
logger_clone,
"Could not fetch gateways from federation {federation_id}: {e}",
)
});

if let Ok(gateways) = gateways {
if let Some(a) = get_gateway_preference(gateways, federation_id) {
log_info!(
logger_clone,
"Setting active gateway for federation {federation_id}: {a}"
);
let _ = lightning_module.set_active_gateway(&a).await.map_err(|e| {
log_warn!(
logger_clone,
"Could not set gateway for federation {federation_id}: {e}",
)
});
}
}
}

log_trace!(
logger_clone,
"Setting active gateway took: {}ms",
start.elapsed().as_millis()
);
});

log_debug!(logger, "Built fedimint client");
Ok(FederationClient {
Expand Down
89 changes: 55 additions & 34 deletions mutiny-core/src/gossip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@ use crate::{
};
use bitcoin::hashes::hex::{FromHex, ToHex};
use bitcoin::Network;
#[cfg(target_arch = "wasm32")]
use instant::Instant;
use lightning::ln::msgs::NodeAnnouncement;
use lightning::routing::gossip::NodeId;
use lightning::util::logger::Logger;
use lightning::util::ser::ReadableArgs;
use lightning::{log_debug, log_error, log_info, log_warn};
use lightning::{log_debug, log_error, log_info, log_trace, log_warn};
use reqwest::Client;
use reqwest::{Method, Url};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::str::FromStr;
use std::sync::Arc;
#[cfg(not(target_arch = "wasm32"))]
use std::time::Instant;

use crate::logging::MutinyLogger;
use crate::node::{NetworkGraph, RapidGossipSync};
Expand Down Expand Up @@ -105,7 +109,7 @@ pub struct Scorer {
pub value: String,
}

pub async fn get_remote_scorer_bytes(
async fn get_remote_scorer_bytes(
auth_client: &MutinyAuthClient,
base_url: &str,
) -> Result<Vec<u8>, MutinyError> {
Expand All @@ -126,6 +130,29 @@ pub async fn get_remote_scorer_bytes(
Ok(decoded)
}

/// Gets the remote scorer from the server, parses it and returns it as a [`HubPreferentialScorer`]
pub async fn get_remote_scorer(
auth_client: &MutinyAuthClient,
base_url: &str,
network_graph: Arc<NetworkGraph>,
logger: Arc<MutinyLogger>,
) -> Result<HubPreferentialScorer, MutinyError> {
let start = Instant::now();
let scorer_bytes = get_remote_scorer_bytes(auth_client, base_url).await?;
let mut readable_bytes = lightning::io::Cursor::new(scorer_bytes);
let params = decay_params();
let args = (params, network_graph, logger.clone());
let scorer = ProbScorer::read(&mut readable_bytes, args)?;

log_trace!(
logger,
"Retrieved remote scorer in {}ms",
start.elapsed().as_millis()
);

Ok(HubPreferentialScorer::new(scorer))
}

fn write_gossip_data(
storage: &impl MutinyStorage,
last_sync_timestamp: u32,
Expand All @@ -142,9 +169,7 @@ fn write_gossip_data(
}

pub async fn get_gossip_sync(
_storage: &impl MutinyStorage,
remote_scorer_url: Option<String>,
auth_client: Option<Arc<MutinyAuthClient>>,
storage: &impl MutinyStorage,
network: Network,
logger: Arc<MutinyLogger>,
) -> Result<(RapidGossipSync, HubPreferentialScorer), MutinyError> {
Expand All @@ -158,37 +183,28 @@ pub async fn get_gossip_sync(
gossip_data.last_sync_timestamp
);

let start = Instant::now();

// get network graph
let gossip_sync = RapidGossipSync::new(gossip_data.network_graph.clone(), logger.clone());

// Try to get remote scorer if remote_scorer_url and auth_client are available
if let (Some(url), Some(client)) = (remote_scorer_url, &auth_client) {
match get_remote_scorer_bytes(client, &url).await {
Ok(scorer_bytes) => {
let mut readable_bytes = lightning::io::Cursor::new(scorer_bytes);
let params = decay_params();
let args = (
params,
Arc::clone(&gossip_data.network_graph),
Arc::clone(&logger),
);
if let Ok(remote_scorer) = ProbScorer::read(&mut readable_bytes, args) {
log_debug!(logger, "retrieved remote scorer");
let remote_scorer = HubPreferentialScorer::new(remote_scorer);
gossip_data.scorer = Some(remote_scorer);
} else {
log_error!(
logger,
"failed to parse remote scorer, keeping the local one"
);
}
}
Err(_) => {
log_error!(
logger,
"failed to retrieve remote scorer, keeping the local one"
);
}
let scorer_hex: Option<String> = storage.get_data(PROB_SCORER_KEY)?;

if let Some(hex) = scorer_hex {
let scorer_bytes: Vec<u8> = Vec::from_hex(&hex)?;
let mut readable_bytes = lightning::io::Cursor::new(scorer_bytes);
let params = decay_params();
let args = (
params,
Arc::clone(&gossip_data.network_graph),
Arc::clone(&logger),
);
if let Ok(scorer) = ProbScorer::read(&mut readable_bytes, args) {
log_debug!(logger, "retrieved local scorer");
let scorer = HubPreferentialScorer::new(scorer);
gossip_data.scorer = Some(scorer);
} else {
log_error!(logger, "failed to parse local scorer");
}
}

Expand All @@ -201,6 +217,11 @@ pub async fn get_gossip_sync(
}
};

log_trace!(
&logger,
"Gossip sync/Scorer initialized in {}ms",
start.elapsed().as_millis()
);
Ok((gossip_sync, prob_scorer))
}

Expand Down Expand Up @@ -550,7 +571,7 @@ mod test {
let storage = MemoryStorage::default();

let logger = Arc::new(MutinyLogger::default());
let _gossip_sync = get_gossip_sync(&storage, None, None, Network::Regtest, logger.clone())
let _gossip_sync = get_gossip_sync(&storage, Network::Regtest, logger.clone())
.await
.unwrap();

Expand Down
Loading
Loading