Skip to content

Commit e66d6ea

Browse files
Fix CI problems
1 parent 26f3423 commit e66d6ea

File tree

4 files changed

+118
-105
lines changed

4 files changed

+118
-105
lines changed

lightning-liquidity/src/lsps5/client.rs

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use core::ops::Deref;
2828
use crate::prelude::{new_hash_map, HashMap, String};
2929

3030
use super::msgs::{Lsps5AppName, Lsps5WebhookUrl};
31-
use super::service::{DefaultTimeProvider, TimeProvider};
31+
use super::service::{from_rfc3339, DefaultTimeProvider, TimeProvider};
3232
use super::url_utils::Url;
3333
use core::time::Duration;
3434
use lightning::sign::EntropySource;
@@ -88,14 +88,15 @@ impl PeerState {
8888
let now = time_provider.now();
8989

9090
// Only run cleanup once per minute to avoid excessive processing
91-
if now.abs_diff(self.last_cleanup) < Duration::from_secs(60) {
91+
if now.checked_sub(self.last_cleanup).unwrap() < Duration::from_secs(60) {
9292
return;
9393
}
9494

9595
self.last_cleanup = now.clone();
9696

9797
// Calculate the cutoff time for expired requests
98-
let cutoff = now.abs_diff(Duration::from_secs(max_age_secs.try_into().unwrap()));
98+
let cutoff =
99+
now.checked_sub(Duration::from_secs(max_age_secs.try_into().unwrap())).unwrap();
99100

100101
// Remove expired set_webhook requests
101102
self.pending_set_webhook_requests.retain(|_, (_, _, timestamp)| *timestamp > cutoff);
@@ -517,14 +518,19 @@ where
517518
/// * On error: LightningError with error description
518519
pub fn verify_notification_signature(
519520
counterparty_node_id: PublicKey, timestamp: &str, signature: &str,
520-
notification: &WebhookNotification, time_provider: Arc<dyn TimeProvider>,
521+
notification: &WebhookNotification, time_provider: &Arc<dyn TimeProvider>,
521522
) -> Result<bool, LightningError> {
522523
// Check timestamp format
523-
match time_provider.from_rfc3339(timestamp) {
524+
match from_rfc3339(timestamp) {
524525
Ok(timestamp_dt) => {
525526
// Check timestamp is within 10 minutes of current time
526527
let now = time_provider.now();
527-
let diff = now.abs_diff(timestamp_dt);
528+
let diff;
529+
if now > timestamp_dt {
530+
diff = now.checked_sub(timestamp_dt).unwrap();
531+
} else {
532+
diff = timestamp_dt.checked_sub(now).unwrap();
533+
}
528534
if diff > Duration::from_secs(600) {
529535
// 10 minutes
530536
return Err(LightningError {
@@ -587,7 +593,7 @@ where
587593
/// * On error: LightningError with error description
588594
pub fn parse_webhook_notification(
589595
counterparty_node_id: PublicKey, timestamp: &str, signature: &str, notification_json: &str,
590-
time_provider: Arc<dyn TimeProvider>,
596+
time_provider: &Arc<dyn TimeProvider>,
591597
) -> Result<WebhookNotification, LightningError> {
592598
// Parse the notification JSON
593599
let notification: WebhookNotification = match serde_json::from_str(notification_json) {
@@ -605,7 +611,7 @@ where
605611
timestamp,
606612
signature,
607613
&notification,
608-
time_provider,
614+
&time_provider,
609615
) {
610616
Ok(_) => Ok(notification),
611617
Err(e) => Err(e),
@@ -770,7 +776,7 @@ mod tests {
770776
fn test_cleanup_expired_responses() {
771777
// use DefaultTimeProvider
772778
let (client, _, _, _, _) = setup_test_client();
773-
let time_provider = client.time_provider;
779+
let time_provider = &client.time_provider;
774780
const OLD_APP_NAME: &str = "test-app-old";
775781
const NEW_APP_NAME: &str = "test-app-new";
776782
const WEBHOOK_URL: &str = "https://example.com/hook";
@@ -781,7 +787,7 @@ mod tests {
781787
let now = time_provider.now();
782788
// Create a mock PeerState with a very old cleanup time
783789
let mut peer_state = PeerState::new();
784-
peer_state.last_cleanup = now.abs_diff(Duration::from_secs(120));
790+
peer_state.last_cleanup = now.checked_sub(Duration::from_secs(120)).unwrap();
785791

786792
// Add some test requests with different timestamps
787793
let old_request_id = LSPSRequestId("test:request:old".to_string());
@@ -793,14 +799,18 @@ mod tests {
793799
(
794800
lsps5_old_app_name,
795801
lsps5_webhook_url.clone(),
796-
now.abs_diff(Duration::from_secs(7200)),
802+
now.checked_sub(Duration::from_secs(7200)).unwrap(),
797803
), // 2 hours old
798804
);
799805

800806
// Add a recent request (should be kept)
801807
peer_state.pending_set_webhook_requests.insert(
802808
new_request_id.clone(),
803-
(lsps5_new_app_name, lsps5_webhook_url, now.abs_diff(Duration::from_secs(600))), // 10 minutes old
809+
(
810+
lsps5_new_app_name,
811+
lsps5_webhook_url,
812+
now.checked_sub(Duration::from_secs(600)).unwrap(),
813+
), // 10 minutes old
804814
);
805815

806816
// Run cleanup with 30 minutes (1800 seconds) max age
@@ -811,7 +821,7 @@ mod tests {
811821
assert!(peer_state.pending_set_webhook_requests.contains_key(&new_request_id));
812822

813823
// Verify last_cleanup was updated within the last 10 seconds
814-
let cleanup_age = time_provider.clone().now().abs_diff(peer_state.last_cleanup);
824+
let cleanup_age = time_provider.now().checked_sub(peer_state.last_cleanup).unwrap();
815825
assert!(cleanup_age < Duration::from_secs(10));
816826
}
817827

lightning-liquidity/src/lsps5/service.rs

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -148,14 +148,11 @@ pub trait HttpClient: Send + Sync + 'static {
148148
pub trait TimeProvider: Send + Sync + 'static {
149149
/// Get the current time as a duration since the Unix epoch
150150
fn now(&self) -> Duration;
151-
/// Convert an RFC3339 formatted string to a duration since the Unix epoch
152-
fn from_rfc3339(&self, _rfc3339: &str) -> Result<Duration, String>;
153-
/// Convert a duration since the Unix epoch to an RFC3339 formatted string
154-
fn to_rfc3339(&self, duration: Duration) -> String;
155151
}
156152

157153
/// Default time provider using the system clock
158154
#[derive(Clone, Debug)]
155+
#[cfg(feature = "std")]
159156
pub struct DefaultTimeProvider;
160157

161158
#[cfg(feature = "std")]
@@ -166,19 +163,21 @@ impl TimeProvider for DefaultTimeProvider {
166163
SystemTime::now().duration_since(UNIX_EPOCH).expect("system time before Unix epoch");
167164
Duration::from_secs(now.as_secs())
168165
}
166+
}
169167

170-
fn from_rfc3339(&self, s: &str) -> Result<Duration, String> {
171-
use chrono::DateTime;
172-
let dt = DateTime::parse_from_rfc3339(s).map_err(|e| e.to_string())?;
173-
let now = dt.timestamp();
174-
Ok(Duration::from_secs(now as u64))
175-
}
168+
/// Convert an RFC3339 timestamp string to a Duration
169+
pub fn from_rfc3339(s: &str) -> Result<Duration, String> {
170+
use chrono::DateTime;
171+
let dt = DateTime::parse_from_rfc3339(s).map_err(|e| e.to_string())?;
172+
let now = dt.timestamp();
173+
Ok(Duration::from_secs(now as u64))
174+
}
176175

177-
fn to_rfc3339(&self, duration: Duration) -> String {
178-
use chrono::DateTime;
179-
(DateTime::from_timestamp(duration.as_secs() as i64, duration.subsec_nanos()).unwrap())
180-
.to_rfc3339()
181-
}
176+
/// Convert a Duration to an RFC3339 timestamp string
177+
pub fn to_rfc3339(duration: Duration) -> String {
178+
use chrono::DateTime;
179+
(DateTime::from_timestamp(duration.as_secs() as i64, duration.subsec_nanos()).unwrap())
180+
.to_rfc3339()
182181
}
183182

184183
/// Configuration for LSPS5 service
@@ -618,7 +617,7 @@ impl LSPS5ServiceHandler {
618617
for (app_name, webhook) in client_webhooks.iter_mut() {
619618
// Check if this notification type was recently sent (cooldown period)
620619
if let Some(last_sent) = webhook.last_notification_sent.get(&method) {
621-
let duration = now.clone().abs_diff(*last_sent);
620+
let duration = now.checked_sub(*last_sent).unwrap();
622621
// Skip if notification was sent less than cooldown_hours ago
623622
// According to spec: "This timeout must be measurable in hours or days."
624623
if duration.as_secs() < self.config.notification_cooldown_hours * 3600 {
@@ -650,7 +649,7 @@ impl LSPS5ServiceHandler {
650649
notification: WebhookNotification, method: WebhookNotificationMethod,
651650
) -> Result<(), LightningError> {
652651
// Create timestamp in ISO8601 format using chrono
653-
let timestamp = self.time_provider.to_rfc3339(self.time_provider.now());
652+
let timestamp = to_rfc3339(self.time_provider.now());
654653

655654
// Serialize the notification
656655
let notification_json =
@@ -770,7 +769,7 @@ impl LSPS5ServiceHandler {
770769
if client_channel_counts.get(client_id).copied().unwrap_or(0) == 0 {
771770
// Filter out webhooks that haven't been used in at least MIN_WEBHOOK_RETENTION_DAYS
772771
client_webhooks.retain(|_, webhook| {
773-
let duration = now.abs_diff(webhook.last_used);
772+
let duration = now.checked_sub(webhook.last_used).unwrap();
774773
if duration.as_secs() < (MIN_WEBHOOK_RETENTION_DAYS * 24 * 60 * 60).into() {
775774
// Keep webhook - not stale yet
776775
true

lightning-liquidity/tests/lsps5_integration_tests.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use lightning_liquidity::events::LiquidityEvent;
99
use lightning_liquidity::lsps5::client::{LSPS5ClientConfig, LSPS5ClientHandler};
1010
use lightning_liquidity::lsps5::event::{LSPS5ClientEvent, LSPS5ServiceEvent};
1111
use lightning_liquidity::lsps5::msgs::{Lsps5AppName, Lsps5WebhookUrl, WebhookNotificationMethod};
12-
use lightning_liquidity::lsps5::service::{DefaultTimeProvider, HttpClient, LSPS5ServiceConfig};
12+
use lightning_liquidity::lsps5::service::{
13+
DefaultTimeProvider, HttpClient, LSPS5ServiceConfig, TimeProvider,
14+
};
1315
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
1416

1517
use bitcoin::secp256k1::SecretKey;
@@ -524,7 +526,7 @@ fn webhook_error_handling_test() {
524526
fn webhook_notification_delivery_test() {
525527
let mock_client = Arc::new(MockHttpClient::new(true));
526528
let mock_client_for_verification = mock_client.clone();
527-
let time_provider = Arc::new(DefaultTimeProvider);
529+
let time_provider: Arc<(dyn TimeProvider + 'static)> = Arc::new(DefaultTimeProvider);
528530

529531
let signing_key = SecretKey::from_slice(&[42; 32]).unwrap();
530532

@@ -627,7 +629,7 @@ fn webhook_notification_delivery_test() {
627629
&timestamp_value,
628630
&signature_value,
629631
&first_call.2,
630-
time_provider.clone(),
632+
&time_provider,
631633
);
632634
assert!(
633635
result.is_ok(),
@@ -667,13 +669,13 @@ fn webhook_notification_delivery_test() {
667669
.find(|(name, _)| name == "x-lsps5-signature")
668670
.map(|(_, value)| value.clone())
669671
.expect("Signature header should be present");
670-
let time_provider_cloned = time_provider.clone();
672+
671673
let result = LSPS5ClientHandler::<Arc<dyn EntropySource>>::parse_webhook_notification(
672674
derived_pubkey,
673675
&timestamp_header,
674676
&signature_header,
675677
&payment_call.2,
676-
time_provider_cloned,
678+
&time_provider,
677679
);
678680
assert!(
679681
result.is_ok(),
@@ -874,14 +876,14 @@ fn multiple_webhooks_notification_test() {
874876
.find(|(name, _)| name == "x-lsps5-signature")
875877
.map(|(_, value)| value.clone())
876878
.expect("Signature header should be present");
877-
let time_provider = Arc::new(DefaultTimeProvider);
879+
let time_provider: Arc<(dyn TimeProvider + 'static)> = Arc::new(DefaultTimeProvider);
878880
// Verify the signature using the derived pubkey
879881
let result = LSPS5ClientHandler::<Arc<dyn EntropySource>>::parse_webhook_notification(
880882
derived_pubkey,
881883
&timestamp_header,
882884
&signature_header,
883885
&call.2,
884-
time_provider,
886+
&time_provider,
885887
);
886888
assert!(result.is_ok(), "Signature verification should succeed for all notifications");
887889
}
@@ -1176,14 +1178,14 @@ fn replay_prevention_test() {
11761178
// Extract the timestamp and signature
11771179
let (timestamp, signature) = extract_timestamp_and_signature(payment_call);
11781180
let body = payment_call.2.clone();
1179-
let time_provider = Arc::new(DefaultTimeProvider);
1181+
let time_provider: Arc<(dyn TimeProvider + 'static)> = Arc::new(DefaultTimeProvider);
11801182
// First verification should succeed
11811183
let result = LSPS5ClientHandler::<Arc<dyn EntropySource>>::parse_webhook_notification(
11821184
derived_pubkey,
11831185
&timestamp,
11841186
&signature,
11851187
&body,
1186-
time_provider.clone(),
1188+
&time_provider,
11871189
);
11881190
assert!(result.is_ok(), "First verification should succeed");
11891191

@@ -1193,7 +1195,7 @@ fn replay_prevention_test() {
11931195
&timestamp,
11941196
&signature,
11951197
&body,
1196-
time_provider,
1198+
&time_provider,
11971199
);
11981200

11991201
assert!(

0 commit comments

Comments
 (0)