@@ -202,6 +202,86 @@ func unfinishedSwapNotification(
202202 }
203203}
204204
205+ func staticLoopInRiskAcceptedNotification (
206+ swapHash lntypes.Hash ) * swapserverrpc.SubscribeNotificationsResponse {
207+
208+ return & swapserverrpc.SubscribeNotificationsResponse {
209+ Notification : & swapserverrpc.
210+ SubscribeNotificationsResponse_StaticLoopInRiskAccepted {
211+ StaticLoopInRiskAccepted : & swapserverrpc.
212+ ServerStaticLoopInRiskAcceptedNotification {
213+ SwapHash : swapHash [:],
214+ },
215+ },
216+ }
217+ }
218+
219+ func staticLoopInRiskRejectedNotification (
220+ swapHash lntypes.Hash ) * swapserverrpc.SubscribeNotificationsResponse {
221+
222+ return & swapserverrpc.SubscribeNotificationsResponse {
223+ Notification : & swapserverrpc.
224+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
225+ StaticLoopInRiskRejected : & swapserverrpc.
226+ ServerStaticLoopInRiskRejectedNotification {
227+ SwapHash : swapHash [:],
228+ },
229+ },
230+ }
231+ }
232+
233+ type staticLoopInRiskNotification interface {
234+ GetSwapHash () []byte
235+ }
236+
237+ func assertStaticLoopInRiskNotificationSwapScoped [
238+ T staticLoopInRiskNotification ](t * testing.T ,
239+ subscribe func (* Manager , context.Context , lntypes.Hash ) <- chan T ,
240+ notification func (lntypes.Hash ) * swapserverrpc.
241+ SubscribeNotificationsResponse , label string ,
242+ swapHashA , swapHashB lntypes.Hash ) {
243+
244+ t .Helper ()
245+
246+ mgr := NewManager (& Config {})
247+
248+ subCtx , subCancel := context .WithCancel (t .Context ())
249+ defer subCancel ()
250+
251+ subChanA := subscribe (mgr , subCtx , swapHashA )
252+ subChanB := subscribe (mgr , subCtx , swapHashB )
253+
254+ mgr .handleNotification (notification (swapHashA ))
255+
256+ select {
257+ case received := <- subChanA :
258+ require .Equal (t , swapHashA [:], received .GetSwapHash ())
259+
260+ case <- time .After (time .Second ):
261+ t .Fatalf ("did not receive first swap risk %s notification" ,
262+ label )
263+ }
264+
265+ select {
266+ case received := <- subChanB :
267+ t .Fatalf ("second swap received wrong notification: %x" ,
268+ received .GetSwapHash ())
269+
270+ default :
271+ }
272+
273+ mgr .handleNotification (notification (swapHashB ))
274+
275+ select {
276+ case received := <- subChanB :
277+ require .Equal (t , swapHashB [:], received .GetSwapHash ())
278+
279+ case <- time .After (time .Second ):
280+ t .Fatalf ("did not receive second swap risk %s notification" ,
281+ label )
282+ }
283+ }
284+
205285// TestManager_SlowSubscriberDoesNotBlock tests that a subscriber with a full
206286// notification channel does not block delivery to other subscribers.
207287func TestManager_SlowSubscriberDoesNotBlock (t * testing.T ) {
@@ -333,6 +413,22 @@ func TestManager_StaticLoopInRiskAcceptedNotification(t *testing.T) {
333413 }
334414}
335415
416+ // TestManager_StaticLoopInRiskAcceptedNotificationSwapScoped verifies that a
417+ // notification for one swap does not occupy another swap's subscriber channel.
418+ func TestManager_StaticLoopInRiskAcceptedNotificationSwapScoped (t * testing.T ) {
419+ t .Parallel ()
420+
421+ assertStaticLoopInRiskNotificationSwapScoped (
422+ t , func (m * Manager , ctx context.Context ,
423+ swapHash lntypes.Hash ) <- chan * swapserverrpc.
424+ ServerStaticLoopInRiskAcceptedNotification {
425+
426+ return m .SubscribeStaticLoopInRiskAccepted (ctx , swapHash )
427+ }, staticLoopInRiskAcceptedNotification , "accepted" ,
428+ lntypes.Hash {0x04 , 0x05 }, lntypes.Hash {0x06 , 0x07 },
429+ )
430+ }
431+
336432// TestManager_StaticLoopInRiskAcceptedNotificationReplay tests that the Manager
337433// replays a risk accepted notification that arrives before the swap-specific
338434// subscriber is registered.
@@ -368,6 +464,92 @@ func TestManager_StaticLoopInRiskAcceptedNotificationReplay(t *testing.T) {
368464 }
369465}
370466
467+ // TestManager_StaticLoopInRiskRejectedNotification tests that the Manager
468+ // forwards static loop in risk rejected notifications to subscribers.
469+ func TestManager_StaticLoopInRiskRejectedNotification (t * testing.T ) {
470+ t .Parallel ()
471+
472+ mgr := NewManager (& Config {})
473+
474+ subCtx , subCancel := context .WithCancel (t .Context ())
475+ defer subCancel ()
476+
477+ swapHash := lntypes.Hash {0x08 , 0x09 }
478+
479+ subChan := mgr .SubscribeStaticLoopInRiskRejected (subCtx , swapHash )
480+
481+ mgr .handleNotification (
482+ & swapserverrpc.SubscribeNotificationsResponse {
483+ Notification : & swapserverrpc.
484+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
485+ StaticLoopInRiskRejected : & swapserverrpc.
486+ ServerStaticLoopInRiskRejectedNotification {
487+ SwapHash : swapHash [:],
488+ },
489+ },
490+ },
491+ )
492+
493+ select {
494+ case received := <- subChan :
495+ require .Equal (t , swapHash [:], received .SwapHash )
496+
497+ case <- time .After (time .Second ):
498+ t .Fatal ("did not receive risk rejected notification" )
499+ }
500+ }
501+
502+ // TestManager_StaticLoopInRiskRejectedNotificationSwapScoped verifies that a
503+ // notification for one swap does not occupy another swap's subscriber channel.
504+ func TestManager_StaticLoopInRiskRejectedNotificationSwapScoped (t * testing.T ) {
505+ t .Parallel ()
506+
507+ assertStaticLoopInRiskNotificationSwapScoped (
508+ t , func (m * Manager , ctx context.Context ,
509+ swapHash lntypes.Hash ) <- chan * swapserverrpc.
510+ ServerStaticLoopInRiskRejectedNotification {
511+
512+ return m .SubscribeStaticLoopInRiskRejected (ctx , swapHash )
513+ }, staticLoopInRiskRejectedNotification , "rejected" ,
514+ lntypes.Hash {0x08 , 0x09 }, lntypes.Hash {0x0a , 0x0b },
515+ )
516+ }
517+
518+ // TestManager_StaticLoopInRiskRejectedNotificationReplay tests that the Manager
519+ // replays a risk rejected notification that arrives before the swap-specific
520+ // subscriber is registered.
521+ func TestManager_StaticLoopInRiskRejectedNotificationReplay (t * testing.T ) {
522+ t .Parallel ()
523+
524+ mgr := NewManager (& Config {})
525+
526+ swapHash := lntypes.Hash {0x0a , 0x0b }
527+ mgr .handleNotification (
528+ & swapserverrpc.SubscribeNotificationsResponse {
529+ Notification : & swapserverrpc.
530+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
531+ StaticLoopInRiskRejected : & swapserverrpc.
532+ ServerStaticLoopInRiskRejectedNotification {
533+ SwapHash : swapHash [:],
534+ },
535+ },
536+ },
537+ )
538+
539+ subCtx , subCancel := context .WithCancel (t .Context ())
540+ defer subCancel ()
541+
542+ subChan := mgr .SubscribeStaticLoopInRiskRejected (subCtx , swapHash )
543+
544+ select {
545+ case received := <- subChan :
546+ require .Equal (t , swapHash [:], received .SwapHash )
547+
548+ case <- time .After (time .Second ):
549+ t .Fatal ("did not replay risk rejected notification" )
550+ }
551+ }
552+
371553// TestManager_Backoff verifies that repeated failures in
372554// subscribeNotifications cause the Manager to space out subscription attempts
373555// via a predictable incremental backoff.
0 commit comments