@@ -7,6 +7,7 @@ use common::{create_service_and_client_nodes, get_lsps_message, LSPSNodes};
77use lightning:: ln:: functional_test_utils:: {
88 create_chanmon_cfgs, create_network, create_node_cfgs, create_node_chanmgrs, Node ,
99} ;
10+ use lightning:: ln:: msgs:: Init ;
1011use lightning:: ln:: peer_handler:: CustomMessageHandler ;
1112use lightning:: util:: hash_tables:: { HashMap , HashSet } ;
1213use lightning_liquidity:: events:: LiquidityEvent ;
@@ -17,7 +18,9 @@ use lightning_liquidity::lsps5::msgs::{
1718 LSPS5AppName , LSPS5ClientError , LSPS5ProtocolError , LSPS5WebhookUrl , WebhookNotification ,
1819 WebhookNotificationMethod ,
1920} ;
20- use lightning_liquidity:: lsps5:: service:: LSPS5ServiceConfig ;
21+ use lightning_liquidity:: lsps5:: service:: {
22+ LSPS5ServiceConfig , DEFAULT_MAX_WEBHOOKS_PER_CLIENT , DEFAULT_NOTIFICATION_COOLDOWN_HOURS ,
23+ } ;
2124use lightning_liquidity:: lsps5:: service:: {
2225 MIN_WEBHOOK_RETENTION_DAYS , PRUNE_STALE_WEBHOOKS_INTERVAL_DAYS ,
2326} ;
@@ -27,18 +30,10 @@ use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
2730use std:: sync:: { Arc , RwLock } ;
2831use std:: time:: Duration ;
2932
30- /// Default maximum number of webhooks allowed per client.
31- pub ( crate ) const DEFAULT_MAX_WEBHOOKS_PER_CLIENT : u32 = 10 ;
32- /// Default notification cooldown time in hours.
33- pub ( crate ) const DEFAULT_NOTIFICATION_COOLDOWN_HOURS : Duration = Duration :: from_secs ( 24 * 60 * 60 ) ;
34-
3533pub ( crate ) fn lsps5_test_setup < ' a , ' b , ' c > (
3634 nodes : Vec < Node < ' a , ' b , ' c > > , time_provider : Arc < dyn TimeProvider + Send + Sync > ,
3735) -> ( LSPSNodes < ' a , ' b , ' c > , LSPS5Validator ) {
38- let lsps5_service_config = LSPS5ServiceConfig {
39- max_webhooks_per_client : DEFAULT_MAX_WEBHOOKS_PER_CLIENT ,
40- notification_cooldown_hours : DEFAULT_NOTIFICATION_COOLDOWN_HOURS ,
41- } ;
36+ let lsps5_service_config = LSPS5ServiceConfig :: default ( ) ;
4237 let service_config = LiquidityServiceConfig {
4338 #[ cfg( lsps1_service) ]
4439 lsps1_service_config : None ,
@@ -1053,3 +1048,112 @@ fn test_notify_without_webhooks_does_nothing() {
10531048 let _ = service_handler. notify_onion_message_incoming ( client_node_id) ;
10541049 assert ! ( service_node. liquidity_manager. next_event( ) . is_none( ) ) ;
10551050}
1051+
1052+ #[ test]
1053+ fn test_send_notifications_and_peer_connected_resets_cooldown ( ) {
1054+ let mock_time_provider = Arc :: new ( MockTimeProvider :: new ( 1000 ) ) ;
1055+ let time_provider = Arc :: < MockTimeProvider > :: clone ( & mock_time_provider) ;
1056+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1057+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1058+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1059+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1060+ let ( lsps_nodes, _) = lsps5_test_setup ( nodes, time_provider) ;
1061+ let LSPSNodes { service_node, client_node } = lsps_nodes;
1062+ let service_node_id = service_node. inner . node . get_our_node_id ( ) ;
1063+ let client_node_id = client_node. inner . node . get_our_node_id ( ) ;
1064+
1065+ let client_handler = client_node. liquidity_manager . lsps5_client_handler ( ) . unwrap ( ) ;
1066+ let service_handler = service_node. liquidity_manager . lsps5_service_handler ( ) . unwrap ( ) ;
1067+
1068+ let app_name = "CooldownTestApp" ;
1069+ let webhook_url = "https://www.example.org/cooldown" ;
1070+ let _ = client_handler
1071+ . set_webhook ( service_node_id, app_name. to_string ( ) , webhook_url. to_string ( ) )
1072+ . expect ( "Register webhook request should succeed" ) ;
1073+ let set_req = get_lsps_message ! ( client_node, service_node_id) ;
1074+ service_node. liquidity_manager . handle_custom_message ( set_req, client_node_id) . unwrap ( ) ;
1075+
1076+ let _ = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
1077+
1078+ let resp = get_lsps_message ! ( service_node, client_node_id) ;
1079+ client_node. liquidity_manager . handle_custom_message ( resp, service_node_id) . unwrap ( ) ;
1080+ let _ = client_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
1081+
1082+ // 1. First notification should be sent
1083+ let _ = service_handler. notify_payment_incoming ( client_node_id) ;
1084+ let event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
1085+ match event {
1086+ LiquidityEvent :: LSPS5Service ( LSPS5ServiceEvent :: SendWebhookNotification {
1087+ notification,
1088+ ..
1089+ } ) => {
1090+ assert_eq ! ( notification. method, WebhookNotificationMethod :: LSPS5PaymentIncoming ) ;
1091+ } ,
1092+ _ => panic ! ( "Expected SendWebhookNotification event" ) ,
1093+ }
1094+
1095+ // 2. Second notification before cooldown should NOT be sent
1096+ let _ = service_handler. notify_payment_incoming ( client_node_id) ;
1097+ assert ! (
1098+ service_node. liquidity_manager. next_event( ) . is_none( ) ,
1099+ "Should not emit event due to cooldown"
1100+ ) ;
1101+
1102+ // 3. Notification of a different method CAN be sent
1103+ let timeout_block = 424242 ;
1104+ let _ = service_handler. notify_expiry_soon ( client_node_id, timeout_block) ;
1105+ let event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
1106+ match event {
1107+ LiquidityEvent :: LSPS5Service ( LSPS5ServiceEvent :: SendWebhookNotification {
1108+ notification,
1109+ ..
1110+ } ) => {
1111+ assert ! ( matches!(
1112+ notification. method,
1113+ WebhookNotificationMethod :: LSPS5ExpirySoon { timeout } if timeout == timeout_block
1114+ ) ) ;
1115+ } ,
1116+ _ => panic ! ( "Expected SendWebhookNotification event for expiry_soon" ) ,
1117+ }
1118+
1119+ // 4. Advance time past cooldown and ensure payment_incoming can be sent again
1120+ mock_time_provider. advance_time ( DEFAULT_NOTIFICATION_COOLDOWN_HOURS . as_secs ( ) + 1 ) ;
1121+
1122+ let _ = service_handler. notify_payment_incoming ( client_node_id) ;
1123+ let event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
1124+ match event {
1125+ LiquidityEvent :: LSPS5Service ( LSPS5ServiceEvent :: SendWebhookNotification {
1126+ notification,
1127+ ..
1128+ } ) => {
1129+ assert_eq ! ( notification. method, WebhookNotificationMethod :: LSPS5PaymentIncoming ) ;
1130+ } ,
1131+ _ => panic ! ( "Expected SendWebhookNotification event after cooldown" ) ,
1132+ }
1133+
1134+ // 5. Can't send payment_incoming notification again immediately after cooldown
1135+ let _ = service_handler. notify_payment_incoming ( client_node_id) ;
1136+ assert ! (
1137+ service_node. liquidity_manager. next_event( ) . is_none( ) ,
1138+ "Should not emit event due to cooldown"
1139+ ) ;
1140+
1141+ // 6. After peer_connected, notification should be sent again immediately
1142+ let init_msg = Init {
1143+ features : lightning_types:: features:: InitFeatures :: empty ( ) ,
1144+ remote_network_address : None ,
1145+ networks : None ,
1146+ } ;
1147+ service_node. liquidity_manager . peer_connected ( client_node_id, & init_msg, false ) . unwrap ( ) ;
1148+ let _ = service_handler. notify_payment_incoming ( client_node_id) ;
1149+ let event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
1150+ match event {
1151+ LiquidityEvent :: LSPS5Service ( LSPS5ServiceEvent :: SendWebhookNotification {
1152+ notification,
1153+ ..
1154+ } ) => {
1155+ assert_eq ! ( notification. method, WebhookNotificationMethod :: LSPS5PaymentIncoming ) ;
1156+ } ,
1157+ _ => panic ! ( "Expected SendWebhookNotification event after peer_connected" ) ,
1158+ }
1159+ }
0 commit comments