@@ -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
@@ -11191,6 +11208,18 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1119111208 }
1119211209}
1119311210
11211+ fn duration_since_epoch() -> Option<Duration> {
11212+ #[cfg(not(feature = "std"))]
11213+ let now = None;
11214+
11215+ #[cfg(feature = "std")]
11216+ let now = Some(std::time::SystemTime::now()
11217+ .duration_since(std::time::SystemTime::UNIX_EPOCH)
11218+ .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"));
11219+
11220+ now
11221+ }
11222+
1119411223#[cfg(test)]
1119511224mod tests {
1119611225 use std::cmp;
@@ -11426,6 +11455,7 @@ mod tests {
1142611455 },
1142711456 skimmed_fee_msat: None,
1142811457 blinding_point: None,
11458+ send_timestamp: None,
1142911459 });
1143011460
1143111461 // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
@@ -11810,6 +11840,7 @@ mod tests {
1181011840 source: dummy_htlc_source.clone(),
1181111841 skimmed_fee_msat: None,
1181211842 blinding_point: None,
11843+ send_timestamp: None,
1181311844 };
1181411845 let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10];
1181511846 for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() {
@@ -12132,6 +12163,7 @@ mod tests {
1213212163 source: HTLCSource::dummy(),
1213312164 skimmed_fee_msat: None,
1213412165 blinding_point: None,
12166+ timestamp: None,
1213512167 };
1213612168 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).to_byte_array();
1213712169 out
@@ -12146,6 +12178,7 @@ mod tests {
1214612178 source: HTLCSource::dummy(),
1214712179 skimmed_fee_msat: None,
1214812180 blinding_point: None,
12181+ timestamp: None,
1214912182 };
1215012183 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).to_byte_array();
1215112184 out
@@ -12558,6 +12591,7 @@ mod tests {
1255812591 source: HTLCSource::dummy(),
1255912592 skimmed_fee_msat: None,
1256012593 blinding_point: None,
12594+ timestamp: None,
1256112595 };
1256212596 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1256312597 out
@@ -12572,6 +12606,7 @@ mod tests {
1257212606 source: HTLCSource::dummy(),
1257312607 skimmed_fee_msat: None,
1257412608 blinding_point: None,
12609+ timestamp: None,
1257512610 };
1257612611 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1257712612 out
0 commit comments