Skip to content

Commit 4512570

Browse files
author
Matt Corallo
committed
Merge PR 'Add amounts to HTLC locators' (#4767)
from amt-htlc-locators into main Reviewed-on: https://git.rust-bitcoin.org/lightningdevkit/rust-lightning/pulls/4767 Reviewed-by: Matt Corallo <matt@noreply.gitea.bitcoin.ninja>
2 parents eb70921 + 588054e commit 4512570

6 files changed

Lines changed: 99 additions & 10 deletions

File tree

lightning/src/events/mod.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,9 @@ pub struct HTLCLocator {
866866
/// The channel that the HTLC was sent or received on.
867867
pub channel_id: ChannelId,
868868

869+
/// The amount, in milli-satoshis, of the HTLC that was sent or received, if known.
870+
pub amount_msat: Option<u64>,
871+
869872
/// The `user_channel_id` for `channel_id`.
870873
///
871874
/// This will be `None` if the payment was settled via an on-chain transaction. It will also
@@ -883,6 +886,7 @@ impl_ser_tlv_based!(HTLCLocator, {
883886
(1, channel_id, required),
884887
(3, user_channel_id, option),
885888
(5, node_id, option),
889+
(7, amount_msat, option),
886890
});
887891

888892
/// An Event which you should probably take some action in response to.
@@ -2215,6 +2219,7 @@ impl Writeable for Event {
22152219
);
22162220
let empty_locator = HTLCLocator {
22172221
channel_id: ChannelId::new_zero(),
2222+
amount_msat: None,
22182223
user_channel_id: None,
22192224
node_id: None,
22202225
};
@@ -2782,11 +2787,14 @@ impl MaybeReadable for Event {
27822787
// with pending forwards to 0.1 for any version 0.0.123 or earlier.
27832788
(17, prev_htlcs, (default_value, vec![HTLCLocator{
27842789
channel_id: prev_channel_id_legacy.ok_or(DecodeError::InvalidValue)?,
2790+
amount_msat: total_fee_earned_msat
2791+
.map(|fee| outbound_amount_forwarded_msat + fee),
27852792
user_channel_id: prev_user_channel_id_legacy,
27862793
node_id: prev_node_id_legacy,
27872794
}])),
27882795
(19, next_htlcs, (default_value, vec![HTLCLocator{
27892796
channel_id: next_channel_id_legacy.ok_or(DecodeError::InvalidValue)?,
2797+
amount_msat: Some(outbound_amount_forwarded_msat),
27902798
user_channel_id: next_user_channel_id_legacy,
27912799
node_id: next_node_id_legacy,
27922800
}])),
@@ -3228,6 +3236,48 @@ impl MaybeReadable for Event {
32283236
}
32293237
}
32303238

3239+
#[cfg(test)]
3240+
mod tests {
3241+
use super::*;
3242+
3243+
#[test]
3244+
fn legacy_payment_forwarded_preserves_unknown_inbound_htlc_amount() {
3245+
let prev_channel_id = ChannelId::from_bytes([1; 32]);
3246+
let next_channel_id = ChannelId::from_bytes([2; 32]);
3247+
let mut encoded_legacy_event = vec![
3248+
7, // Event::PaymentForwarded
3249+
81, // TLV stream length
3250+
1, 32, // prev_channel_id
3251+
];
3252+
encoded_legacy_event.extend_from_slice(&[1; 32]);
3253+
encoded_legacy_event.extend_from_slice(&[2, 1, 0]); // claim_from_onchain_tx
3254+
encoded_legacy_event.extend_from_slice(&[3, 32]); // next_channel_id
3255+
encoded_legacy_event.extend_from_slice(&[2; 32]);
3256+
// outbound_amount_forwarded_msat
3257+
encoded_legacy_event.extend_from_slice(&[5, 8, 0, 0, 0, 0, 0, 45, 198, 192]);
3258+
3259+
match Event::read(&mut &encoded_legacy_event[..]).unwrap().unwrap() {
3260+
Event::PaymentForwarded {
3261+
prev_htlcs,
3262+
next_htlcs,
3263+
total_fee_earned_msat,
3264+
outbound_amount_forwarded_msat,
3265+
..
3266+
} => {
3267+
assert_eq!(total_fee_earned_msat, None);
3268+
assert_eq!(outbound_amount_forwarded_msat, 3_000_000);
3269+
assert_eq!(prev_htlcs.len(), 1);
3270+
assert_eq!(prev_htlcs[0].channel_id, prev_channel_id);
3271+
assert_eq!(prev_htlcs[0].amount_msat, None);
3272+
assert_eq!(next_htlcs.len(), 1);
3273+
assert_eq!(next_htlcs[0].channel_id, next_channel_id);
3274+
assert_eq!(next_htlcs[0].amount_msat, Some(3_000_000));
3275+
},
3276+
_ => panic!("expected PaymentForwarded event"),
3277+
}
3278+
}
3279+
}
3280+
32313281
/// A trait indicating an object may generate events.
32323282
///
32333283
/// Events are processed by passing an [`EventHandler`] to [`process_pending_events`].

lightning/src/ln/channel.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8175,6 +8175,7 @@ where
81758175
let prev_hop_data = HTLCPreviousHopData {
81768176
prev_outbound_scid_alias,
81778177
user_channel_id: Some(user_channel_id),
8178+
amount_msat: Some(htlc.amount_msat),
81788179
htlc_id: htlc.htlc_id,
81798180
incoming_packet_shared_secret: *incoming_packet_shared_secret,
81808181
phantom_shared_secret: *phantom_shared_secret,

lightning/src/ln/channelmanager.rs

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,7 @@ impl PendingAddHTLCInfo {
481481
HTLCPreviousHopData {
482482
prev_outbound_scid_alias: self.prev_outbound_scid_alias,
483483
user_channel_id: Some(self.prev_user_channel_id),
484+
amount_msat: self.forward_info.incoming_amt_msat,
484485
outpoint: self.prev_funding_outpoint,
485486
channel_id: self.prev_channel_id,
486487
counterparty_node_id: Some(self.prev_counterparty_node_id),
@@ -944,6 +945,7 @@ mod fuzzy_channelmanager {
944945
pub struct HTLCPreviousHopData {
945946
pub prev_outbound_scid_alias: u64,
946947
pub user_channel_id: Option<u128>,
948+
pub amount_msat: Option<u64>,
947949
pub htlc_id: u64,
948950
pub incoming_packet_shared_secret: [u8; 32],
949951
pub phantom_shared_secret: Option<[u8; 32]>,
@@ -960,12 +962,13 @@ mod fuzzy_channelmanager {
960962
pub cltv_expiry: Option<u32>,
961963
}
962964

963-
impl From<&HTLCPreviousHopData> for events::HTLCLocator {
964-
fn from(value: &HTLCPreviousHopData) -> Self {
965+
impl HTLCPreviousHopData {
966+
pub(super) fn htlc_locator(&self, amount_msat: Option<u64>) -> events::HTLCLocator {
965967
events::HTLCLocator {
966-
channel_id: value.channel_id,
967-
user_channel_id: value.user_channel_id,
968-
node_id: value.counterparty_node_id,
968+
channel_id: self.channel_id,
969+
amount_msat,
970+
user_channel_id: self.user_channel_id,
971+
node_id: self.counterparty_node_id,
969972
}
970973
}
971974
}
@@ -8860,6 +8863,7 @@ impl<
88608863
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
88618864
prev_outbound_scid_alias: prev_hop.prev_outbound_scid_alias,
88628865
user_channel_id: prev_hop.user_channel_id,
8866+
amount_msat: Some(value),
88638867
counterparty_node_id: prev_hop.counterparty_node_id,
88648868
channel_id: prev_channel_id,
88658869
outpoint: prev_funding_outpoint,
@@ -10522,7 +10526,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1052210526
}
1052310527
},
1052410528
HTLCSource::PreviousHopData(hop_data) => {
10525-
let prev_htlcs = vec![events::HTLCLocator::from(&hop_data)];
10529+
let event_prev_hop_data = hop_data.clone();
1052610530
self.claim_funds_from_htlc_forward_hop(
1052710531
payment_preimage,
1052810532
|htlc_claim_value_msat: Option<u64>| -> Option<events::Event> {
@@ -10536,11 +10540,16 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1053610540
skimmed_fee_msat <= total_fee_earned_msat,
1053710541
"skimmed_fee_msat must always be included in total_fee_earned_msat"
1053810542
);
10543+
let prev_htlc_amount_msat =
10544+
event_prev_hop_data.amount_msat.or(htlc_claim_value_msat);
1053910545

1054010546
Some(events::Event::PaymentForwarded {
10541-
prev_htlcs,
10547+
prev_htlcs: vec![
10548+
event_prev_hop_data.htlc_locator(prev_htlc_amount_msat)
10549+
],
1054210550
next_htlcs: vec![events::HTLCLocator {
1054310551
channel_id: next_channel_id,
10552+
amount_msat: Some(forwarded_htlc_value_msat),
1054410553
user_channel_id: next_user_channel_id,
1054510554
node_id: Some(next_channel_counterparty_node_id),
1054610555
}],
@@ -10561,20 +10570,29 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
1056110570
},
1056210571
HTLCSource::TrampolineForward { previous_hop_data, .. } => {
1056310572
// Only emit a single event for trampoline claims.
10564-
let prev_htlcs: Vec<events::HTLCLocator> =
10565-
previous_hop_data.iter().map(Into::into).collect();
10573+
let mut event_prev_htlcs = Some(
10574+
previous_hop_data.iter().map(|hop| hop.htlc_locator(hop.amount_msat)).collect(),
10575+
);
1056610576
for (i, current_previous_hop_data) in previous_hop_data.into_iter().enumerate() {
1056710577
self.claim_funds_from_htlc_forward_hop(
1056810578
payment_preimage,
1056910579
|_: Option<u64>| -> Option<events::Event> {
1057010580
if i == 0 {
10581+
let Some(prev_htlcs) = event_prev_htlcs.take() else {
10582+
debug_assert!(
10583+
false,
10584+
"trampoline forward event already emitted"
10585+
);
10586+
return None;
10587+
};
1057110588
Some(events::Event::PaymentForwarded {
10572-
prev_htlcs: prev_htlcs.clone(),
10589+
prev_htlcs,
1057310590
// TODO: When trampoline payments are tracked in our
1057410591
// pending_outbound_payments, we'll be able to provide all the
1057510592
// outgoing htlcs for this forward.
1057610593
next_htlcs: vec![events::HTLCLocator {
1057710594
channel_id: next_channel_id,
10595+
amount_msat: Some(forwarded_htlc_value_msat),
1057810596
user_channel_id: next_user_channel_id,
1057910597
node_id: Some(next_channel_counterparty_node_id),
1058010598
}],
@@ -18343,6 +18361,7 @@ impl_ser_tlv_based!(HTLCPreviousHopData, {
1834318361
(9, channel_id, (default_value, ChannelId::v1_from_funding_outpoint(outpoint.0.unwrap()))),
1834418362
(11, counterparty_node_id, option),
1834518363
(13, trampoline_shared_secret, option),
18364+
(15, amount_msat, option),
1834618365
});
1834718366

1834818367
fn write_claimable_htlc<W: Writer>(

lightning/src/ln/functional_test_utils.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3097,6 +3097,7 @@ pub fn expect_payment_forwarded<CM: AChannelManager, H: NodeHolder<CM = CM>>(
30973097
total_fee_earned_msat,
30983098
skimmed_fee_msat,
30993099
claim_from_onchain_tx,
3100+
outbound_amount_forwarded_msat,
31003101
..
31013102
} => {
31023103
assert_eq!(prev_htlcs.len(), 1);
@@ -3115,6 +3116,19 @@ pub fn expect_payment_forwarded<CM: AChannelManager, H: NodeHolder<CM = CM>>(
31153116
// Check that the (knowingly) withheld amount is always less or equal to the expected
31163117
// overpaid amount.
31173118
assert!(skimmed_fee_msat == expected_extra_fees_msat);
3119+
match expected_fee {
3120+
Some(_) => {
3121+
let actual_fee = total_fee_earned_msat.unwrap();
3122+
assert_eq!(next_htlcs[0].amount_msat, Some(outbound_amount_forwarded_msat));
3123+
assert_eq!(
3124+
prev_htlcs[0].amount_msat,
3125+
Some(next_htlcs[0].amount_msat.unwrap() + actual_fee)
3126+
);
3127+
},
3128+
None => {
3129+
assert_eq!(total_fee_earned_msat, None);
3130+
},
3131+
}
31183132
if !upstream_force_closed {
31193133
let prev_node_id = prev_htlcs[0].node_id.unwrap();
31203134
let prev_channel_id = prev_htlcs[0].channel_id;

lightning/src/ln/functional_tests.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,8 +1506,10 @@ pub fn test_htlc_on_chain_success() {
15061506
} => {
15071507
assert_eq!(total_fee_earned_msat, Some(1000));
15081508
assert_eq!(prev_htlcs[0].channel_id, chan_id);
1509+
assert_eq!(prev_htlcs[0].amount_msat, Some(3001000));
15091510
assert_eq!(claim_from_onchain_tx, true);
15101511
assert_eq!(next_htlcs[0].channel_id, chan_2.2);
1512+
assert_eq!(next_htlcs[0].amount_msat, Some(3000000));
15111513
assert_eq!(outbound_amount_forwarded_msat, 3000000);
15121514
},
15131515
_ => panic!(),
@@ -1523,8 +1525,10 @@ pub fn test_htlc_on_chain_success() {
15231525
} => {
15241526
assert_eq!(total_fee_earned_msat, Some(1000));
15251527
assert_eq!(prev_htlcs[0].channel_id, chan_id);
1528+
assert_eq!(prev_htlcs[0].amount_msat, Some(3001000));
15261529
assert_eq!(claim_from_onchain_tx, true);
15271530
assert_eq!(next_htlcs[0].channel_id, chan_2.2);
1531+
assert_eq!(next_htlcs[0].amount_msat, Some(3000000));
15281532
assert_eq!(outbound_amount_forwarded_msat, 3000000);
15291533
},
15301534
_ => panic!(),

lightning/src/ln/trampoline_forward_tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ fn test_prev_hop_data(htlc_id: u64) -> HTLCPreviousHopData {
2727
HTLCPreviousHopData {
2828
prev_outbound_scid_alias: 0,
2929
user_channel_id: None,
30+
amount_msat: None,
3031
htlc_id,
3132
incoming_packet_shared_secret: [0; 32],
3233
phantom_shared_secret: None,

0 commit comments

Comments
 (0)