@@ -68,6 +68,7 @@ use crate::util::scid_utils::scid_from_parts;
6868
6969use crate::io;
7070use crate::prelude::*;
71+ use core::time::Duration;
7172use core::{cmp,mem,fmt};
7273use core::ops::Deref;
7374#[cfg(any(test, fuzzing, debug_assertions))]
@@ -323,6 +324,7 @@ struct OutboundHTLCOutput {
323324 source: HTLCSource,
324325 blinding_point: Option<PublicKey>,
325326 skimmed_fee_msat: Option<u64>,
327+ send_timestamp: Option<Duration>,
326328}
327329
328330/// See AwaitingRemoteRevoke ChannelState for more info
@@ -6095,10 +6097,16 @@ impl<SP: Deref> FundedChannel<SP> where
60956097 false
60966098 } else { true }
60976099 });
6100+ let now = duration_since_epoch();
60986101 pending_outbound_htlcs.retain(|htlc| {
60996102 if let &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref outcome) = &htlc.state {
61006103 log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", &htlc.payment_hash);
6101- if let OutboundHTLCOutcome::Failure(reason) = outcome.clone() { // We really want take() here, but, again, non-mut ref :(
6104+ if let OutboundHTLCOutcome::Failure(mut reason) = outcome.clone() { // We really want take() here, but, again, non-mut ref :(
6105+ if let (Some(timestamp), Some(now)) = (htlc.send_timestamp, now) {
6106+ let hold_time = u32::try_from((now - timestamp).as_millis()).unwrap_or(u32::MAX);
6107+ reason.set_hold_time(hold_time);
6108+ }
6109+
61026110 revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
61036111 } else {
61046112 finalized_claimed_htlcs.push(htlc.source.clone());
@@ -8667,6 +8675,13 @@ impl<SP: Deref> FundedChannel<SP> where
86678675 return Ok(None);
86688676 }
86698677
8678+ // Record the approximate time when the HTLC is sent to the peer. This timestamp is later used to calculate the
8679+ // htlc hold time for reporting back to the sender. There is some freedom to report a time including or
8680+ // excluding our own processing time. What we choose here doesn't matter all that much, because it will probably
8681+ // just shift sender-applied penalties between our incoming and outgoing side. So we choose measuring points
8682+ // that are simple to implement, and we do it on the outgoing side because then the failure message that encodes
8683+ // the hold time still needs to be built in channel manager.
8684+ let timestamp = duration_since_epoch();
86708685 self.context.pending_outbound_htlcs.push(OutboundHTLCOutput {
86718686 htlc_id: self.context.next_holder_htlc_id,
86728687 amount_msat,
@@ -8676,6 +8691,7 @@ impl<SP: Deref> FundedChannel<SP> where
86768691 source,
86778692 blinding_point,
86788693 skimmed_fee_msat,
8694+ send_timestamp: timestamp,
86798695 });
86808696
86818697 let res = msgs::UpdateAddHTLC {
@@ -10673,6 +10689,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1067310689 },
1067410690 skimmed_fee_msat: None,
1067510691 blinding_point: None,
10692+ send_timestamp: None,
1067610693 });
1067710694 }
1067810695
@@ -11195,6 +11212,18 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1119511212 }
1119611213}
1119711214
11215+ fn duration_since_epoch() -> Option<Duration> {
11216+ #[cfg(not(feature = "std"))]
11217+ let now = None;
11218+
11219+ #[cfg(feature = "std")]
11220+ let now = Some(std::time::SystemTime::now()
11221+ .duration_since(std::time::SystemTime::UNIX_EPOCH)
11222+ .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"));
11223+
11224+ now
11225+ }
11226+
1119811227#[cfg(test)]
1119911228mod tests {
1120011229 use std::cmp;
@@ -11430,6 +11459,7 @@ mod tests {
1143011459 },
1143111460 skimmed_fee_msat: None,
1143211461 blinding_point: None,
11462+ send_timestamp: None,
1143311463 });
1143411464
1143511465 // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
@@ -11814,6 +11844,7 @@ mod tests {
1181411844 source: dummy_htlc_source.clone(),
1181511845 skimmed_fee_msat: None,
1181611846 blinding_point: None,
11847+ send_timestamp: None,
1181711848 };
1181811849 let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10];
1181911850 for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() {
@@ -12136,6 +12167,7 @@ mod tests {
1213612167 source: HTLCSource::dummy(),
1213712168 skimmed_fee_msat: None,
1213812169 blinding_point: None,
12170+ send_timestamp: None,
1213912171 };
1214012172 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).to_byte_array();
1214112173 out
@@ -12150,6 +12182,7 @@ mod tests {
1215012182 source: HTLCSource::dummy(),
1215112183 skimmed_fee_msat: None,
1215212184 blinding_point: None,
12185+ send_timestamp: None,
1215312186 };
1215412187 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).to_byte_array();
1215512188 out
@@ -12562,6 +12595,7 @@ mod tests {
1256212595 source: HTLCSource::dummy(),
1256312596 skimmed_fee_msat: None,
1256412597 blinding_point: None,
12598+ send_timestamp: None,
1256512599 };
1256612600 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1256712601 out
@@ -12576,6 +12610,7 @@ mod tests {
1257612610 source: HTLCSource::dummy(),
1257712611 skimmed_fee_msat: None,
1257812612 blinding_point: None,
12613+ send_timestamp: None,
1257912614 };
1258012615 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1258112616 out
0 commit comments