@@ -21,8 +21,8 @@ use lightning::events::{
2121 ClosureReason , Event as LdkEvent , FundingInfo , PaymentFailureReason , PaymentPurpose ,
2222 ReplayEvent ,
2323} ;
24- use lightning:: impl_writeable_tlv_based_enum;
2524use lightning:: ln:: channelmanager:: PaymentId ;
25+ use lightning:: ln:: msgs:: DecodeError ;
2626use lightning:: ln:: types:: ChannelId ;
2727use lightning:: routing:: gossip:: NodeId ;
2828use lightning:: sign:: EntropySource ;
@@ -31,7 +31,10 @@ use lightning::util::config::{
3131} ;
3232use lightning:: util:: errors:: APIError ;
3333use lightning:: util:: persist:: KVStore ;
34- use lightning:: util:: ser:: { Readable , ReadableArgs , Writeable , Writer } ;
34+ use lightning:: util:: ser:: {
35+ CollectionLength , MaybeReadable , Readable , ReadableArgs , Writeable , Writer ,
36+ } ;
37+ use lightning:: { impl_writeable_tlv_based, impl_writeable_tlv_based_enum} ;
3538use lightning_liquidity:: lsps2:: utils:: compute_opening_fee;
3639use lightning_types:: payment:: { PaymentHash , PaymentPreimage } ;
3740
@@ -61,6 +64,71 @@ use crate::{
6164 UserChannelId ,
6265} ;
6366
67+ /// A set of multiple htlcs all associated with same forward.
68+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
69+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Record ) ) ]
70+ pub struct HTLCSet ( Vec < HTLCLocator > ) ;
71+
72+ impl Writeable for HTLCSet {
73+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , lightning:: io:: Error > {
74+ lightning:: util:: ser:: CollectionLength ( self . 0 . len ( ) as u64 ) . write ( w) ?;
75+ for elem in self . 0 . iter ( ) {
76+ elem. write ( w) ?;
77+ }
78+ Ok ( ( ) )
79+ }
80+ }
81+
82+ impl Readable for HTLCSet {
83+ fn read < R : lightning:: io:: Read > ( r : & mut R ) -> Result < Self , DecodeError > {
84+ let len: CollectionLength = Readable :: read ( r) ?;
85+ let mut ret = Vec :: with_capacity ( std:: cmp:: min (
86+ len. 0 as usize ,
87+ lightning:: util:: ser:: MAX_BUF_SIZE / core:: mem:: size_of :: < HTLCLocator > ( ) ,
88+ ) ) ;
89+ for _ in 0 ..len. 0 {
90+ if let Some ( val) = MaybeReadable :: read ( r) ? {
91+ ret. push ( val) ;
92+ }
93+ }
94+ Ok ( HTLCSet ( ret) )
95+ }
96+ }
97+
98+ /// Identifies the channel and counterparty that a HTLC was processed with.
99+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
100+ #[ cfg_attr( feature = "uniffi" , derive( uniffi:: Record ) ) ]
101+ pub struct HTLCLocator {
102+ /// The channel that the HTLC was sent or received on.
103+ pub channel_id : ChannelId ,
104+ /// The `user_channel_id` for the channel.
105+ ///
106+ /// Will only be `None` for events serialized with LDK Node v0.3.0 or prior, or if the
107+ /// payment was settled via an on-chain transaction.
108+ pub user_channel_id : Option < UserChannelId > ,
109+ /// The node id of the counterparty for this HTLC.
110+ ///
111+ /// This is only `None` for HTLCs received prior to LDK Node v0.5 or for events serialized by
112+ /// versions prior to v0.5.
113+ pub node_id : Option < PublicKey > ,
114+ }
115+
116+ impl_writeable_tlv_based ! ( HTLCLocator , {
117+ ( 1 , channel_id, required) ,
118+ ( 3 , user_channel_id, option) ,
119+ ( 5 , node_id, option) ,
120+ } ) ;
121+
122+ impl From < lightning:: events:: HTLCLocator > for HTLCLocator {
123+ fn from ( value : lightning:: events:: HTLCLocator ) -> Self {
124+ HTLCLocator {
125+ channel_id : value. channel_id ,
126+ user_channel_id : value. user_channel_id . map ( |u| UserChannelId ( u) ) ,
127+ node_id : value. node_id ,
128+ }
129+ }
130+ }
131+
64132/// An event emitted by [`Node`], which should be handled by the user.
65133///
66134/// [`Node`]: [`crate::Node`]
@@ -128,29 +196,14 @@ pub enum Event {
128196 } ,
129197 /// A payment has been forwarded.
130198 PaymentForwarded {
131- /// The channel id of the incoming channel between the previous node and us.
132- prev_channel_id : ChannelId ,
133- /// The channel id of the outgoing channel between the next node and us.
134- next_channel_id : ChannelId ,
135- /// The `user_channel_id` of the incoming channel between the previous node and us.
136- ///
137- /// Will only be `None` for events serialized with LDK Node v0.3.0 or prior.
138- prev_user_channel_id : Option < UserChannelId > ,
139- /// The `user_channel_id` of the outgoing channel between the next node and us.
140- ///
141- /// This will be `None` if the payment was settled via an on-chain transaction. See the
142- /// caveat described for the `total_fee_earned_msat` field.
143- next_user_channel_id : Option < UserChannelId > ,
144- /// The node id of the previous node.
145- ///
146- /// This is only `None` for HTLCs received prior to LDK Node v0.5 or for events serialized by
147- /// versions prior to v0.5.
148- prev_node_id : Option < PublicKey > ,
149- /// The node id of the next node.
150- ///
151- /// This is only `None` for HTLCs received prior to LDK Node v0.5 or for events serialized by
152- /// versions prior to v0.5.
153- next_node_id : Option < PublicKey > ,
199+ /// The set of incoming HTLCs that were forwarded to our node. Contains a single HTLC for
200+ /// source-routed payments, and may contain multiple HTLCs when we acted as a trampoline
201+ /// router.
202+ prev_htlcs : HTLCSet ,
203+ /// The set of outgoing HTLCs forwarded by our node. Contains a single HTLC for regular
204+ /// source-routed payments, and may contain multiple HTLCs when we acted as a trampoline
205+ /// router.
206+ next_htlcs : HTLCSet ,
154207 /// The total fee, in milli-satoshis, which was earned as a result of the payment.
155208 ///
156209 /// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC
@@ -323,16 +376,58 @@ impl_writeable_tlv_based_enum!(Event,
323376 ( 7 , custom_records, optional_vec) ,
324377 } ,
325378 ( 7 , PaymentForwarded ) => {
326- ( 0 , prev_channel_id, required) ,
327- ( 1 , prev_node_id, option) ,
328- ( 2 , next_channel_id, required) ,
329- ( 3 , next_node_id, option) ,
330- ( 4 , prev_user_channel_id, option) ,
331- ( 6 , next_user_channel_id, option) ,
379+ // For backwards compatibility, write the first prev/next_htlc to our legacy fields. This
380+ // allows use to downgrade with some information loss about the remaining htlcs.
381+ ( 0 , prev_channel_id_legacy, ( legacy, ChannelId , |_| Ok ( ( ) ) ,
382+ |us: & Event | match us {
383+ Event :: PaymentForwarded { prev_htlcs, .. } => prev_htlcs. 0 . first( ) . map( |h| h. channel_id) ,
384+ _ => unreachable!( ) ,
385+ }
386+ ) ) ,
387+ ( 1 , prev_node_id_legacy, ( legacy, PublicKey , |_| Ok ( ( ) ) ,
388+ |us: & Event | match us {
389+ Event :: PaymentForwarded { prev_htlcs, .. } => prev_htlcs. 0 . first( ) . and_then( |h| h. node_id) ,
390+ _ => unreachable!( ) ,
391+ }
392+ ) ) ,
393+ ( 2 , next_channel_id_legacy, ( legacy, ChannelId , |_| Ok ( ( ) ) ,
394+ |us: & Event | match us {
395+ Event :: PaymentForwarded { next_htlcs, .. } => next_htlcs. 0 . first( ) . map( |h| h. channel_id) ,
396+ _ => unreachable!( ) ,
397+ }
398+ ) ) ,
399+ ( 3 , next_node_id_legacy, ( legacy, PublicKey , |_| Ok ( ( ) ) ,
400+ |us: & Event | match us {
401+ Event :: PaymentForwarded { next_htlcs, .. } => next_htlcs. 0 . first( ) . and_then( |h| h. node_id) ,
402+ _ => unreachable!( ) ,
403+ }
404+ ) ) ,
405+ ( 4 , prev_user_channel_id_legacy, ( legacy, UserChannelId , |_| Ok ( ( ) ) ,
406+ |us: & Event | match us {
407+ Event :: PaymentForwarded { prev_htlcs, .. } => prev_htlcs. 0 . first( ) . and_then( |h| h. user_channel_id) ,
408+ _ => unreachable!( ) ,
409+ }
410+ ) ) ,
411+ ( 6 , next_user_channel_id_legacy, ( legacy, UserChannelId , |_| Ok ( ( ) ) ,
412+ |us: & Event | match us {
413+ Event :: PaymentForwarded { next_htlcs, .. } => next_htlcs. 0 . first( ) . and_then( |h| h. user_channel_id) ,
414+ _ => unreachable!( ) ,
415+ }
416+ ) ) ,
332417 ( 8 , total_fee_earned_msat, option) ,
333418 ( 10 , skimmed_fee_msat, option) ,
334419 ( 12 , claim_from_onchain_tx, required) ,
335420 ( 14 , outbound_amount_forwarded_msat, option) ,
421+ ( 15 , prev_htlcs, ( default_value, HTLCSet ( vec![ HTLCLocator {
422+ channel_id: prev_channel_id_legacy. ok_or( lightning:: ln:: msgs:: DecodeError :: InvalidValue ) ?,
423+ user_channel_id: prev_user_channel_id_legacy,
424+ node_id: prev_node_id_legacy,
425+ } ] ) ) ) ,
426+ ( 17 , next_htlcs, ( default_value, HTLCSet ( vec![ HTLCLocator {
427+ channel_id: next_channel_id_legacy. ok_or( lightning:: ln:: msgs:: DecodeError :: InvalidValue ) ?,
428+ user_channel_id: next_user_channel_id_legacy,
429+ node_id: next_node_id_legacy,
430+ } ] ) ) ) ,
336431 } ,
337432 ( 8 , SplicePending ) => {
338433 ( 1 , channel_id, required) ,
@@ -644,7 +739,8 @@ where
644739 )
645740 . unwrap_or_else ( |e| {
646741 log_error ! ( self . logger, "Failed to force close channel after funding generation failed: {:?}" , e) ;
647- debug_assert ! ( false ,
742+ debug_assert ! (
743+ false ,
648744 "Failed to force close channel after funding generation failed"
649745 ) ;
650746 } ) ;
@@ -1306,12 +1402,8 @@ where
13061402 }
13071403 } ,
13081404 LdkEvent :: PaymentForwarded {
1309- prev_channel_id,
1310- next_channel_id,
1311- prev_user_channel_id,
1312- next_user_channel_id,
1313- prev_node_id,
1314- next_node_id,
1405+ prev_htlcs,
1406+ next_htlcs,
13151407 total_fee_earned_msat,
13161408 skimmed_fee_msat,
13171409 claim_from_onchain_tx,
@@ -1322,11 +1414,10 @@ where
13221414 let nodes = read_only_network_graph. nodes ( ) ;
13231415 let channels = self . channel_manager . list_channels ( ) ;
13241416
1325- let node_str = |channel_id : & Option < ChannelId > | {
1326- channel_id
1327- . and_then ( |channel_id| {
1328- channels. iter ( ) . find ( |c| c. channel_id == channel_id)
1329- } )
1417+ let node_str = |channel_id : & ChannelId | {
1418+ channels
1419+ . iter ( )
1420+ . find ( |c| c. channel_id == * channel_id)
13301421 . and_then ( |channel| {
13311422 nodes. get ( & NodeId :: from_pubkey ( & channel. counterparty . node_id ) )
13321423 } )
@@ -1338,21 +1429,22 @@ where
13381429 } )
13391430 } )
13401431 } ;
1341- let channel_str = |channel_id : & Option < ChannelId > | {
1342- channel_id
1343- . map ( |channel_id| format ! ( " with channel {}" , channel_id) )
1344- . unwrap_or_default ( )
1345- } ;
1346- let from_prev_str = format ! (
1347- " from {}{}" ,
1348- node_str( & prev_channel_id) ,
1349- channel_str( & prev_channel_id)
1350- ) ;
1351- let to_next_str = format ! (
1352- " to {}{}" ,
1353- node_str( & next_channel_id) ,
1354- channel_str( & next_channel_id)
1355- ) ;
1432+
1433+ let from_prev_str: String = prev_htlcs
1434+ . iter ( )
1435+ . map ( |htlc| {
1436+ format ! ( "with {} on {}" , node_str( & htlc. channel_id) , htlc. channel_id)
1437+ } )
1438+ . collect :: < Vec < _ > > ( )
1439+ . join ( ", " ) ;
1440+
1441+ let to_next_str: String = next_htlcs
1442+ . iter ( )
1443+ . map ( |htlc| {
1444+ format ! ( "with {} on {}" , node_str( & htlc. channel_id) , htlc. channel_id)
1445+ } )
1446+ . collect :: < Vec < _ > > ( )
1447+ . join ( ", " ) ;
13561448
13571449 let fee_earned = total_fee_earned_msat. unwrap_or ( 0 ) ;
13581450 if claim_from_onchain_tx {
@@ -1367,8 +1459,10 @@ where
13671459 } else {
13681460 log_info ! (
13691461 self . logger,
1370- "Forwarded payment{}{} of {}msat, earning {}msat in fees." ,
1462+ "Forwarded payment with {} inbound HTLC(s) ({}) and {} outbound HTLC(s) ({}) of {}msat, earning {}msat in fees." ,
1463+ prev_htlcs. len( ) ,
13711464 from_prev_str,
1465+ next_htlcs. len( ) ,
13721466 to_next_str,
13731467 outbound_amount_forwarded_msat. unwrap_or( 0 ) ,
13741468 fee_earned,
@@ -1378,18 +1472,16 @@ where
13781472
13791473 if let Some ( liquidity_source) = self . liquidity_source . as_ref ( ) {
13801474 let skimmed_fee_msat = skimmed_fee_msat. unwrap_or ( 0 ) ;
1381- liquidity_source
1382- . handle_payment_forwarded ( next_channel_id, skimmed_fee_msat)
1383- . await ;
1475+ for next_htlc in next_htlcs. iter ( ) {
1476+ liquidity_source
1477+ . handle_payment_forwarded ( Some ( next_htlc. channel_id ) , skimmed_fee_msat)
1478+ . await ;
1479+ }
13841480 }
13851481
13861482 let event = Event :: PaymentForwarded {
1387- prev_channel_id : prev_channel_id. expect ( "prev_channel_id expected for events generated by LDK versions greater than 0.0.107." ) ,
1388- next_channel_id : next_channel_id. expect ( "next_channel_id expected for events generated by LDK versions greater than 0.0.107." ) ,
1389- prev_user_channel_id : prev_user_channel_id. map ( UserChannelId ) ,
1390- next_user_channel_id : next_user_channel_id. map ( UserChannelId ) ,
1391- prev_node_id,
1392- next_node_id,
1483+ prev_htlcs : HTLCSet ( prev_htlcs. into_iter ( ) . map ( |h| h. into ( ) ) . collect ( ) ) ,
1484+ next_htlcs : HTLCSet ( next_htlcs. into_iter ( ) . map ( |h| h. into ( ) ) . collect ( ) ) ,
13931485 total_fee_earned_msat,
13941486 skimmed_fee_msat,
13951487 claim_from_onchain_tx,
0 commit comments