@@ -216,6 +216,86 @@ func unfinishedSwapNotification(
216216 }
217217}
218218
219+ func staticLoopInRiskAcceptedNotification (
220+ swapHash lntypes.Hash ) * swapserverrpc.SubscribeNotificationsResponse {
221+
222+ return & swapserverrpc.SubscribeNotificationsResponse {
223+ Notification : & swapserverrpc.
224+ SubscribeNotificationsResponse_StaticLoopInRiskAccepted {
225+ StaticLoopInRiskAccepted : & swapserverrpc.
226+ ServerStaticLoopInRiskAcceptedNotification {
227+ SwapHash : swapHash [:],
228+ },
229+ },
230+ }
231+ }
232+
233+ func staticLoopInRiskRejectedNotification (
234+ swapHash lntypes.Hash ) * swapserverrpc.SubscribeNotificationsResponse {
235+
236+ return & swapserverrpc.SubscribeNotificationsResponse {
237+ Notification : & swapserverrpc.
238+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
239+ StaticLoopInRiskRejected : & swapserverrpc.
240+ ServerStaticLoopInRiskRejectedNotification {
241+ SwapHash : swapHash [:],
242+ },
243+ },
244+ }
245+ }
246+
247+ type staticLoopInRiskNotification interface {
248+ GetSwapHash () []byte
249+ }
250+
251+ func assertStaticLoopInRiskNotificationSwapScoped [
252+ T staticLoopInRiskNotification ](t * testing.T ,
253+ subscribe func (* Manager , context.Context , lntypes.Hash ) <- chan T ,
254+ notification func (lntypes.Hash ) * swapserverrpc.
255+ SubscribeNotificationsResponse , label string ,
256+ swapHashA , swapHashB lntypes.Hash ) {
257+
258+ t .Helper ()
259+
260+ mgr := NewManager (& Config {})
261+
262+ subCtx , subCancel := context .WithCancel (t .Context ())
263+ defer subCancel ()
264+
265+ subChanA := subscribe (mgr , subCtx , swapHashA )
266+ subChanB := subscribe (mgr , subCtx , swapHashB )
267+
268+ mgr .handleNotification (notification (swapHashA ))
269+
270+ select {
271+ case received := <- subChanA :
272+ require .Equal (t , swapHashA [:], received .GetSwapHash ())
273+
274+ case <- time .After (time .Second ):
275+ t .Fatalf ("did not receive first swap risk %s notification" ,
276+ label )
277+ }
278+
279+ select {
280+ case received := <- subChanB :
281+ t .Fatalf ("second swap received wrong notification: %x" ,
282+ received .GetSwapHash ())
283+
284+ default :
285+ }
286+
287+ mgr .handleNotification (notification (swapHashB ))
288+
289+ select {
290+ case received := <- subChanB :
291+ require .Equal (t , swapHashB [:], received .GetSwapHash ())
292+
293+ case <- time .After (time .Second ):
294+ t .Fatalf ("did not receive second swap risk %s notification" ,
295+ label )
296+ }
297+ }
298+
219299// TestManager_SlowSubscriberDoesNotBlock tests that a subscriber with a full
220300// notification channel does not block delivery to other subscribers.
221301func TestManager_SlowSubscriberDoesNotBlock (t * testing.T ) {
@@ -397,6 +477,22 @@ func TestManager_StaticLoopInRiskAcceptedNotification(t *testing.T) {
397477 }
398478}
399479
480+ // TestManager_StaticLoopInRiskAcceptedNotificationSwapScoped verifies that a
481+ // notification for one swap does not occupy another swap's subscriber channel.
482+ func TestManager_StaticLoopInRiskAcceptedNotificationSwapScoped (t * testing.T ) {
483+ t .Parallel ()
484+
485+ assertStaticLoopInRiskNotificationSwapScoped (
486+ t , func (m * Manager , ctx context.Context ,
487+ swapHash lntypes.Hash ) <- chan * swapserverrpc.
488+ ServerStaticLoopInRiskAcceptedNotification {
489+
490+ return m .SubscribeStaticLoopInRiskAccepted (ctx , swapHash )
491+ }, staticLoopInRiskAcceptedNotification , "accepted" ,
492+ lntypes.Hash {0x04 , 0x05 }, lntypes.Hash {0x06 , 0x07 },
493+ )
494+ }
495+
400496// TestManager_StaticLoopInRiskAcceptedNotificationReplay tests that the Manager
401497// replays a risk accepted notification that arrives before the swap-specific
402498// subscriber is registered.
@@ -432,6 +528,92 @@ func TestManager_StaticLoopInRiskAcceptedNotificationReplay(t *testing.T) {
432528 }
433529}
434530
531+ // TestManager_StaticLoopInRiskRejectedNotification tests that the Manager
532+ // forwards static loop in risk rejected notifications to subscribers.
533+ func TestManager_StaticLoopInRiskRejectedNotification (t * testing.T ) {
534+ t .Parallel ()
535+
536+ mgr := NewManager (& Config {})
537+
538+ subCtx , subCancel := context .WithCancel (t .Context ())
539+ defer subCancel ()
540+
541+ swapHash := lntypes.Hash {0x08 , 0x09 }
542+
543+ subChan := mgr .SubscribeStaticLoopInRiskRejected (subCtx , swapHash )
544+
545+ mgr .handleNotification (
546+ & swapserverrpc.SubscribeNotificationsResponse {
547+ Notification : & swapserverrpc.
548+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
549+ StaticLoopInRiskRejected : & swapserverrpc.
550+ ServerStaticLoopInRiskRejectedNotification {
551+ SwapHash : swapHash [:],
552+ },
553+ },
554+ },
555+ )
556+
557+ select {
558+ case received := <- subChan :
559+ require .Equal (t , swapHash [:], received .SwapHash )
560+
561+ case <- time .After (time .Second ):
562+ t .Fatal ("did not receive risk rejected notification" )
563+ }
564+ }
565+
566+ // TestManager_StaticLoopInRiskRejectedNotificationSwapScoped verifies that a
567+ // notification for one swap does not occupy another swap's subscriber channel.
568+ func TestManager_StaticLoopInRiskRejectedNotificationSwapScoped (t * testing.T ) {
569+ t .Parallel ()
570+
571+ assertStaticLoopInRiskNotificationSwapScoped (
572+ t , func (m * Manager , ctx context.Context ,
573+ swapHash lntypes.Hash ) <- chan * swapserverrpc.
574+ ServerStaticLoopInRiskRejectedNotification {
575+
576+ return m .SubscribeStaticLoopInRiskRejected (ctx , swapHash )
577+ }, staticLoopInRiskRejectedNotification , "rejected" ,
578+ lntypes.Hash {0x08 , 0x09 }, lntypes.Hash {0x0a , 0x0b },
579+ )
580+ }
581+
582+ // TestManager_StaticLoopInRiskRejectedNotificationReplay tests that the Manager
583+ // replays a risk rejected notification that arrives before the swap-specific
584+ // subscriber is registered.
585+ func TestManager_StaticLoopInRiskRejectedNotificationReplay (t * testing.T ) {
586+ t .Parallel ()
587+
588+ mgr := NewManager (& Config {})
589+
590+ swapHash := lntypes.Hash {0x0a , 0x0b }
591+ mgr .handleNotification (
592+ & swapserverrpc.SubscribeNotificationsResponse {
593+ Notification : & swapserverrpc.
594+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
595+ StaticLoopInRiskRejected : & swapserverrpc.
596+ ServerStaticLoopInRiskRejectedNotification {
597+ SwapHash : swapHash [:],
598+ },
599+ },
600+ },
601+ )
602+
603+ subCtx , subCancel := context .WithCancel (t .Context ())
604+ defer subCancel ()
605+
606+ subChan := mgr .SubscribeStaticLoopInRiskRejected (subCtx , swapHash )
607+
608+ select {
609+ case received := <- subChan :
610+ require .Equal (t , swapHash [:], received .SwapHash )
611+
612+ case <- time .After (time .Second ):
613+ t .Fatal ("did not replay risk rejected notification" )
614+ }
615+ }
616+
435617// TestManager_Backoff verifies that repeated failures in
436618// subscribeNotifications cause the Manager to space out subscription attempts
437619// via a predictable incremental backoff.
0 commit comments