@@ -202,6 +202,86 @@ func staticLoopInSweepNotification(
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 ) {
@@ -335,6 +415,22 @@ func TestManager_StaticLoopInRiskAcceptedNotification(t *testing.T) {
335415 }
336416}
337417
418+ // TestManager_StaticLoopInRiskAcceptedNotificationSwapScoped verifies that a
419+ // notification for one swap does not occupy another swap's subscriber channel.
420+ func TestManager_StaticLoopInRiskAcceptedNotificationSwapScoped (t * testing.T ) {
421+ t .Parallel ()
422+
423+ assertStaticLoopInRiskNotificationSwapScoped (
424+ t , func (m * Manager , ctx context.Context ,
425+ swapHash lntypes.Hash ) <- chan * swapserverrpc.
426+ ServerStaticLoopInRiskAcceptedNotification {
427+
428+ return m .SubscribeStaticLoopInRiskAccepted (ctx , swapHash )
429+ }, staticLoopInRiskAcceptedNotification , "accepted" ,
430+ lntypes.Hash {0x04 , 0x05 }, lntypes.Hash {0x06 , 0x07 },
431+ )
432+ }
433+
338434// TestManager_StaticLoopInRiskAcceptedNotificationReplay tests that the Manager
339435// replays a risk accepted notification that arrives before the swap-specific
340436// subscriber is registered.
@@ -370,6 +466,92 @@ func TestManager_StaticLoopInRiskAcceptedNotificationReplay(t *testing.T) {
370466 }
371467}
372468
469+ // TestManager_StaticLoopInRiskRejectedNotification tests that the Manager
470+ // forwards static loop in risk rejected notifications to subscribers.
471+ func TestManager_StaticLoopInRiskRejectedNotification (t * testing.T ) {
472+ t .Parallel ()
473+
474+ mgr := NewManager (& Config {})
475+
476+ subCtx , subCancel := context .WithCancel (t .Context ())
477+ defer subCancel ()
478+
479+ swapHash := lntypes.Hash {0x08 , 0x09 }
480+
481+ subChan := mgr .SubscribeStaticLoopInRiskRejected (subCtx , swapHash )
482+
483+ mgr .handleNotification (
484+ & swapserverrpc.SubscribeNotificationsResponse {
485+ Notification : & swapserverrpc.
486+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
487+ StaticLoopInRiskRejected : & swapserverrpc.
488+ ServerStaticLoopInRiskRejectedNotification {
489+ SwapHash : swapHash [:],
490+ },
491+ },
492+ },
493+ )
494+
495+ select {
496+ case received := <- subChan :
497+ require .Equal (t , swapHash [:], received .SwapHash )
498+
499+ case <- time .After (time .Second ):
500+ t .Fatal ("did not receive risk rejected notification" )
501+ }
502+ }
503+
504+ // TestManager_StaticLoopInRiskRejectedNotificationSwapScoped verifies that a
505+ // notification for one swap does not occupy another swap's subscriber channel.
506+ func TestManager_StaticLoopInRiskRejectedNotificationSwapScoped (t * testing.T ) {
507+ t .Parallel ()
508+
509+ assertStaticLoopInRiskNotificationSwapScoped (
510+ t , func (m * Manager , ctx context.Context ,
511+ swapHash lntypes.Hash ) <- chan * swapserverrpc.
512+ ServerStaticLoopInRiskRejectedNotification {
513+
514+ return m .SubscribeStaticLoopInRiskRejected (ctx , swapHash )
515+ }, staticLoopInRiskRejectedNotification , "rejected" ,
516+ lntypes.Hash {0x08 , 0x09 }, lntypes.Hash {0x0a , 0x0b },
517+ )
518+ }
519+
520+ // TestManager_StaticLoopInRiskRejectedNotificationReplay tests that the Manager
521+ // replays a risk rejected notification that arrives before the swap-specific
522+ // subscriber is registered.
523+ func TestManager_StaticLoopInRiskRejectedNotificationReplay (t * testing.T ) {
524+ t .Parallel ()
525+
526+ mgr := NewManager (& Config {})
527+
528+ swapHash := lntypes.Hash {0x0a , 0x0b }
529+ mgr .handleNotification (
530+ & swapserverrpc.SubscribeNotificationsResponse {
531+ Notification : & swapserverrpc.
532+ SubscribeNotificationsResponse_StaticLoopInRiskRejected {
533+ StaticLoopInRiskRejected : & swapserverrpc.
534+ ServerStaticLoopInRiskRejectedNotification {
535+ SwapHash : swapHash [:],
536+ },
537+ },
538+ },
539+ )
540+
541+ subCtx , subCancel := context .WithCancel (t .Context ())
542+ defer subCancel ()
543+
544+ subChan := mgr .SubscribeStaticLoopInRiskRejected (subCtx , swapHash )
545+
546+ select {
547+ case received := <- subChan :
548+ require .Equal (t , swapHash [:], received .SwapHash )
549+
550+ case <- time .After (time .Second ):
551+ t .Fatal ("did not replay risk rejected notification" )
552+ }
553+ }
554+
373555// TestManager_Backoff verifies that repeated failures in
374556// subscribeNotifications cause the Manager to space out subscription attempts
375557// via a predictable incremental backoff.
0 commit comments