Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
9e44090
lsps2: Move client into module directory
tnull Jul 16, 2026
9be149f
lsps2: Add single-use payment leases
tnull Jul 16, 2026
bb5509b
lsps2: Persist payment leases
tnull Jul 16, 2026
8e092fb
lsps2: Prune stale payment leases
tnull Jul 16, 2026
5695107
lsps2: Cache negotiated payment leases
tnull Jul 16, 2026
01453b1
lsps2: Configure a global fee limit
tnull Jul 21, 2026
19465e2
bolt11: Consume cached LSPS2 leases
tnull Jul 16, 2026
529815a
f Preserve undiscovered LSP leases
tnull Aug 7, 2026
10c4a44
bolt12: Move payment into module directory
tnull Jul 20, 2026
0b0a695
deps: Use invoice MPP response APIs
tnull Jul 21, 2026
f9da978
lsps2: Persist lease cache targets
tnull Jul 21, 2026
93b67be
bolt12: Warm LSPS2 lease targets
tnull Jul 16, 2026
f068ab5
payment: Move payment metadata
tnull Jul 16, 2026
8eb8479
lsps2: Add JIT payment router
tnull Jul 21, 2026
24ec50e
f Apply LSPS2 final CLTV buffer
tnull Jul 29, 2026
f7da851
f Reject insufficient direct BOLT12 paths
tnull Aug 5, 2026
3ff9a41
bolt12: Wrap offers message handling
tnull Jul 20, 2026
8fb952c
bolt12: Sync offers flow block state
tnull Jul 20, 2026
b476a88
bolt12: Install LSPS2 router
tnull Jul 16, 2026
5e932c8
lsps2: Share payment lease selection
tnull Jul 16, 2026
8ba866f
f Prevent duplicate lease consumption
tnull Jul 29, 2026
285b9c8
bolt12: Handle invoice requests locally
tnull Jul 20, 2026
6cf165f
bolt12: Respond to requests from leases
tnull Jul 16, 2026
9d412bd
f Preserve MPP for ordinary offer paths
tnull Jul 28, 2026
603e757
f Reject unsupported LSPS2 CLTV deltas
tnull Aug 7, 2026
e560b11
bolt12: Bound pending JIT requests
tnull Jul 20, 2026
6ac00ee
f Reject in-flight invoice request replays
tnull Aug 7, 2026
f9a5bdb
lsps2: Extend opening parameter validity
tnull Jul 16, 2026
8fd482a
bolt12: Validate LSPS2 opening fees
tnull Jul 16, 2026
b7366b9
f Allow idempotent inbound BOLT12 hashes
tnull Jul 29, 2026
74afbf1
lsps2: Serialize lease negotiation
tnull Jul 16, 2026
61ad0e6
lsps2: Refill consumed payment leases
tnull Jul 16, 2026
0ca2fb8
f Track LSPS2 lease refill tasks
tnull Aug 7, 2026
eda7648
lsps2: Restore cached payment leases
tnull Jul 21, 2026
ce8d814
lsps2: Retry failed lease negotiation
tnull Jul 16, 2026
fc58f3e
lsps2: Fail over lease negotiation
tnull Jul 16, 2026
567d18e
lsps2: Match variable leases to payments
tnull Jul 21, 2026
1312b2c
f Separate cache and invoice validity
tnull Jul 29, 2026
b452df4
lsps2: Test BOLT12 JIT payments
tnull Jul 16, 2026
3377939
lsps2: Test multi-LSP BOLT12 selection
tnull Jul 16, 2026
7164f60
lsps2: Test restored BOLT12 leases
tnull Jul 16, 2026
703a43b
lsps2: Test payment lease state
tnull Jul 16, 2026
4a23329
f Update cached lease state tests
tnull Jul 29, 2026
03260f1
f Update cached lease state tests
tnull Aug 7, 2026
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
12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,16 @@ harness = false
#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" }
[patch."https://github.com/lightningdevkit/rust-lightning"]
lightning = { git = "https://git.rust-bitcoin.org/tnull/rust-lightning", rev = "5df6db764b88f57913f18923124838cc66bf6400" }
lightning-types = { git = "https://git.rust-bitcoin.org/tnull/rust-lightning", rev = "5df6db764b88f57913f18923124838cc66bf6400" }
lightning-invoice = { git = "https://git.rust-bitcoin.org/tnull/rust-lightning", rev = "5df6db764b88f57913f18923124838cc66bf6400" }
#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" }
lightning-liquidity = { git = "https://git.rust-bitcoin.org/tnull/rust-lightning", rev = "5df6db764b88f57913f18923124838cc66bf6400" }
lightning-macros = { git = "https://git.rust-bitcoin.org/tnull/rust-lightning", rev = "5df6db764b88f57913f18923124838cc66bf6400" }
#lightning-dns-resolver = { path = "../rust-lightning/lightning-dns-resolver" }
49 changes: 37 additions & 12 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,13 @@ use crate::io::{
PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
};
use crate::liquidity::client::lsps2::router::LSPS2Router;
use crate::liquidity::{LSPS2ServiceConfig, LiquiditySourceBuilder, LspConfig};
use crate::lnurl_auth::LnurlAuth;
use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger};
use crate::message_handler::NodeCustomMessageHandler;
use crate::payment::asynchronous::om_mailbox::OnionMessageMailbox;
use crate::payment::NodeOffersMessageHandler;
use crate::peer_store::PeerStore;
use crate::probing::{
HighDegreeStrategy, Prober, ProbingConfig, ProbingStrategy, ProbingStrategyKind,
Expand Down Expand Up @@ -1900,12 +1902,15 @@ fn build_with_store_internal(
}

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

let mut user_config = default_user_config(&config);
Expand Down Expand Up @@ -1980,6 +1985,15 @@ fn build_with_store_internal(
};

let channel_manager = Arc::new(channel_manager);
let offers_message_handler = Arc::new(NodeOffersMessageHandler::new(
config.network,
cur_time.as_secs().try_into().map_err(|_| BuildError::InvalidSystemTime)?,
Arc::clone(&channel_manager),
Arc::clone(&keys_manager),
Arc::clone(&router),
Arc::clone(&message_router),
Arc::clone(&logger),
));

// Give ChannelMonitors to ChainMonitor
for (_blockhash, channel_monitor) in channel_monitors.into_iter() {
Expand Down Expand Up @@ -2050,7 +2064,7 @@ fn build_with_store_internal(
Arc::clone(&logger),
Arc::clone(&channel_manager),
message_router,
Arc::clone(&channel_manager),
Arc::clone(&offers_message_handler),
Arc::clone(&channel_manager),
Arc::clone(&om_resolver),
IgnoringMessageHandler {},
Expand All @@ -2063,7 +2077,7 @@ fn build_with_store_internal(
Arc::clone(&logger),
Arc::clone(&channel_manager),
message_router,
Arc::clone(&channel_manager),
Arc::clone(&offers_message_handler),
Arc::clone(&channel_manager),
Arc::clone(&om_resolver),
IgnoringMessageHandler {},
Expand Down Expand Up @@ -2105,6 +2119,7 @@ fn build_with_store_internal(
Arc::clone(&keys_manager),
Arc::clone(&tx_broadcaster),
Arc::clone(&kv_store),
Arc::downgrade(&runtime),
Arc::clone(&config),
Arc::clone(&logger),
);
Expand Down Expand Up @@ -2189,6 +2204,12 @@ fn build_with_store_internal(
Arc::clone(&keys_manager),
Arc::clone(&logger),
));
offers_message_handler.initialize_jit_handling(
Arc::clone(&runtime),
liquidity_source.lsps2_client(),
Arc::downgrade(&connection_manager),
Arc::downgrade(&onion_messenger),
);

let output_sweeper = match sweeper_bytes_res {
Ok(output_sweeper) => Arc::new(output_sweeper),
Expand Down Expand Up @@ -2258,12 +2279,15 @@ fn build_with_store_internal(
if let Some(penalty) = probing_cfg.diversity_penalty_msat {
probing_fee_params.probing_diversity_penalty_msat = penalty;
}
let probing_router = Arc::new(DefaultRouter::new(
Arc::clone(&network_graph),
Arc::clone(&logger),
let probing_router = Arc::new(LSPS2Router::new(
DefaultRouter::new(
Arc::clone(&network_graph),
Arc::clone(&logger),
Arc::clone(&keys_manager),
Arc::clone(&scorer),
probing_fee_params,
),
Arc::clone(&keys_manager),
Arc::clone(&scorer),
probing_fee_params,
));
Arc::new(HighDegreeStrategy::new(
Arc::clone(&network_graph),
Expand Down Expand Up @@ -2321,6 +2345,7 @@ fn build_with_store_internal(
output_sweeper,
peer_manager,
onion_messenger,
offers_message_handler,
connection_manager,
keys_manager,
network_graph,
Expand Down
60 changes: 49 additions & 11 deletions src/chain/bitcoind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use crate::fee_estimator::{
};
use crate::io::utils::update_and_persist_node_metrics;
use crate::logger::{log_bytes, log_debug, log_error, log_info, log_trace, LdkLogger, Logger};
use crate::payment::NodeOffersMessageHandler;
use crate::tx_broadcaster::SortedTransactions;
use crate::types::{ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
use crate::{Error, PersistedNodeMetrics};
Expand Down Expand Up @@ -156,7 +157,8 @@ impl BitcoindChainSource {
pub(super) async fn continuously_sync_wallets(
&self, mut stop_sync_receiver: tokio::sync::watch::Receiver<()>,
onchain_wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>,
chain_monitor: Arc<ChainMonitor>, output_sweeper: Arc<Sweeper>,
offers_message_handler: Arc<NodeOffersMessageHandler>, chain_monitor: Arc<ChainMonitor>,
output_sweeper: Arc<Sweeper>,
) {
// First register for the wallet polling status to make sure `Node::sync_wallets` calls
// wait on the result before proceeding.
Expand Down Expand Up @@ -184,11 +186,13 @@ impl BitcoindChainSource {

let onchain_wallet_best_block = onchain_wallet.current_best_block();
let channel_manager_best_block = channel_manager.current_best_block();
let offers_best_block = offers_message_handler.current_best_block();
let sweeper_best_block = output_sweeper.current_best_block();

let mut chain_listeners = vec![
(onchain_wallet_best_block, &*onchain_wallet as &(dyn Listen + Send + Sync)),
(channel_manager_best_block, &*channel_manager as &(dyn Listen + Send + Sync)),
(offers_best_block, &*offers_message_handler as &(dyn Listen + Send + Sync)),
(sweeper_best_block, &*output_sweeper as &(dyn Listen + Send + Sync)),
];

Expand Down Expand Up @@ -224,6 +228,7 @@ impl BitcoindChainSource {
header_cache,
Arc::clone(&onchain_wallet),
Arc::clone(&channel_manager),
Arc::clone(&offers_message_handler),
Arc::clone(&chain_monitor),
Arc::clone(&output_sweeper),
);
Expand Down Expand Up @@ -341,6 +346,7 @@ impl BitcoindChainSource {
_ = self.poll_and_update_listeners(
Arc::clone(&onchain_wallet),
Arc::clone(&channel_manager),
Arc::clone(&offers_message_handler),
Arc::clone(&chain_monitor),
Arc::clone(&output_sweeper)
) => {}
Expand Down Expand Up @@ -398,7 +404,8 @@ impl BitcoindChainSource {

pub(super) async fn poll_and_update_listeners(
&self, onchain_wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>,
chain_monitor: Arc<ChainMonitor>, output_sweeper: Arc<Sweeper>,
offers_message_handler: Arc<NodeOffersMessageHandler>, chain_monitor: Arc<ChainMonitor>,
output_sweeper: Arc<Sweeper>,
) -> Result<(), Error> {
let receiver_res = {
let mut status_lock = self.wallet_polling_status.lock().expect("lock");
Expand All @@ -418,6 +425,7 @@ impl BitcoindChainSource {
.poll_and_update_listeners_inner(
onchain_wallet,
channel_manager,
offers_message_handler,
chain_monitor,
output_sweeper,
)
Expand All @@ -430,7 +438,8 @@ impl BitcoindChainSource {

async fn poll_and_update_listeners_inner(
&self, onchain_wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>,
chain_monitor: Arc<ChainMonitor>, output_sweeper: Arc<Sweeper>,
offers_message_handler: Arc<NodeOffersMessageHandler>, chain_monitor: Arc<ChainMonitor>,
output_sweeper: Arc<Sweeper>,
) -> Result<(), Error> {
let mut spv_client_lock = self.spv_client.lock().await;
if spv_client_lock.is_none() {
Expand All @@ -445,6 +454,7 @@ impl BitcoindChainSource {
HeaderCache::new(),
Arc::clone(&onchain_wallet),
Arc::clone(&channel_manager),
Arc::clone(&offers_message_handler),
chain_monitor,
output_sweeper,
));
Expand Down Expand Up @@ -511,12 +521,14 @@ impl BitcoindChainSource {
fn new_spv_client(
&self, chain_tip: ValidatedBlockHeader, header_cache: HeaderCache,
onchain_wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>,
chain_monitor: Arc<ChainMonitor>, output_sweeper: Arc<Sweeper>,
offers_message_handler: Arc<NodeOffersMessageHandler>, chain_monitor: Arc<ChainMonitor>,
output_sweeper: Arc<Sweeper>,
) -> BitcoindSpvClient {
let chain_poller = ChainPoller::new(Arc::clone(&self.api_client), self.config.network);
let chain_listener = Arc::new(ChainListener {
onchain_wallet: Arc::downgrade(&onchain_wallet),
channel_manager: Arc::downgrade(&channel_manager),
offers_message_handler: Arc::downgrade(&offers_message_handler),
chain_monitor: Arc::downgrade(&chain_monitor),
output_sweeper: Arc::downgrade(&output_sweeper),
});
Expand Down Expand Up @@ -1507,17 +1519,25 @@ pub(crate) enum FeeRateEstimationMode {
pub(crate) struct ChainListener {
pub(crate) onchain_wallet: std::sync::Weak<Wallet>,
pub(crate) channel_manager: std::sync::Weak<ChannelManager>,
pub(crate) offers_message_handler: std::sync::Weak<NodeOffersMessageHandler>,
pub(crate) chain_monitor: std::sync::Weak<ChainMonitor>,
pub(crate) output_sweeper: std::sync::Weak<Sweeper>,
}

impl ChainListener {
fn upgrade(
&self,
) -> Option<(Arc<Wallet>, Arc<ChannelManager>, Arc<ChainMonitor>, Arc<Sweeper>)> {
) -> Option<(
Arc<Wallet>,
Arc<ChannelManager>,
Arc<NodeOffersMessageHandler>,
Arc<ChainMonitor>,
Arc<Sweeper>,
)> {
Some((
self.onchain_wallet.upgrade()?,
self.channel_manager.upgrade()?,
self.offers_message_handler.upgrade()?,
self.chain_monitor.upgrade()?,
self.output_sweeper.upgrade()?,
))
Expand All @@ -1529,32 +1549,50 @@ impl Listen for ChainListener {
&self, header: &bitcoin::block::Header,
txdata: &lightning::chain::transaction::TransactionData, height: u32,
) {
if let Some((onchain_wallet, channel_manager, chain_monitor, output_sweeper)) =
self.upgrade()
if let Some((
onchain_wallet,
channel_manager,
offers_message_handler,
chain_monitor,
output_sweeper,
)) = self.upgrade()
{
onchain_wallet.filtered_block_connected(header, txdata, height);
channel_manager.filtered_block_connected(header, txdata, height);
offers_message_handler.filtered_block_connected(header, txdata, height);
chain_monitor.filtered_block_connected(header, txdata, height);
output_sweeper.filtered_block_connected(header, txdata, height);
}
}
fn block_connected(&self, block: &bitcoin::Block, height: u32) {
if let Some((onchain_wallet, channel_manager, chain_monitor, output_sweeper)) =
self.upgrade()
if let Some((
onchain_wallet,
channel_manager,
offers_message_handler,
chain_monitor,
output_sweeper,
)) = self.upgrade()
{
onchain_wallet.block_connected(block, height);
channel_manager.block_connected(block, height);
offers_message_handler.block_connected(block, height);
chain_monitor.block_connected(block, height);
output_sweeper.block_connected(block, height);
}
}

fn blocks_disconnected(&self, fork_point_block: lightning::chain::BlockLocator) {
if let Some((onchain_wallet, channel_manager, chain_monitor, output_sweeper)) =
self.upgrade()
if let Some((
onchain_wallet,
channel_manager,
offers_message_handler,
chain_monitor,
output_sweeper,
)) = self.upgrade()
{
onchain_wallet.blocks_disconnected(fork_point_block);
channel_manager.blocks_disconnected(fork_point_block);
offers_message_handler.blocks_disconnected(fork_point_block);
chain_monitor.blocks_disconnected(fork_point_block);
output_sweeper.blocks_disconnected(fork_point_block);
}
Expand Down
19 changes: 15 additions & 4 deletions src/chain/electrum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ use crate::fee_estimator::{
};
use crate::io::utils::update_and_persist_node_metrics;
use crate::logger::{log_bytes, log_debug, log_error, log_trace, log_warn, LdkLogger, Logger};
use crate::payment::NodeOffersMessageHandler;
use crate::runtime::Runtime;
use crate::tx_broadcaster::SortedTransactions;
use crate::types::{ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
Expand Down Expand Up @@ -208,7 +209,8 @@ impl ElectrumChainSource {
}

pub(crate) async fn sync_lightning_wallet(
&self, channel_manager: Arc<ChannelManager>, chain_monitor: Arc<ChainMonitor>,
&self, channel_manager: Arc<ChannelManager>,
offers_message_handler: Arc<NodeOffersMessageHandler>, chain_monitor: Arc<ChainMonitor>,
output_sweeper: Arc<Sweeper>,
) -> Result<(), Error> {
let receiver_res = {
Expand All @@ -224,8 +226,14 @@ impl ElectrumChainSource {
})?;
}

let res =
self.sync_lightning_wallet_inner(channel_manager, chain_monitor, output_sweeper).await;
let res = self
.sync_lightning_wallet_inner(
channel_manager,
offers_message_handler,
chain_monitor,
output_sweeper,
)
.await;

self.lightning_wallet_sync_status
.lock()
Expand All @@ -236,14 +244,17 @@ impl ElectrumChainSource {
}

async fn sync_lightning_wallet_inner(
&self, channel_manager: Arc<ChannelManager>, chain_monitor: Arc<ChainMonitor>,
&self, channel_manager: Arc<ChannelManager>,
offers_message_handler: Arc<NodeOffersMessageHandler>, chain_monitor: Arc<ChainMonitor>,
output_sweeper: Arc<Sweeper>,
) -> Result<(), Error> {
let sync_cman = Arc::clone(&channel_manager);
let sync_offers = Arc::clone(&offers_message_handler);
let sync_cmon = Arc::clone(&chain_monitor);
let sync_sweeper = Arc::clone(&output_sweeper);
let confirmables = vec![
sync_cman as Arc<dyn Confirm + Sync + Send>,
sync_offers as Arc<dyn Confirm + Sync + Send>,
sync_cmon as Arc<dyn Confirm + Sync + Send>,
sync_sweeper as Arc<dyn Confirm + Sync + Send>,
];
Expand Down
Loading
Loading