@@ -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
@@ -6073,10 +6075,16 @@ impl<SP: Deref> FundedChannel<SP> where
60736075 false
60746076 } else { true }
60756077 });
6078+ let now = duration_since_epoch();
60766079 pending_outbound_htlcs.retain(|htlc| {
60776080 if let &OutboundHTLCState::AwaitingRemovedRemoteRevoke(ref outcome) = &htlc.state {
60786081 log_trace!(logger, " ...removing outbound AwaitingRemovedRemoteRevoke {}", &htlc.payment_hash);
6079- if let OutboundHTLCOutcome::Failure(reason) = outcome.clone() { // We really want take() here, but, again, non-mut ref :(
6082+ if let OutboundHTLCOutcome::Failure(mut reason) = outcome.clone() { // We really want take() here, but, again, non-mut ref :(
6083+ if let (Some(timestamp), Some(now)) = (htlc.send_timestamp, now) {
6084+ let hold_time = u32::try_from(now.saturating_sub(timestamp).as_millis()).unwrap_or(u32::MAX);
6085+ reason.set_hold_time(hold_time);
6086+ }
6087+
60806088 revoked_htlcs.push((htlc.source.clone(), htlc.payment_hash, reason));
60816089 } else {
60826090 finalized_claimed_htlcs.push(htlc.source.clone());
@@ -8648,6 +8656,13 @@ impl<SP: Deref> FundedChannel<SP> where
86488656 return Ok(None);
86498657 }
86508658
8659+ // Record the approximate time when the HTLC is sent to the peer. This timestamp is later used to calculate the
8660+ // htlc hold time for reporting back to the sender. There is some freedom to report a time including or
8661+ // excluding our own processing time. What we choose here doesn't matter all that much, because it will probably
8662+ // just shift sender-applied penalties between our incoming and outgoing side. So we choose measuring points
8663+ // that are simple to implement, and we do it on the outgoing side because then the failure message that encodes
8664+ // the hold time still needs to be built in channel manager.
8665+ let send_timestamp = duration_since_epoch();
86518666 self.context.pending_outbound_htlcs.push(OutboundHTLCOutput {
86528667 htlc_id: self.context.next_holder_htlc_id,
86538668 amount_msat,
@@ -8657,6 +8672,7 @@ impl<SP: Deref> FundedChannel<SP> where
86578672 source,
86588673 blinding_point,
86598674 skimmed_fee_msat,
8675+ send_timestamp,
86608676 });
86618677
86628678 let res = msgs::UpdateAddHTLC {
@@ -10657,6 +10673,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1065710673 },
1065810674 skimmed_fee_msat: None,
1065910675 blinding_point: None,
10676+ send_timestamp: None,
1066010677 });
1066110678 }
1066210679
@@ -11175,6 +11192,18 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, &'c Channel
1117511192 }
1117611193}
1117711194
11195+ fn duration_since_epoch() -> Option<Duration> {
11196+ #[cfg(not(feature = "std"))]
11197+ let now = None;
11198+
11199+ #[cfg(feature = "std")]
11200+ let now = Some(std::time::SystemTime::now()
11201+ .duration_since(std::time::SystemTime::UNIX_EPOCH)
11202+ .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"));
11203+
11204+ now
11205+ }
11206+
1117811207#[cfg(test)]
1117911208mod tests {
1118011209 use std::cmp;
@@ -11410,6 +11439,7 @@ mod tests {
1141011439 },
1141111440 skimmed_fee_msat: None,
1141211441 blinding_point: None,
11442+ send_timestamp: None,
1141311443 });
1141411444
1141511445 // Make sure when Node A calculates their local commitment transaction, none of the HTLCs pass
@@ -11794,6 +11824,7 @@ mod tests {
1179411824 source: dummy_htlc_source.clone(),
1179511825 skimmed_fee_msat: None,
1179611826 blinding_point: None,
11827+ send_timestamp: None,
1179711828 };
1179811829 let mut pending_outbound_htlcs = vec![dummy_outbound_output.clone(); 10];
1179911830 for (idx, htlc) in pending_outbound_htlcs.iter_mut().enumerate() {
@@ -12107,6 +12138,7 @@ mod tests {
1210712138 source: HTLCSource::dummy(),
1210812139 skimmed_fee_msat: None,
1210912140 blinding_point: None,
12141+ send_timestamp: None,
1211012142 };
1211112143 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0202020202020202020202020202020202020202020202020202020202020202").unwrap()).to_byte_array();
1211212144 out
@@ -12121,6 +12153,7 @@ mod tests {
1212112153 source: HTLCSource::dummy(),
1212212154 skimmed_fee_msat: None,
1212312155 blinding_point: None,
12156+ send_timestamp: None,
1212412157 };
1212512158 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0303030303030303030303030303030303030303030303030303030303030303").unwrap()).to_byte_array();
1212612159 out
@@ -12533,6 +12566,7 @@ mod tests {
1253312566 source: HTLCSource::dummy(),
1253412567 skimmed_fee_msat: None,
1253512568 blinding_point: None,
12569+ send_timestamp: None,
1253612570 };
1253712571 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1253812572 out
@@ -12547,6 +12581,7 @@ mod tests {
1254712581 source: HTLCSource::dummy(),
1254812582 skimmed_fee_msat: None,
1254912583 blinding_point: None,
12584+ send_timestamp: None,
1255012585 };
1255112586 out.payment_hash.0 = Sha256::hash(&<Vec<u8>>::from_hex("0505050505050505050505050505050505050505050505050505050505050505").unwrap()).to_byte_array();
1255212587 out
0 commit comments