@@ -7,6 +7,7 @@ use common::{create_service_and_client_nodes, get_lsps_message, LSPSNodes};
7
7
use lightning:: ln:: functional_test_utils:: {
8
8
create_chanmon_cfgs, create_network, create_node_cfgs, create_node_chanmgrs, Node ,
9
9
} ;
10
+ use lightning:: ln:: msgs:: Init ;
10
11
use lightning:: ln:: peer_handler:: CustomMessageHandler ;
11
12
use lightning:: util:: hash_tables:: { HashMap , HashSet } ;
12
13
use lightning_liquidity:: events:: LiquidityEvent ;
@@ -17,7 +18,9 @@ use lightning_liquidity::lsps5::msgs::{
17
18
LSPS5AppName , LSPS5ClientError , LSPS5ProtocolError , LSPS5WebhookUrl , WebhookNotification ,
18
19
WebhookNotificationMethod ,
19
20
} ;
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
+ } ;
21
24
use lightning_liquidity:: lsps5:: service:: {
22
25
MIN_WEBHOOK_RETENTION_DAYS , PRUNE_STALE_WEBHOOKS_INTERVAL_DAYS ,
23
26
} ;
@@ -27,18 +30,10 @@ use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
27
30
use std:: sync:: { Arc , RwLock } ;
28
31
use std:: time:: Duration ;
29
32
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
-
35
33
pub ( crate ) fn lsps5_test_setup < ' a , ' b , ' c > (
36
34
nodes : Vec < Node < ' a , ' b , ' c > > , time_provider : Arc < dyn TimeProvider + Send + Sync > ,
37
35
) -> ( 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 ( ) ;
42
37
let service_config = LiquidityServiceConfig {
43
38
#[ cfg( lsps1_service) ]
44
39
lsps1_service_config : None ,
@@ -1053,3 +1048,112 @@ fn test_notify_without_webhooks_does_nothing() {
1053
1048
let _ = service_handler. notify_onion_message_incoming ( client_node_id) ;
1054
1049
assert ! ( service_node. liquidity_manager. next_event( ) . is_none( ) ) ;
1055
1050
}
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