@@ -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.saturating_sub(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 {
@@ -10674,6 +10690,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1067410690 },
1067510691 skimmed_fee_msat: None,
1067610692 blinding_point: None,
10693+ send_timestamp: None,
1067710694 });
1067810695 }
1067910696
@@ -11192,6 +11209,18 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1119211209 }
1119311210}
1119411211
11212+ fn duration_since_epoch() -> Option<Duration> {
11213+ #[cfg(not(feature = "std"))]
11214+ let now = None;
11215+
11216+ #[cfg(feature = "std")]
11217+ let now = Some(std::time::SystemTime::now()
11218+ .duration_since(std::time::SystemTime::UNIX_EPOCH)
11219+ .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"));
11220+
11221+ now
11222+ }
11223+
1119511224#[cfg(test)]
1119611225mod tests {
1119711226 use std::cmp;
@@ -11427,6 +11456,7 @@ mod tests {
1142711456 },
1142811457 skimmed_fee_msat: None,
1142911458 blinding_point: None,
11459+ send_timestamp: None,
1143011460 });
1143111461
1143211462 // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
@@ -11811,6 +11841,7 @@ mod tests {
1181111841 source: dummy_htlc_source.clone(),
1181211842 skimmed_fee_msat: None,
1181311843 blinding_point: None,
11844+ send_timestamp: None,
1181411845 };
1181511846 let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10];
1181611847 for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() {
@@ -12133,6 +12164,7 @@ mod tests {
1213312164 source: HTLCSource::dummy(),
1213412165 skimmed_fee_msat: None,
1213512166 blinding_point: None,
12167+ send_timestamp: None,
1213612168 };
1213712169 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).to_byte_array();
1213812170 out
@@ -12147,6 +12179,7 @@ mod tests {
1214712179 source: HTLCSource::dummy(),
1214812180 skimmed_fee_msat: None,
1214912181 blinding_point: None,
12182+ send_timestamp: None,
1215012183 };
1215112184 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).to_byte_array();
1215212185 out
@@ -12559,6 +12592,7 @@ mod tests {
1255912592 source: HTLCSource::dummy(),
1256012593 skimmed_fee_msat: None,
1256112594 blinding_point: None,
12595+ send_timestamp: None,
1256212596 };
1256312597 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1256412598 out
@@ -12573,6 +12607,7 @@ mod tests {
1257312607 source: HTLCSource::dummy(),
1257412608 skimmed_fee_msat: None,
1257512609 blinding_point: None,
12610+ send_timestamp: None,
1257612611 };
1257712612 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1257812613 out
0 commit comments