diff --git a/Cargo.toml b/Cargo.toml index 539941677..b55762a4c 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -172,15 +172,15 @@ 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" } -#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" } +[patch."https://github.com/lightningdevkit/rust-lightning"] +lightning = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc", features = ["std"] } +lightning-types = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc" } +lightning-invoice = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc", features = ["std"] } +lightning-net-tokio = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc" } +lightning-persister = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc", features = ["tokio"] } +lightning-background-processor = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc" } +lightning-rapid-gossip-sync = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc" } +lightning-block-sync = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc", features = ["rest-client", "rpc-client", "tokio"] } +lightning-transaction-sync = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc", features = ["esplora-async-https", "time", "electrum-rustls-ring"] } +lightning-liquidity = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc", features = ["std"] } +lightning-macros = { git = "https://github.com/carlakc/rust-lightning", rev = "62fde7a019b2d6a696efb7120be1d548efb031cc" } diff --git a/src/event.rs b/src/event.rs index f06d701bc..55e0be26e 100644 --- a/src/event.rs +++ b/src/event.rs @@ -18,10 +18,9 @@ use lightning::events::bump_transaction::BumpTransactionEvent; #[cfg(not(feature = "uniffi"))] use lightning::events::PaidBolt12Invoice; use lightning::events::{ - ClosureReason, Event as LdkEvent, FundingInfo, PaymentFailureReason, PaymentPurpose, - ReplayEvent, + ClosureReason, Event as LdkEvent, FundingInfo, HTLCLocator as LdkHtlcLocator, + PaymentFailureReason, PaymentPurpose, ReplayEvent, }; -use lightning::impl_writeable_tlv_based_enum; use lightning::ln::channelmanager::PaymentId; use lightning::ln::types::ChannelId; use lightning::routing::gossip::NodeId; @@ -32,6 +31,7 @@ use lightning::util::config::{ use lightning::util::errors::APIError; use lightning::util::persist::KVStore; use lightning::util::ser::{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 +61,40 @@ use crate::{ UserChannelId, }; +/// 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: LdkHtlcLocator) -> 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 +162,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: Vec, + /// 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: Vec, /// 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 +342,27 @@ 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), + // Legacy fields: read from old data, never written. + (0, legacy_prev_channel_id, (legacy, ChannelId, |_| Ok(()), |_: &Event| None::>)), + (1, legacy_prev_node_id, (legacy, PublicKey, |_| Ok(()), |_: &Event| None::>)), + (2, legacy_next_channel_id, (legacy, ChannelId, |_| Ok(()), |_: &Event| None::>)), + (3, legacy_next_node_id, (legacy, PublicKey, |_| Ok(()), |_: &Event| None::>)), + (4, legacy_prev_user_channel_id, (legacy, u128, |_| Ok(()), |_: &Event| None::>)), + (6, legacy_next_user_channel_id, (legacy, u128, |_| Ok(()), |_: &Event| None::>)), (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_vec, vec![HTLCLocator { + channel_id: legacy_prev_channel_id.ok_or(lightning::ln::msgs::DecodeError::InvalidValue)?, + user_channel_id: legacy_prev_user_channel_id.map(UserChannelId), + node_id: legacy_prev_node_id, + }])), + (17, next_htlcs, (default_value_vec, vec![HTLCLocator { + channel_id: legacy_next_channel_id.ok_or(lightning::ln::msgs::DecodeError::InvalidValue)?, + user_channel_id: legacy_next_user_channel_id.map(UserChannelId), + node_id: legacy_next_node_id, + }])), }, (8, SplicePending) => { (1, channel_id, required), @@ -1395,32 +1425,29 @@ where } } - // We only allow multiple HTLCs in/out for trampoline forwards, which have not yet - // been fully implemented in LDK, so we do not lose any information by just - // reporting the first HTLC in each vec. - debug_assert_eq!(prev_htlcs.len(), 1, "unexpected number of prev_htlcs"); - debug_assert_eq!(next_htlcs.len(), 1, "unexpected number of next_htlcs"); - let prev_htlc = prev_htlcs - .first() - .expect("we expect at least one prev_htlc for PaymentForwarded"); - let next_htlc = next_htlcs - .first() - .expect("we expect at least one next_htlc for PaymentForwarded"); - + // We only expect multiple next_htlcs when we have a trampoline forward, and we do + // not support JIT channels in combination with trampoline. We're not at risk of + // double-reporting a skimmed fee when we have multiple next_htlcs because we + // expect our skimmed fee to be zero. + if skimmed_fee_msat.is_some() { + debug_assert_eq!( + next_htlcs.len(), + 1, + "unexpected skimmed fee for trampoline forward, fee may be double counted" + ); + } 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(Some(next_htlc.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_htlc.channel_id, - next_channel_id: next_htlc.channel_id, - prev_user_channel_id: prev_htlc.user_channel_id.map(UserChannelId), - next_user_channel_id: next_htlc.user_channel_id.map(UserChannelId), - prev_node_id: prev_htlc.node_id, - next_node_id: next_htlc.node_id, + prev_htlcs: prev_htlcs.into_iter().map(HTLCLocator::from).collect(), + next_htlcs: next_htlcs.into_iter().map(HTLCLocator::from).collect(), total_fee_earned_msat, skimmed_fee_msat, claim_from_onchain_tx,