Skip to content
Draft
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
39 changes: 14 additions & 25 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ bip21 = { version = "0.5", features = ["std"], default-features = false }
base64 = { version = "0.22.1", default-features = false, features = ["std"] }
getrandom = { version = "0.3", default-features = false }
chrono = { version = "0.4", default-features = false, features = ["clock"] }
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros", "net" ] }
tokio = { version = "1.37", default-features = false, features = [ "rt-multi-thread", "time", "sync", "macros" ] }
esplora-client = { version = "0.12", default-features = false, features = ["tokio", "async-https-rustls"] }
electrum-client = { version = "0.24.0", default-features = false, features = ["proxy", "use-rustls-ring"] }
libc = "0.2"
Expand All @@ -79,7 +79,7 @@ async-trait = { version = "0.1", default-features = false }
vss-client = { package = "vss-client-ng", version = "0.5" }
prost = { version = "0.11.6", default-features = false}
#bitcoin-payment-instructions = { version = "0.6" }
bitcoin-payment-instructions = { git = "https://github.com/joostjager/bitcoin-payment-instructions", branch = "ldk-dcf0c203e166da2348bef12b2e5eff4a250cdec7" }
bitcoin-payment-instructions = { git = "https://github.com/jkczyz/bitcoin-payment-instructions", rev = "0138feb7acefb1e49102a6fb46d7b776bf43265e" }

[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3", features = ["winbase"] }
Expand Down Expand Up @@ -157,30 +157,19 @@ harness = false
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", branch = "main" }

#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
#lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "21e9a9c0ef80021d0669f2a366f55d08ba8d9b03" }
[patch."https://github.com/lightningdevkit/rust-lightning"]
lightning = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-types = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-invoice = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-net-tokio = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-persister = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-background-processor = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-rapid-gossip-sync = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-block-sync = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-transaction-sync = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-liquidity = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }
lightning-macros = { git = "https://github.com/tnull/rust-lightning", rev = "733d3f25cd29cc9b114d3df2c9b0484dc73dbb8c" }

#vss-client-ng = { path = "../vss-client" }
#vss-client-ng = { git = "https://github.com/lightningdevkit/vss-client", branch = "main" }
#
#[patch."https://github.com/lightningdevkit/rust-lightning"]
#lightning = { path = "../rust-lightning/lightning" }
#lightning-types = { path = "../rust-lightning/lightning-types" }
#lightning-invoice = { path = "../rust-lightning/lightning-invoice" }
#lightning-net-tokio = { path = "../rust-lightning/lightning-net-tokio" }
#lightning-persister = { path = "../rust-lightning/lightning-persister" }
#lightning-background-processor = { path = "../rust-lightning/lightning-background-processor" }
#lightning-rapid-gossip-sync = { path = "../rust-lightning/lightning-rapid-gossip-sync" }
#lightning-block-sync = { path = "../rust-lightning/lightning-block-sync" }
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
16 changes: 11 additions & 5 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ use lightning::util::persist::{
};
use lightning::util::ser::ReadableArgs;
use lightning::util::sweep::OutputSweeper;
use lightning_liquidity::lsps2::router::LSPS2BOLT12Router;
use lightning_persister::fs_store::v1::FilesystemStore;
use vss_client::headers::VssHeaderProvider;

Expand Down Expand Up @@ -77,7 +78,7 @@ use crate::runtime::{Runtime, RuntimeSpawner};
use crate::tx_broadcaster::TransactionBroadcaster;
use crate::types::{
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreRef, DynStoreWrapper,
GossipSync, Graph, KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager,
GossipSync, Graph, InnerMessageRouter, KeysManager, OnionMessenger, PaymentStore, PeerManager,
PendingPaymentStore, SyncAndAsyncKVStore,
};
use crate::wallet::persist::KVStoreWalletPersister;
Expand Down Expand Up @@ -1622,13 +1623,16 @@ fn build_with_store_internal(
}

let scoring_fee_params = ProbabilisticScoringFeeParameters::default();
let router = Arc::new(DefaultRouter::new(
let inner_router = DefaultRouter::new(
Arc::clone(&network_graph),
Arc::clone(&logger),
Arc::clone(&keys_manager),
Arc::clone(&scorer),
scoring_fee_params,
));
);
let inner_message_router =
InnerMessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager));
let router = Arc::new(LSPS2BOLT12Router::new(inner_router, Arc::clone(&keys_manager)));

let mut user_config = default_user_config(&config);

Expand Down Expand Up @@ -1656,8 +1660,7 @@ fn build_with_store_internal(
}
}

let message_router =
Arc::new(MessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager)));
let message_router = Arc::new(inner_message_router);

// Initialize the ChannelManager
let channel_manager = {
Expand Down Expand Up @@ -1791,6 +1794,7 @@ fn build_with_store_internal(
Arc::clone(&wallet),
Arc::clone(&channel_manager),
Arc::clone(&keys_manager),
Arc::clone(&router),
Arc::clone(&tx_broadcaster),
Arc::clone(&kv_store),
Arc::clone(&config),
Expand Down Expand Up @@ -1828,6 +1832,8 @@ fn build_with_store_internal(

let liquidity_source = runtime
.block_on(async move { liquidity_source_builder.build().await.map(Arc::new) })?;
// TODO: Rehydrate persisted intercept SCID -> LSPS2Bolt12InvoiceParameters mappings here
// for client nodes and call `router.register_intercept_scid(...)` before startup completes.
let custom_message_handler =
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
(Some(liquidity_source), custom_message_handler)
Expand Down
21 changes: 15 additions & 6 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1653,15 +1653,24 @@ where

self.bump_tx_event_handler.handle_event(&bte).await;
},
LdkEvent::OnionMessageIntercepted { peer_node_id, message } => {
if let Some(om_mailbox) = self.om_mailbox.as_ref() {
om_mailbox.onion_message_intercepted(peer_node_id, message);
} else {
LdkEvent::OnionMessageIntercepted { next_hop, message } => match next_hop {
lightning::blinded_path::message::NextMessageHop::NodeId(peer_node_id) => {
if let Some(om_mailbox) = self.om_mailbox.as_ref() {
om_mailbox.onion_message_intercepted(peer_node_id, message);
} else {
log_trace!(
self.logger,
"Onion message intercepted, but no onion message mailbox available"
);
}
},
lightning::blinded_path::message::NextMessageHop::ShortChannelId(scid) => {
log_trace!(
self.logger,
"Onion message intercepted, but no onion message mailbox available"
"Onion message intercepted for unknown SCID {}, ignoring",
scid
);
}
},
},
LdkEvent::OnionMessagePeerConnected { peer_node_id } => {
if let Some(om_mailbox) = self.om_mailbox.as_ref() {
Expand Down
8 changes: 8 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,9 +901,13 @@ impl Node {
#[cfg(not(feature = "uniffi"))]
pub fn bolt12_payment(&self) -> Bolt12Payment {
Bolt12Payment::new(
Arc::clone(&self.runtime),
Arc::clone(&self.channel_manager),
Arc::clone(&self.connection_manager),
self.liquidity_source.clone(),
Arc::clone(&self.keys_manager),
Arc::clone(&self.payment_store),
Arc::clone(&self.peer_store),
Arc::clone(&self.config),
Arc::clone(&self.is_running),
Arc::clone(&self.logger),
Expand All @@ -917,9 +921,13 @@ impl Node {
#[cfg(feature = "uniffi")]
pub fn bolt12_payment(&self) -> Arc<Bolt12Payment> {
Arc::new(Bolt12Payment::new(
Arc::clone(&self.runtime),
Arc::clone(&self.channel_manager),
Arc::clone(&self.connection_manager),
self.liquidity_source.clone(),
Arc::clone(&self.keys_manager),
Arc::clone(&self.payment_store),
Arc::clone(&self.peer_store),
Arc::clone(&self.config),
Arc::clone(&self.is_running),
Arc::clone(&self.logger),
Expand Down
115 changes: 110 additions & 5 deletions src/liquidity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use lightning_liquidity::lsps1::msgs::{
use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
use lightning_liquidity::lsps2::event::{LSPS2ClientEvent, LSPS2ServiceEvent};
use lightning_liquidity::lsps2::msgs::{LSPS2OpeningFeeParams, LSPS2RawOpeningFeeParams};
use lightning_liquidity::lsps2::router::LSPS2Bolt12InvoiceParameters;
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
use lightning_liquidity::lsps2::utils::compute_opening_fee;
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
Expand All @@ -43,14 +44,15 @@ use crate::connection::ConnectionManager;
use crate::logger::{log_debug, log_error, log_info, LdkLogger, Logger};
use crate::runtime::Runtime;
use crate::types::{
Broadcaster, ChannelManager, DynStore, KeysManager, LiquidityManager, PeerManager, Wallet,
Broadcaster, ChannelManager, DynStore, KeysManager, LiquidityManager, PeerManager, Router,
Wallet,
};
use crate::{total_anchor_channels_reserve_sats, Config, Error};

const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;

const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u16 = 72;

struct LSPS1Client {
lsp_node_id: PublicKey,
Expand Down Expand Up @@ -153,6 +155,7 @@ where
lsps2_service: Option<LSPS2Service>,
wallet: Arc<Wallet>,
channel_manager: Arc<ChannelManager>,
router: Arc<Router>,
keys_manager: Arc<KeysManager>,
tx_broadcaster: Arc<Broadcaster>,
kv_store: Arc<DynStore>,
Expand All @@ -166,7 +169,8 @@ where
{
pub(crate) fn new(
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>, config: Arc<Config>, logger: L,
router: Arc<Router>, tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>,
config: Arc<Config>, logger: L,
) -> Self {
let lsps1_client = None;
let lsps2_client = None;
Expand All @@ -177,6 +181,7 @@ where
lsps2_service,
wallet,
channel_manager,
router,
keys_manager,
tx_broadcaster,
kv_store,
Expand Down Expand Up @@ -272,6 +277,7 @@ where
lsps2_service: self.lsps2_service,
wallet: self.wallet,
channel_manager: self.channel_manager,
router: self.router,
peer_manager: RwLock::new(None),
keys_manager: self.keys_manager,
liquidity_manager,
Expand All @@ -290,6 +296,7 @@ where
lsps2_service: Option<LSPS2Service>,
wallet: Arc<Wallet>,
channel_manager: Arc<ChannelManager>,
router: Arc<Router>,
peer_manager: RwLock<Option<Weak<PeerManager>>>,
keys_manager: Arc<KeysManager>,
liquidity_manager: Arc<LiquidityManager>,
Expand Down Expand Up @@ -1190,6 +1197,104 @@ where
Ok((invoice, min_prop_fee_ppm_msat))
}

pub(crate) async fn lsps2_register_bolt12_payment_paths(
&self, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>,
) -> Result<u64, Error> {
let fee_response = self.lsps2_request_opening_fee_params().await?;

let (min_total_fee_msat, min_opening_params) = fee_response
.opening_fee_params_menu
.into_iter()
.filter_map(|params| {
if amount_msat < params.min_payment_size_msat
|| amount_msat > params.max_payment_size_msat
{
log_debug!(self.logger,
"Skipping LSP-offered JIT parameters as the payment of {}msat doesn't meet LSP limits (min: {}msat, max: {}msat)",
amount_msat,
params.min_payment_size_msat,
params.max_payment_size_msat
);
None
} else {
compute_opening_fee(amount_msat, params.min_fee_msat, params.proportional as u64)
.map(|fee| (fee, params))
}
})
.min_by_key(|p| p.0)
.ok_or_else(|| {
log_error!(self.logger, "Failed to handle response from liquidity service",);
Error::LiquidityRequestFailed
})?;

if let Some(max_total_lsp_fee_limit_msat) = max_total_lsp_fee_limit_msat {
if min_total_fee_msat > max_total_lsp_fee_limit_msat {
log_error!(self.logger,
"Failed to request inbound JIT channel as LSP's requested total opening fee of {}msat exceeds our fee limit of {}msat",
min_total_fee_msat, max_total_lsp_fee_limit_msat
);
return Err(Error::LiquidityFeeTooHigh);
}
}

let buy_response =
self.lsps2_send_buy_request(Some(amount_msat), min_opening_params).await?;
self.register_lsps2_bolt12_payment_paths(buy_response)?;

Ok(min_total_fee_msat)
}

pub(crate) async fn lsps2_register_variable_amount_bolt12_payment_paths(
&self, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
) -> Result<u64, Error> {
let fee_response = self.lsps2_request_opening_fee_params().await?;

let (min_prop_fee_ppm_msat, min_opening_params) = fee_response
.opening_fee_params_menu
.into_iter()
.map(|params| (params.proportional as u64, params))
.min_by_key(|p| p.0)
.ok_or_else(|| {
log_error!(self.logger, "Failed to handle response from liquidity service",);
Error::LiquidityRequestFailed
})?;

if let Some(max_proportional_lsp_fee_limit_ppm_msat) =
max_proportional_lsp_fee_limit_ppm_msat
{
if min_prop_fee_ppm_msat > max_proportional_lsp_fee_limit_ppm_msat {
log_error!(self.logger,
"Failed to request inbound JIT channel as LSP's requested proportional opening fee of {} ppm msat exceeds our fee limit of {} ppm msat",
min_prop_fee_ppm_msat,
max_proportional_lsp_fee_limit_ppm_msat
);
return Err(Error::LiquidityFeeTooHigh);
}
}

let buy_response = self.lsps2_send_buy_request(None, min_opening_params).await?;
self.register_lsps2_bolt12_payment_paths(buy_response)?;

Ok(min_prop_fee_ppm_msat)
}

fn register_lsps2_bolt12_payment_paths(
&self, buy_response: LSPS2BuyResponse,
) -> Result<(), Error> {
let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;

self.router.register_intercept_scid(
buy_response.intercept_scid,
LSPS2Bolt12InvoiceParameters {
counterparty_node_id: lsps2_client.lsp_node_id,
intercept_scid: buy_response.intercept_scid,
cltv_expiry_delta: buy_response.cltv_expiry_delta,
},
);

Ok(())
}

async fn lsps2_request_opening_fee_params(&self) -> Result<LSPS2FeeResponse, Error> {
let lsps2_client = self.lsps2_client.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;

Expand Down Expand Up @@ -1302,7 +1407,7 @@ where
src_node_id: lsps2_client.lsp_node_id,
short_channel_id: buy_response.intercept_scid,
fees: RoutingFees { base_msat: 0, proportional_millionths: 0 },
cltv_expiry_delta: buy_response.cltv_expiry_delta as u16,
cltv_expiry_delta: buy_response.cltv_expiry_delta,
htlc_minimum_msat: None,
htlc_maximum_msat: None,
}]);
Expand Down Expand Up @@ -1435,7 +1540,7 @@ pub(crate) struct LSPS2FeeResponse {
#[derive(Debug, Clone)]
pub(crate) struct LSPS2BuyResponse {
intercept_scid: u64,
cltv_expiry_delta: u32,
cltv_expiry_delta: u16,
}

/// A liquidity handler allowing to request channels via the [bLIP-51 / LSPS1] protocol.
Expand Down
Loading