Skip to content

Commit bca896a

Browse files
committed
Decode hold times as a sender
Hold times are surfaced via the PaymentPathSuccessful event.
1 parent a3d4b56 commit bca896a

File tree

9 files changed

+263
-25
lines changed

9 files changed

+263
-25
lines changed

fuzz/src/process_onion_failure.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
115115
let path = Path { hops, blinded_tail };
116116

117117
let htlc_source = HTLCSource::OutboundRoute {
118-
path,
118+
path: path.clone(),
119119
session_priv,
120120
first_hop_htlc_msat: 0,
121121
payment_id,
@@ -133,8 +133,19 @@ fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
133133
} else {
134134
None
135135
};
136-
let encrypted_packet = OnionErrorPacket { data: failure_data.into(), attribution_data };
136+
let encrypted_packet =
137+
OnionErrorPacket { data: failure_data.into(), attribution_data: attribution_data.clone() };
137138
lightning::ln::process_onion_failure(&secp_ctx, &logger, &htlc_source, encrypted_packet);
139+
140+
if let Some(attribution_data) = attribution_data {
141+
lightning::ln::decode_fulfill_attribution_data(
142+
&secp_ctx,
143+
&logger,
144+
&path,
145+
&session_priv,
146+
attribution_data,
147+
);
148+
}
138149
}
139150

140151
/// Method that needs to be added manually, {name}_test

lightning-background-processor/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2732,6 +2732,7 @@ mod tests {
27322732
payment_id: PaymentId([42; 32]),
27332733
payment_hash: None,
27342734
path: path.clone(),
2735+
hold_times: None,
27352736
});
27362737
let event = $receive.expect("PaymentPathSuccessful not handled within deadline");
27372738
match event {

lightning/src/events/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,6 +1102,8 @@ pub enum Event {
11021102
///
11031103
/// May contain a closed channel if the HTLC sent along the path was fulfilled on chain.
11041104
path: Path,
1105+
/// The hold times as reported by each hop.
1106+
hold_times: Option<Vec<u32>>,
11051107
},
11061108
/// Indicates an outbound HTLC we sent failed, likely due to an intermediary node being unable to
11071109
/// handle the HTLC.
@@ -1910,10 +1912,16 @@ impl Writeable for Event {
19101912
(4, funding_info, required),
19111913
})
19121914
},
1913-
&Event::PaymentPathSuccessful { ref payment_id, ref payment_hash, ref path } => {
1915+
&Event::PaymentPathSuccessful {
1916+
ref payment_id,
1917+
ref payment_hash,
1918+
ref path,
1919+
ref hold_times,
1920+
} => {
19141921
13u8.write(writer)?;
19151922
write_tlv_fields!(writer, {
19161923
(0, payment_id, required),
1924+
(1, hold_times, option),
19171925
(2, payment_hash, option),
19181926
(4, path.hops, required_vec),
19191927
(6, path.blinded_tail, option),
@@ -2413,6 +2421,7 @@ impl MaybeReadable for Event {
24132421
let mut f = || {
24142422
_init_and_read_len_prefixed_tlv_fields!(reader, {
24152423
(0, payment_id, required),
2424+
(1, hold_times, option),
24162425
(2, payment_hash, option),
24172426
(4, path, required_vec),
24182427
(6, blinded_tail, option),
@@ -2421,6 +2430,7 @@ impl MaybeReadable for Event {
24212430
payment_id: payment_id.0.unwrap(),
24222431
payment_hash,
24232432
path: Path { hops: path, blinded_tail },
2433+
hold_times,
24242434
}))
24252435
};
24262436
f()

lightning/src/ln/channel.rs

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ impl OutboundHTLCState {
404404
enum OutboundHTLCOutcome {
405405
/// We started always filling in the preimages here in 0.0.105, and the requirement
406406
/// that the preimages always be filled in was added in 0.2.
407-
Success(PaymentPreimage, #[allow(dead_code)] Option<AttributionData>),
407+
Success(PaymentPreimage, Option<AttributionData>),
408408
Failure(HTLCFailReason),
409409
}
410410

@@ -1184,7 +1184,7 @@ pub(super) struct MonitorRestoreUpdates {
11841184
pub order: RAACommitmentOrder,
11851185
pub accepted_htlcs: Vec<(PendingHTLCInfo, u64)>,
11861186
pub failed_htlcs: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
1187-
pub finalized_claimed_htlcs: Vec<HTLCSource>,
1187+
pub finalized_claimed_htlcs: Vec<(HTLCSource, Option<AttributionData>)>,
11881188
pub pending_update_adds: Vec<msgs::UpdateAddHTLC>,
11891189
pub funding_broadcastable: Option<Transaction>,
11901190
pub channel_ready: Option<msgs::ChannelReady>,
@@ -2314,7 +2314,7 @@ where
23142314
// but need to handle this somehow or we run the risk of losing HTLCs!
23152315
monitor_pending_forwards: Vec<(PendingHTLCInfo, u64)>,
23162316
monitor_pending_failures: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
2317-
monitor_pending_finalized_fulfills: Vec<HTLCSource>,
2317+
monitor_pending_finalized_fulfills: Vec<(HTLCSource, Option<AttributionData>)>,
23182318
monitor_pending_update_adds: Vec<msgs::UpdateAddHTLC>,
23192319
monitor_pending_tx_signatures: Option<msgs::TxSignatures>,
23202320

@@ -6677,7 +6677,8 @@ where
66776677
));
66786678
}
66796679

6680-
let outcome = OutboundHTLCOutcome::Success(msg.payment_preimage, None);
6680+
let outcome =
6681+
OutboundHTLCOutcome::Success(msg.payment_preimage, msg.attribution_data.clone());
66816682
self.mark_outbound_htlc_removed(msg.htlc_id, outcome).map(|htlc| {
66826683
(htlc.source.clone(), htlc.amount_msat, htlc.skimmed_fee_msat, htlc.send_timestamp)
66836684
})
@@ -7498,16 +7499,21 @@ where
74987499
&htlc.payment_hash
74997500
);
75007501
// We really want take() here, but, again, non-mut ref :(
7501-
if let OutboundHTLCOutcome::Failure(mut reason) = outcome.clone() {
7502-
hold_time(htlc.send_timestamp, now).map(|hold_time| {
7503-
reason.set_hold_time(hold_time);
7504-
});
7505-
7506-
revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
7507-
} else {
7508-
finalized_claimed_htlcs.push(htlc.source.clone());
7509-
// They fulfilled, so we sent them money
7510-
value_to_self_msat_diff -= htlc.amount_msat as i64;
7502+
match outcome.clone() {
7503+
OutboundHTLCOutcome::Failure(mut reason) => {
7504+
hold_time(htlc.send_timestamp, now).map(|hold_time| {
7505+
reason.set_hold_time(hold_time);
7506+
});
7507+
revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
7508+
},
7509+
OutboundHTLCOutcome::Success(_, attribution_data) => {
7510+
// Even though a fast track was taken for fulfilled HTLCs to the incoming side, we still
7511+
// pass along attribution data here so that we can include hold time information in the
7512+
// final PaymentPathSuccessful events.
7513+
finalized_claimed_htlcs.push((htlc.source.clone(), attribution_data));
7514+
// They fulfilled, so we sent them money
7515+
value_to_self_msat_diff -= htlc.amount_msat as i64;
7516+
},
75117517
}
75127518
false
75137519
} else {
@@ -7990,7 +7996,7 @@ where
79907996
&mut self, resend_raa: bool, resend_commitment: bool, resend_channel_ready: bool,
79917997
mut pending_forwards: Vec<(PendingHTLCInfo, u64)>,
79927998
mut pending_fails: Vec<(HTLCSource, PaymentHash, HTLCFailReason)>,
7993-
mut pending_finalized_claimed_htlcs: Vec<HTLCSource>,
7999+
mut pending_finalized_claimed_htlcs: Vec<(HTLCSource, Option<AttributionData>)>,
79948000
) {
79958001
self.context.monitor_pending_revoke_and_ack |= resend_raa;
79968002
self.context.monitor_pending_commitment_signed |= resend_commitment;

lightning/src/ln/channelmanager.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@ use crate::ln::onion_payment::{
7777
NextPacketDetails,
7878
};
7979
use crate::ln::onion_utils::{self};
80+
use crate::ln::onion_utils::{
81+
decode_fulfill_attribution_data, HTLCFailReason, LocalHTLCFailureReason,
82+
};
8083
use crate::ln::onion_utils::{process_fulfill_attribution_data, AttributionData};
81-
use crate::ln::onion_utils::{HTLCFailReason, LocalHTLCFailureReason};
8284
use crate::ln::our_peer_storage::EncryptedOurPeerStorage;
8385
#[cfg(test)]
8486
use crate::ln::outbound_payment;
@@ -8279,8 +8281,38 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
82798281
);
82808282
}
82818283

8282-
fn finalize_claims(&self, sources: Vec<HTLCSource>) {
8283-
self.pending_outbound_payments.finalize_claims(sources, &self.pending_events);
8284+
fn finalize_claims(&self, sources: Vec<(HTLCSource, Option<AttributionData>)>) {
8285+
// Decode attribution data to hold times.
8286+
let hold_times = sources.into_iter().filter_map(|(source, attribution_data)| {
8287+
if let HTLCSource::OutboundRoute { ref session_priv, ref path, .. } = source {
8288+
// If the path has trampoline hops, we need to hash the session private key to get the outer session key.
8289+
let derived_key;
8290+
let session_priv = if path.has_trampoline_hops() {
8291+
let session_priv_hash =
8292+
Sha256::hash(&session_priv.secret_bytes()).to_byte_array();
8293+
derived_key = SecretKey::from_slice(&session_priv_hash[..]).unwrap();
8294+
&derived_key
8295+
} else {
8296+
session_priv
8297+
};
8298+
8299+
let hold_times = attribution_data.map(|attribution_data| {
8300+
decode_fulfill_attribution_data(
8301+
&self.secp_ctx,
8302+
&self.logger,
8303+
path,
8304+
session_priv,
8305+
attribution_data,
8306+
)
8307+
});
8308+
8309+
Some((source, hold_times))
8310+
} else {
8311+
None
8312+
}
8313+
});
8314+
8315+
self.pending_outbound_payments.finalize_claims(hold_times, &self.pending_events);
82848316
}
82858317

82868318
fn claim_funds_internal(
@@ -17114,15 +17146,15 @@ mod tests {
1711417146
let events = nodes[0].node.get_and_clear_pending_events();
1711517147
assert_eq!(events.len(), 2);
1711617148
match events[0] {
17117-
Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path } => {
17149+
Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path, .. } => {
1711817150
assert_eq!(payment_id, *actual_payment_id);
1711917151
assert_eq!(our_payment_hash, *payment_hash.as_ref().unwrap());
1712017152
assert_eq!(route.paths[0], *path);
1712117153
},
1712217154
_ => panic!("Unexpected event"),
1712317155
}
1712417156
match events[1] {
17125-
Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path } => {
17157+
Event::PaymentPathSuccessful { payment_id: ref actual_payment_id, ref payment_hash, ref path, ..} => {
1712617158
assert_eq!(payment_id, *actual_payment_id);
1712717159
assert_eq!(our_payment_hash, *payment_hash.as_ref().unwrap());
1712817160
assert_eq!(route.paths[0], *path);

lightning/src/ln/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ pub use onion_utils::{create_payment_onion, LocalHTLCFailureReason};
5252
// without the node parameter being mut. This is incorrect, and thus newer rustcs will complain
5353
// about an unnecessary mut. Thus, we silence the unused_mut warning in two test modules below.
5454

55+
#[cfg(fuzzing)]
56+
pub use onion_utils::decode_fulfill_attribution_data;
5557
#[cfg(fuzzing)]
5658
pub use onion_utils::process_onion_failure;
5759

0 commit comments

Comments
 (0)