From e4408b5d7fef29a614f4dd9541c203fb2eb23ae3 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Fri, 27 Oct 2023 18:02:35 -0500 Subject: [PATCH] try to get m2m w/ jeff --- mutiny-core/src/ldkstorage.rs | 19 ++-- mutiny-core/src/lib.rs | 1 + mutiny-core/src/node.rs | 51 +++++------ mutiny-core/src/nodemanager.rs | 2 + mutiny-core/src/router.rs | 162 +++++++++++++++++++++++++++++++++ mutiny-wasm/src/models.rs | 2 + 6 files changed, 201 insertions(+), 36 deletions(-) create mode 100644 mutiny-core/src/router.rs diff --git a/mutiny-core/src/ldkstorage.rs b/mutiny-core/src/ldkstorage.rs index d3f4fb96e..d044df568 100644 --- a/mutiny-core/src/ldkstorage.rs +++ b/mutiny-core/src/ldkstorage.rs @@ -5,9 +5,10 @@ use crate::gossip::PROB_SCORER_KEY; use crate::keymanager::PhantomKeysManager; use crate::logging::MutinyLogger; use crate::multiesplora::MultiEsploraClient; +use crate::node::NetworkGraph; use crate::node::{default_user_config, ChainMonitor}; -use crate::node::{NetworkGraph, Router}; use crate::nodemanager::ChannelClosure; +use crate::router::MutinyRouter; use crate::storage::{MutinyStorage, VersionedValue}; use crate::utils; use crate::utils::{sleep, spawn}; @@ -53,7 +54,7 @@ pub(crate) type PhantomChannelManager = LdkChannelManager< Arc>, Arc>, Arc>, - Arc, + Arc, Arc, >; @@ -202,7 +203,7 @@ impl MutinyNodePersister { fee_estimator: Arc>, mutiny_logger: Arc, keys_manager: Arc>, - router: Arc, + router: Arc, channel_monitors: Vec<(BlockHash, ChannelMonitor)>, esplora: &MultiEsploraClient, ) -> Result, MutinyError> { @@ -270,7 +271,7 @@ impl MutinyNodePersister { fee_estimator: Arc>, mutiny_logger: Arc, keys_manager: Arc>, - router: Arc, + router: Arc, mut channel_monitors: Vec<(BlockHash, ChannelMonitor)>, ) -> Result, MutinyError> { let mut channel_monitor_mut_references = Vec::new(); @@ -312,7 +313,7 @@ impl MutinyNodePersister { fee_estimator: Arc>, mutiny_logger: Arc, keys_manager: Arc>, - router: Arc, + router: Arc, channel_monitors: Vec<(BlockHash, ChannelMonitor)>, esplora: &MultiEsploraClient, ) -> Result, MutinyError> { @@ -375,7 +376,7 @@ impl MutinyNodePersister { logger: &MutinyLogger, ) -> Option { let key = self.get_key(payment_key(inbound, payment_hash).as_str()); - log_trace!(logger, "Trace: checking payment key: {key}"); + // log_trace!(logger, "Trace: checking payment key: {key}"); let deserialized_value: Result, MutinyError> = self.storage.get_data(key); deserialized_value.ok().flatten() @@ -619,7 +620,7 @@ impl Arc>, Arc>, Arc>, - Arc, + Arc, Arc, utils::Mutex, > for MutinyNodePersister @@ -744,6 +745,7 @@ pub(crate) async fn persist_monitor( #[cfg(test)] mod test { use crate::onchain::OnChainWallet; + use crate::router::MutinyRouter; use crate::storage::MemoryStorage; use crate::{esplora::EsploraSyncClient, node::scoring_params}; use crate::{ @@ -967,8 +969,9 @@ mod test { persister.clone(), )); - let router: Arc = Arc::new(DefaultRouter::new( + let router: Arc = Arc::new(MutinyRouter::new( network_graph, + None, logger.clone(), km.clone().get_secure_random_bytes(), Arc::new(utils::Mutex::new(scorer)), diff --git a/mutiny-core/src/lib.rs b/mutiny-core/src/lib.rs index c5b85f374..eb07d9e71 100644 --- a/mutiny-core/src/lib.rs +++ b/mutiny-core/src/lib.rs @@ -40,6 +40,7 @@ pub mod storage; mod subscription; pub mod vss; +mod router; #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; pub mod utils; diff --git a/mutiny-core/src/node.rs b/mutiny-core/src/node.rs index 77bf5a79f..53d27e749 100644 --- a/mutiny-core/src/node.rs +++ b/mutiny-core/src/node.rs @@ -39,6 +39,7 @@ use lightning::{ use crate::multiesplora::MultiEsploraClient; use crate::peermanager::LspMessageRouter; +use crate::router::MutinyRouter; use crate::utils::get_monitor_version; use bitcoin::util::bip32::ExtendedPrivKey; use futures_util::lock::Mutex; @@ -59,7 +60,7 @@ use lightning::{ routing::{ gossip, gossip::NodeId, - router::{DefaultRouter, PaymentParameters, RouteParameters}, + router::{PaymentParameters, RouteParameters}, }, util::{ config::{ChannelHandshakeConfig, ChannelHandshakeLimits, UserConfig}, @@ -122,14 +123,6 @@ pub(crate) type ChainMonitor = chainmonitor::ChainMonitor< Arc>, >; -pub(crate) type Router = DefaultRouter< - Arc, - Arc, - Arc>, - ProbabilisticScoringFeeParameters, - HubPreferentialScorer, ->; - #[derive(Clone, Debug, Eq, PartialEq)] pub enum ConnectionType { Tcp(String), @@ -251,8 +244,27 @@ impl Node { let network_graph = gossip_sync.network_graph().clone(); - let router: Arc = Arc::new(DefaultRouter::new( + log_info!(logger, "creating lsp client"); + let lsp_client: Option = match node_index.lsp { + None => { + if lsp_clients.is_empty() { + log_info!(logger, "no lsp saved and no lsp clients available"); + None + } else { + log_info!(logger, "no lsp saved, picking random one"); + // If we don't have an lsp saved we should pick a random + // one from our client list and save it for next time + let rand = rand::random::() % lsp_clients.len(); + Some(lsp_clients[rand].clone()) + } + } + Some(ref lsp) => lsp_clients.iter().find(|c| &c.url == lsp).cloned(), + }; + let lsp_pubkey = lsp_client.as_ref().map(|l| l.pubkey); + + let router: Arc = Arc::new(MutinyRouter::new( network_graph, + lsp_pubkey, logger.clone(), keys_manager.clone().get_secure_random_bytes(), scorer.clone(), @@ -328,24 +340,7 @@ impl Node { logger: logger.clone(), }); - log_info!(logger, "creating lsp client"); - let lsp_client: Option = match node_index.lsp { - None => { - if lsp_clients.is_empty() { - log_info!(logger, "no lsp saved and no lsp clients available"); - None - } else { - log_info!(logger, "no lsp saved, picking random one"); - // If we don't have an lsp saved we should pick a random - // one from our client list and save it for next time - let rand = rand::random::() % lsp_clients.len(); - Some(lsp_clients[rand].clone()) - } - } - Some(ref lsp) => lsp_clients.iter().find(|c| &c.url == lsp).cloned(), - }; - - let message_router = Arc::new(LspMessageRouter::new(lsp_client.as_ref().map(|l| l.pubkey))); + let message_router = Arc::new(LspMessageRouter::new(lsp_pubkey)); let onion_message_handler = Arc::new(OnionMessenger::new( keys_manager.clone(), keys_manager.clone(), diff --git a/mutiny-core/src/nodemanager.rs b/mutiny-core/src/nodemanager.rs index 14f7005fb..617a6daf5 100644 --- a/mutiny-core/src/nodemanager.rs +++ b/mutiny-core/src/nodemanager.rs @@ -326,6 +326,7 @@ pub struct MutinyChannel { pub peer: PublicKey, pub confirmations_required: Option, pub confirmations: u32, + pub scid: Option, } impl From<&ChannelDetails> for MutinyChannel { @@ -339,6 +340,7 @@ impl From<&ChannelDetails> for MutinyChannel { peer: c.counterparty.node_id, confirmations_required: c.confirmations_required, confirmations: c.confirmations.unwrap_or(0), + scid: c.inbound_scid_alias, } } } diff --git a/mutiny-core/src/router.rs b/mutiny-core/src/router.rs new file mode 100644 index 000000000..e6c7a6f06 --- /dev/null +++ b/mutiny-core/src/router.rs @@ -0,0 +1,162 @@ +use crate::logging::MutinyLogger; +use crate::node::NetworkGraph; +use crate::scorer::HubPreferentialScorer; +use crate::utils::Mutex; +use bitcoin::secp256k1::PublicKey; +use lightning::ln::channelmanager::ChannelDetails; +use lightning::ln::features::ChannelFeatures; +use lightning::ln::msgs::LightningError; +use lightning::routing::gossip::NodeId; +use lightning::routing::router::{ + BlindedTail, DefaultRouter, InFlightHtlcs, Path, Payee, Route, RouteHop, RouteParameters, + Router, +}; +use lightning::routing::scoring::ProbabilisticScoringFeeParameters; +use lightning::util::ser::Writeable; +use log::{info, warn}; +use std::sync::Arc; + +type LdkRouter = DefaultRouter< + Arc, + Arc, + Arc>, + ProbabilisticScoringFeeParameters, + HubPreferentialScorer, +>; + +pub struct MutinyRouter { + network_graph: Arc, + lsp_key: Option, + router: LdkRouter, +} + +impl MutinyRouter { + pub fn new( + network_graph: Arc, + lsp_key: Option, + logger: Arc, + random_seed_bytes: [u8; 32], + scorer: Arc>, + score_params: ProbabilisticScoringFeeParameters, + ) -> Self { + let router = DefaultRouter::new( + network_graph.clone(), + logger, + random_seed_bytes, + scorer, + score_params, + ); + + Self { + network_graph, + lsp_key, + router, + } + } +} + +impl Router for MutinyRouter { + fn find_route( + &self, + payer: &PublicKey, + route_params: &RouteParameters, + first_hops: Option<&[&ChannelDetails]>, + inflight_htlcs: InFlightHtlcs, + ) -> Result { + match &route_params.payment_params.payee { + Payee::Clear { .. } => { + self.router + .find_route(payer, route_params, first_hops, inflight_htlcs) + } + Payee::Blinded { + route_hints, + features: _, + } => { + // if we have no LSP, then handle normally + if self.lsp_key.is_none() { + return self + .router + .find_route(payer, route_params, first_hops, inflight_htlcs); + } + + let (blinded_info, blinded_path) = route_hints.first().unwrap(); + let graph_lock = self.network_graph.read_only(); + let lsp_node_id = NodeId::from_pubkey(&self.lsp_key.unwrap()); + let node_info = graph_lock.node(&lsp_node_id).unwrap(); + + let amt = route_params.final_value_msat; + + // first our channel with enough capacity + let first_hops = first_hops.unwrap_or(&[]); + let first = first_hops + .iter() + .find_map(|c| { + if c.outbound_capacity_msat >= amt { + Some(c) + } else { + None + } + }) + .unwrap(); + + let channel_features = + ChannelFeatures::from_be_bytes(first.counterparty.features.encode()); + + let scid = scid_from_parts(467591, 1, 0); + warn!("scid: {}", scid); + + let cltv_expiry_delta = first.config.unwrap().cltv_expiry_delta; + let hops = vec![ + RouteHop { + pubkey: self.lsp_key.unwrap(), + node_features: node_info + .announcement_info + .as_ref() + .unwrap() + .features + .clone(), + short_channel_id: first.get_outbound_payment_scid().unwrap(), + channel_features: channel_features.clone(), + fee_msat: 0, // 0 for own channel + cltv_expiry_delta: 0, // 0 for own channel + maybe_announced_channel: false, + }, + RouteHop { + pubkey: blinded_path.introduction_node_id, + node_features: node_info + .announcement_info + .as_ref() + .unwrap() + .features + .clone(), + short_channel_id: 17112782831943311000, // fixme + channel_features, + fee_msat: 10_000, // put high value just to try + cltv_expiry_delta: cltv_expiry_delta as u32, + maybe_announced_channel: false, + }, + ]; + + let blinded_tail = Some(BlindedTail { + hops: blinded_path.blinded_hops.clone(), + blinding_point: blinded_path.blinding_point, + excess_final_cltv_expiry_delta: blinded_info.cltv_expiry_delta as u32, + final_value_msat: amt, + }); + + let path = Path { hops, blinded_tail }; + + Ok(Route { + paths: vec![path], + route_params: Some(route_params.clone()), + }) + } + } + } +} + +/// Constructs a `short_channel_id` using the components pieces. Results in an error +/// if the block height, tx index, or vout index overflow the maximum sizes. +pub fn scid_from_parts(block: u64, tx_index: u64, vout_index: u64) -> u64 { + (block << 40) | (tx_index << 16) | vout_index +} diff --git a/mutiny-wasm/src/models.rs b/mutiny-wasm/src/models.rs index e4071ce4d..60c0eae14 100644 --- a/mutiny-wasm/src/models.rs +++ b/mutiny-wasm/src/models.rs @@ -261,6 +261,7 @@ pub struct MutinyChannel { peer: String, pub confirmations_required: Option, pub confirmations: u32, + pub scid: Option, } #[wasm_bindgen] @@ -299,6 +300,7 @@ impl From for MutinyChannel { peer: m.peer.to_hex(), confirmations_required: m.confirmations_required, confirmations: m.confirmations, + scid: m.scid, } } }