From f101d37775c5aefd65150b886fed93b1e450e9f1 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Thu, 12 Mar 2026 11:28:40 -0400 Subject: [PATCH 1/2] Bump LDK dependency for splice acceptor contribution In the event of a quiescence tie-breaker, the losing side may contribute as the splice acceptor. A min and max feerate allows us to determine whether to contribute. We use 150% of the min feerate for the max feerate to allow for RBFs in upcoming changes. --- Cargo.toml | 26 +++++++++++++------------- src/ffi/types.rs | 2 +- src/lib.rs | 30 ++++++++++++++++++++++++------ 3 files changed, 38 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 18947b72f..07cabe33f 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,17 +39,17 @@ default = [] #lightning-liquidity = { version = "0.2.0", features = ["std"] } #lightning-macros = { version = "0.2.0" } -lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std"] } -lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" } -lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std"] } -lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" } -lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["tokio"] } -lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" } -lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" } -lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["rest-client", "rpc-client", "tokio"] } -lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } -lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std"] } -lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245" } +lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std"] } +lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } +lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std"] } +lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } +lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["tokio"] } +lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } +lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } +lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["rest-client", "rpc-client", "tokio"] } +lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } +lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std"] } +lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] } bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]} @@ -79,13 +79,13 @@ 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/jkczyz/bitcoin-payment-instructions", rev = "869fd348c3ca0c78f439d2f31181f4d798c6b20e" } +bitcoin-payment-instructions = { git = "https://github.com/jkczyz/bitcoin-payment-instructions", rev = "0138feb7acefb1e49102a6fb46d7b776bf43265e" } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["winbase"] } [dev-dependencies] -lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98501d6e5134228c41460dcf786ab53337e41245", features = ["std", "_test_utils"] } +lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std", "_test_utils"] } rand = { version = "0.9.2", default-features = false, features = ["std", "thread_rng", "os_rng"] } proptest = "1.0.0" regex = "1.5.6" diff --git a/src/ffi/types.rs b/src/ffi/types.rs index cc7298cfa..f39f3bca7 100644 --- a/src/ffi/types.rs +++ b/src/ffi/types.rs @@ -21,7 +21,7 @@ pub use bip39::Mnemonic; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::Hash; use bitcoin::secp256k1::PublicKey; -pub use bitcoin::{Address, BlockHash, FeeRate, Network, OutPoint, ScriptBuf, Txid}; +pub use bitcoin::{Address, BlockHash, Network, OutPoint, ScriptBuf, Txid}; pub use lightning::chain::channelmonitor::BalanceSource; use lightning::events::PaidBolt12Invoice as LdkPaidBolt12Invoice; pub use lightning::events::{ClosureReason, PaymentFailureReason}; diff --git a/src/lib.rs b/src/lib.rs index 109ade0ae..e3beb44db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,6 +118,10 @@ pub use balance::{BalanceDetails, LightningBalance, PendingSweepBalance}; pub use bip39; pub use bitcoin; use bitcoin::secp256k1::PublicKey; +#[cfg(feature = "uniffi")] +pub use bitcoin::FeeRate; +#[cfg(not(feature = "uniffi"))] +use bitcoin::FeeRate; use bitcoin::{Address, Amount}; #[cfg(feature = "uniffi")] pub use builder::ArcedNodeBuilder as Builder; @@ -1403,7 +1407,9 @@ impl Node { if let Some(channel_details) = open_channels.iter().find(|c| c.user_channel_id == user_channel_id.0) { - let fee_rate = self.fee_estimator.estimate_fee_rate(ConfirmationTarget::ChannelFunding); + let min_feerate = + self.fee_estimator.estimate_fee_rate(ConfirmationTarget::ChannelFunding); + let max_feerate = FeeRate::from_sat_per_kwu(min_feerate.to_sat_per_kwu() * 3 / 2); let splice_amount_sats = match splice_amount_sats { FundingAmount::Exact { amount_sats } => amount_sats, @@ -1437,7 +1443,7 @@ impl Node { shared_input, funding_output.script_pubkey.clone(), cur_anchor_reserve_sats, - fee_rate, + min_feerate, ) .map_err(|e| { log_error!( @@ -1451,7 +1457,7 @@ impl Node { self.logger, "Splicing in with all balance: {}sats (fee rate: {} sat/kw, anchor reserve: {}sats)", amount, - fee_rate.to_sat_per_kwu(), + min_feerate.to_sat_per_kwu(), cur_anchor_reserve_sats, ); @@ -1463,7 +1469,12 @@ impl Node { let funding_template = self .channel_manager - .splice_channel(&channel_details.channel_id, &counterparty_node_id, fee_rate) + .splice_channel( + &channel_details.channel_id, + &counterparty_node_id, + min_feerate, + max_feerate, + ) .map_err(|e| { log_error!(self.logger, "Failed to splice channel: {:?}", e); Error::ChannelSplicingFailed @@ -1568,11 +1579,18 @@ impl Node { self.wallet.parse_and_validate_address(address)?; - let fee_rate = self.fee_estimator.estimate_fee_rate(ConfirmationTarget::ChannelFunding); + let min_feerate = + self.fee_estimator.estimate_fee_rate(ConfirmationTarget::ChannelFunding); + let max_feerate = FeeRate::from_sat_per_kwu(min_feerate.to_sat_per_kwu() * 3 / 2); let funding_template = self .channel_manager - .splice_channel(&channel_details.channel_id, &counterparty_node_id, fee_rate) + .splice_channel( + &channel_details.channel_id, + &counterparty_node_id, + min_feerate, + max_feerate, + ) .map_err(|e| { log_error!(self.logger, "Failed to splice channel: {:?}", e); Error::ChannelSplicingFailed From dd42f5ff8c6eb3456dc0fb3048782fc918eeb075 Mon Sep 17 00:00:00 2001 From: Carla Kirk-Cohen Date: Fri, 13 Mar 2026 13:28:39 -0400 Subject: [PATCH 2/2] [wip]: bump rust-lightning to support trampoline changes --- Cargo.toml | 29 +++--- src/event.rs | 227 +++++++++++++++++++++++++++++++++-------------- src/ffi/types.rs | 6 ++ 3 files changed, 180 insertions(+), 82 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07cabe33f..2a135454f 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,17 +39,17 @@ default = [] #lightning-liquidity = { version = "0.2.0", features = ["std"] } #lightning-macros = { version = "0.2.0" } -lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std"] } -lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } -lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std"] } -lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } -lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["tokio"] } -lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } -lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } -lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["rest-client", "rpc-client", "tokio"] } -lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } -lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std"] } -lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204" } +lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["std"] } +lightning-types = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a" } +lightning-invoice = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["std"] } +lightning-net-tokio = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a" } +lightning-persister = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["tokio"] } +lightning-background-processor = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a" } +lightning-rapid-gossip-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a" } +lightning-block-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["rest-client", "rpc-client", "tokio"] } +lightning-transaction-sync = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } +lightning-liquidity = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["std"] } +lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a" } bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] } bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]} @@ -79,13 +79,14 @@ 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/jkczyz/bitcoin-payment-instructions", rev = "0138feb7acefb1e49102a6fb46d7b776bf43265e" } +# TODO: need to push branch to Jeff's fork? +bitcoin-payment-instructions = { git = "https://github.com/carlaKC/bitcoin-payment-instructions", rev = "c22c9b836b70d4c915dd28701e11083a8b558d56" } [target.'cfg(windows)'.dependencies] winapi = { version = "0.3", features = ["winbase"] } [dev-dependencies] -lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "98393b3de3d8aec897e9ab783cb2418da504e204", features = ["std", "_test_utils"] } +lightning = { git = "https://github.com/lightningdevkit/rust-lightning", rev = "128ead25e8d62b0262b71711631220983c48756a", features = ["std", "_test_utils"] } rand = { version = "0.9.2", default-features = false, features = ["std", "thread_rng", "os_rng"] } proptest = "1.0.0" regex = "1.5.6" @@ -182,4 +183,4 @@ harness = false #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-macros = { path = "../rust-lightning/lightning-macros" } diff --git a/src/event.rs b/src/event.rs index c4949a5ac..db2ce228f 100644 --- a/src/event.rs +++ b/src/event.rs @@ -21,8 +21,8 @@ use lightning::events::{ ClosureReason, Event as LdkEvent, FundingInfo, PaymentFailureReason, PaymentPurpose, ReplayEvent, }; -use lightning::impl_writeable_tlv_based_enum; use lightning::ln::channelmanager::PaymentId; +use lightning::ln::msgs::DecodeError; use lightning::ln::types::ChannelId; use lightning::routing::gossip::NodeId; use lightning::sign::EntropySource; @@ -31,7 +31,10 @@ use lightning::util::config::{ }; use lightning::util::errors::APIError; use lightning::util::persist::KVStore; -use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer}; +use lightning::util::ser::{ + CollectionLength, MaybeReadable, Readable, ReadableArgs, Writeable, Writer, +}; +use lightning::{impl_writeable_tlv_based, impl_writeable_tlv_based_enum}; use lightning_liquidity::lsps2::utils::compute_opening_fee; use lightning_types::payment::{PaymentHash, PaymentPreimage}; @@ -61,6 +64,70 @@ use crate::{ UserChannelId, }; +/// A set of multiple htlcs all associated with same forward. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct HTLCSet(pub Vec); + +impl Writeable for HTLCSet { + fn write(&self, w: &mut W) -> Result<(), lightning::io::Error> { + lightning::util::ser::CollectionLength(self.0.len() as u64).write(w)?; + for elem in self.0.iter() { + elem.write(w)?; + } + Ok(()) + } +} + +impl Readable for HTLCSet { + fn read(r: &mut R) -> Result { + let len: CollectionLength = Readable::read(r)?; + let mut ret = Vec::with_capacity(std::cmp::min( + len.0 as usize, + lightning::util::ser::MAX_BUF_SIZE / core::mem::size_of::(), + )); + for _ in 0..len.0 { + if let Some(val) = MaybeReadable::read(r)? { + ret.push(val); + } + } + Ok(HTLCSet(ret)) + } +} + +/// Identifies the channel and counterparty that a HTLC was processed with. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +pub struct HTLCLocator { + /// The channel that the HTLC was sent or received on. + pub channel_id: ChannelId, + /// The `user_channel_id` for the channel. + /// + /// Will only be `None` for events serialized with LDK Node v0.3.0 or prior, or if the + /// payment was settled via an on-chain transaction. + pub user_channel_id: Option, + /// The node id of the counterparty for this HTLC. + /// + /// This is only `None` for HTLCs received prior to LDK Node v0.5 or for events serialized by + /// versions prior to v0.5. + pub node_id: Option, +} + +impl_writeable_tlv_based!(HTLCLocator, { + (1, channel_id, required), + (3, user_channel_id, option), + (5, node_id, option), +}); + +impl From for HTLCLocator { + fn from(value: lightning::events::HTLCLocator) -> Self { + HTLCLocator { + channel_id: value.channel_id, + user_channel_id: value.user_channel_id.map(|u| UserChannelId(u)), + node_id: value.node_id, + } + } +} + /// An event emitted by [`Node`], which should be handled by the user. /// /// [`Node`]: [`crate::Node`] @@ -128,29 +195,14 @@ pub enum Event { }, /// A payment has been forwarded. PaymentForwarded { - /// The channel id of the incoming channel between the previous node and us. - prev_channel_id: ChannelId, - /// The channel id of the outgoing channel between the next node and us. - next_channel_id: ChannelId, - /// The `user_channel_id` of the incoming channel between the previous node and us. - /// - /// Will only be `None` for events serialized with LDK Node v0.3.0 or prior. - prev_user_channel_id: Option, - /// The `user_channel_id` of the outgoing channel between the next node and us. - /// - /// This will be `None` if the payment was settled via an on-chain transaction. See the - /// caveat described for the `total_fee_earned_msat` field. - next_user_channel_id: Option, - /// The node id of the previous node. - /// - /// This is only `None` for HTLCs received prior to LDK Node v0.5 or for events serialized by - /// versions prior to v0.5. - prev_node_id: Option, - /// The node id of the next node. - /// - /// This is only `None` for HTLCs received prior to LDK Node v0.5 or for events serialized by - /// versions prior to v0.5. - next_node_id: Option, + /// The set of incoming HTLCs that were forwarded to our node. Contains a single HTLC for + /// source-routed payments, and may contain multiple HTLCs when we acted as a trampoline + /// router. + prev_htlcs: HTLCSet, + /// The set of outgoing HTLCs forwarded by our node. Contains a single HTLC for regular + /// source-routed payments, and may contain multiple HTLCs when we acted as a trampoline + /// router. + next_htlcs: HTLCSet, /// The total fee, in milli-satoshis, which was earned as a result of the payment. /// /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC @@ -323,16 +375,58 @@ impl_writeable_tlv_based_enum!(Event, (7, custom_records, optional_vec), }, (7, PaymentForwarded) => { - (0, prev_channel_id, required), - (1, prev_node_id, option), - (2, next_channel_id, required), - (3, next_node_id, option), - (4, prev_user_channel_id, option), - (6, next_user_channel_id, option), + // For backwards compatibility, write the first prev/next_htlc to our legacy fields. This + // allows use to downgrade with some information loss about the remaining htlcs. + (0, prev_channel_id_legacy, (legacy, ChannelId, |_| Ok(()), + |us: &Event| match us { + Event::PaymentForwarded { prev_htlcs, .. } => prev_htlcs.0.first().map(|h| h.channel_id), + _ => unreachable!(), + } + )), + (1, prev_node_id_legacy, (legacy, PublicKey, |_| Ok(()), + |us: &Event| match us { + Event::PaymentForwarded { prev_htlcs, .. } => prev_htlcs.0.first().and_then(|h| h.node_id), + _ => unreachable!(), + } + )), + (2, next_channel_id_legacy, (legacy, ChannelId, |_| Ok(()), + |us: &Event| match us { + Event::PaymentForwarded { next_htlcs, .. } => next_htlcs.0.first().map(|h| h.channel_id), + _ => unreachable!(), + } + )), + (3, next_node_id_legacy, (legacy, PublicKey, |_| Ok(()), + |us: &Event| match us { + Event::PaymentForwarded { next_htlcs, .. } => next_htlcs.0.first().and_then(|h| h.node_id), + _ => unreachable!(), + } + )), + (4, prev_user_channel_id_legacy, (legacy, UserChannelId, |_| Ok(()), + |us: &Event| match us { + Event::PaymentForwarded { prev_htlcs, .. } => prev_htlcs.0.first().and_then(|h| h.user_channel_id), + _ => unreachable!(), + } + )), + (6, next_user_channel_id_legacy, (legacy, UserChannelId, |_| Ok(()), + |us: &Event| match us { + Event::PaymentForwarded { next_htlcs, .. } => next_htlcs.0.first().and_then(|h| h.user_channel_id), + _ => unreachable!(), + } + )), (8, total_fee_earned_msat, option), (10, skimmed_fee_msat, option), (12, claim_from_onchain_tx, required), (14, outbound_amount_forwarded_msat, option), + (15, prev_htlcs, (default_value, HTLCSet(vec![HTLCLocator { + channel_id: prev_channel_id_legacy.ok_or(lightning::ln::msgs::DecodeError::InvalidValue)?, + user_channel_id: prev_user_channel_id_legacy, + node_id: prev_node_id_legacy, + }]))), + (17, next_htlcs, (default_value, HTLCSet(vec![HTLCLocator { + channel_id: next_channel_id_legacy.ok_or(lightning::ln::msgs::DecodeError::InvalidValue)?, + user_channel_id: next_user_channel_id_legacy, + node_id: next_node_id_legacy, + }]))), }, (8, SplicePending) => { (1, channel_id, required), @@ -644,7 +738,8 @@ where ) .unwrap_or_else(|e| { log_error!(self.logger, "Failed to force close channel after funding generation failed: {:?}", e); - debug_assert!(false, + debug_assert!( + false, "Failed to force close channel after funding generation failed" ); }); @@ -1306,12 +1401,8 @@ where } }, LdkEvent::PaymentForwarded { - prev_channel_id, - next_channel_id, - prev_user_channel_id, - next_user_channel_id, - prev_node_id, - next_node_id, + prev_htlcs, + next_htlcs, total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, @@ -1322,11 +1413,10 @@ where let nodes = read_only_network_graph.nodes(); let channels = self.channel_manager.list_channels(); - let node_str = |channel_id: &Option| { - channel_id - .and_then(|channel_id| { - channels.iter().find(|c| c.channel_id == channel_id) - }) + let node_str = |channel_id: &ChannelId| { + channels + .iter() + .find(|c| c.channel_id == *channel_id) .and_then(|channel| { nodes.get(&NodeId::from_pubkey(&channel.counterparty.node_id)) }) @@ -1338,21 +1428,22 @@ where }) }) }; - let channel_str = |channel_id: &Option| { - channel_id - .map(|channel_id| format!(" with channel {}", channel_id)) - .unwrap_or_default() - }; - let from_prev_str = format!( - " from {}{}", - node_str(&prev_channel_id), - channel_str(&prev_channel_id) - ); - let to_next_str = format!( - " to {}{}", - node_str(&next_channel_id), - channel_str(&next_channel_id) - ); + + let from_prev_str: String = prev_htlcs + .iter() + .map(|htlc| { + format!("with {} on {}", node_str(&htlc.channel_id), htlc.channel_id) + }) + .collect::>() + .join(", "); + + let to_next_str: String = next_htlcs + .iter() + .map(|htlc| { + format!("with {} on {}", node_str(&htlc.channel_id), htlc.channel_id) + }) + .collect::>() + .join(", "); let fee_earned = total_fee_earned_msat.unwrap_or(0); if claim_from_onchain_tx { @@ -1367,8 +1458,10 @@ where } else { log_info!( self.logger, - "Forwarded payment{}{} of {}msat, earning {}msat in fees.", + "Forwarded payment with {} inbound HTLC(s) ({}) and {} outbound HTLC(s) ({}) of {}msat, earning {}msat in fees.", + prev_htlcs.len(), from_prev_str, + next_htlcs.len(), to_next_str, outbound_amount_forwarded_msat.unwrap_or(0), fee_earned, @@ -1378,18 +1471,16 @@ where if let Some(liquidity_source) = self.liquidity_source.as_ref() { let skimmed_fee_msat = skimmed_fee_msat.unwrap_or(0); - liquidity_source - .handle_payment_forwarded(next_channel_id, skimmed_fee_msat) - .await; + for next_htlc in next_htlcs.iter() { + liquidity_source + .handle_payment_forwarded(Some(next_htlc.channel_id), skimmed_fee_msat) + .await; + } } let event = Event::PaymentForwarded { - prev_channel_id: prev_channel_id.expect("prev_channel_id expected for events generated by LDK versions greater than 0.0.107."), - next_channel_id: next_channel_id.expect("next_channel_id expected for events generated by LDK versions greater than 0.0.107."), - prev_user_channel_id: prev_user_channel_id.map(UserChannelId), - next_user_channel_id: next_user_channel_id.map(UserChannelId), - prev_node_id, - next_node_id, + prev_htlcs: HTLCSet(prev_htlcs.into_iter().map(|h| h.into()).collect()), + next_htlcs: HTLCSet(next_htlcs.into_iter().map(|h| h.into()).collect()), total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx, diff --git a/src/ffi/types.rs b/src/ffi/types.rs index f39f3bca7..7f0073d9a 100644 --- a/src/ffi/types.rs +++ b/src/ffi/types.rs @@ -145,10 +145,16 @@ use crate::builder::sanitize_alias; pub use crate::config::{default_config, ElectrumSyncConfig, EsploraSyncConfig}; pub use crate::entropy::{generate_entropy_mnemonic, NodeEntropy, WordCount}; use crate::error::Error; +use crate::event::{HTLCLocator, HTLCSet}; pub use crate::liquidity::LSPS1OrderStatus; pub use crate::logger::{LogLevel, LogRecord, LogWriter}; use crate::{hex_utils, SocketAddress, UserChannelId}; +uniffi::custom_type!(HTLCSet, Vec, { + try_lift: |val| Ok(HTLCSet(val)), + lower: |obj| obj.0, +}); + uniffi::custom_type!(PublicKey, String, { remote, try_lift: |val| {