22
33mod common;
44
5- use common:: { create_service_and_client_nodes, get_lsps_message, Node } ;
5+ use common:: create_service_and_client_nodes;
6+ use common:: { get_lsps_message, Node } ;
67
78use lightning_liquidity:: events:: LiquidityEvent ;
89use lightning_liquidity:: lsps0:: ser:: LSPSDateTime ;
910use lightning_liquidity:: lsps2:: client:: LSPS2ClientConfig ;
10- use lightning_liquidity:: lsps2:: event:: { LSPS2ClientEvent , LSPS2ServiceEvent } ;
11+ use lightning_liquidity:: lsps2:: event:: LSPS2ClientEvent ;
12+ use lightning_liquidity:: lsps2:: event:: LSPS2ServiceEvent ;
1113use lightning_liquidity:: lsps2:: msgs:: LSPS2RawOpeningFeeParams ;
1214use lightning_liquidity:: lsps2:: service:: LSPS2ServiceConfig ;
1315use lightning_liquidity:: lsps2:: utils:: is_valid_opening_fee_params;
@@ -31,6 +33,9 @@ use bitcoin::Network;
3133use std:: str:: FromStr ;
3234use std:: time:: Duration ;
3335
36+ const MAX_PENDING_REQUESTS_PER_PEER : usize = 10 ;
37+ const MAX_TOTAL_PENDING_REQUESTS : usize = 1000 ;
38+
3439fn setup_test_lsps2 (
3540) -> ( bitcoin:: secp256k1:: PublicKey , bitcoin:: secp256k1:: PublicKey , Node , Node , [ u8 ; 32 ] ) {
3641 let promise_secret = [ 42 ; 32 ] ;
@@ -258,12 +263,9 @@ fn channel_open_failed() {
258263 let ( service_node_id, client_node_id, service_node, client_node, _) = setup_test_lsps2 ( ) ;
259264
260265 let service_handler = service_node. liquidity_manager . lsps2_service_handler ( ) . unwrap ( ) ;
266+ let client_handler = client_node. liquidity_manager . lsps2_client_handler ( ) . unwrap ( ) ;
261267
262- let get_info_request_id = client_node
263- . liquidity_manager
264- . lsps2_client_handler ( )
265- . unwrap ( )
266- . request_opening_params ( service_node_id, None ) ;
268+ let get_info_request_id = client_handler. request_opening_params ( service_node_id, None ) ;
267269 let get_info_request = get_lsps_message ! ( client_node, service_node_id) ;
268270 service_node. liquidity_manager . handle_custom_message ( get_info_request, client_node_id) . unwrap ( ) ;
269271
@@ -301,10 +303,7 @@ fn channel_open_failed() {
301303 } ;
302304
303305 let payment_size_msat = Some ( 1_000_000 ) ;
304- let buy_request_id = client_node
305- . liquidity_manager
306- . lsps2_client_handler ( )
307- . unwrap ( )
306+ let buy_request_id = client_handler
308307 . select_opening_params ( service_node_id, payment_size_msat, opening_fee_params. clone ( ) )
309308 . unwrap ( ) ;
310309 let buy_request = get_lsps_message ! ( client_node, service_node_id) ;
@@ -410,13 +409,10 @@ fn channel_open_abandoned() {
410409 let ( service_node_id, client_node_id, service_node, client_node, _) = setup_test_lsps2 ( ) ;
411410
412411 let service_handler = service_node. liquidity_manager . lsps2_service_handler ( ) . unwrap ( ) ;
412+ let client_handler = client_node. liquidity_manager . lsps2_client_handler ( ) . unwrap ( ) ;
413413
414414 // Set up a JIT channel
415- let get_info_request_id = client_node
416- . liquidity_manager
417- . lsps2_client_handler ( )
418- . unwrap ( )
419- . request_opening_params ( service_node_id, None ) ;
415+ let get_info_request_id = client_handler. request_opening_params ( service_node_id, None ) ;
420416 let get_info_request = get_lsps_message ! ( client_node, service_node_id) ;
421417 service_node. liquidity_manager . handle_custom_message ( get_info_request, client_node_id) . unwrap ( ) ;
422418 let _get_info_event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
@@ -453,10 +449,7 @@ fn channel_open_abandoned() {
453449 } ;
454450
455451 let payment_size_msat = Some ( 1_000_000 ) ;
456- let buy_request_id = client_node
457- . liquidity_manager
458- . lsps2_client_handler ( )
459- . unwrap ( )
452+ let buy_request_id = client_handler
460453 . select_opening_params ( service_node_id, payment_size_msat, opening_fee_params. clone ( ) )
461454 . unwrap ( ) ;
462455 let buy_request = get_lsps_message ! ( client_node, service_node_id) ;
@@ -504,3 +497,248 @@ fn channel_open_abandoned_nonexistent_channel() {
504497 other => panic ! ( "Unexpected error type: {:?}" , other) ,
505498 }
506499}
500+
501+ #[ test]
502+ fn max_pending_requests_per_peer_rejected ( ) {
503+ let ( service_node_id, client_node_id, service_node, client_node, _) = setup_test_lsps2 ( ) ;
504+
505+ let client_handler = client_node. liquidity_manager . lsps2_client_handler ( ) . unwrap ( ) ;
506+
507+ for _ in 0 ..MAX_PENDING_REQUESTS_PER_PEER {
508+ let _ = client_handler. request_opening_params ( service_node_id, None ) ;
509+ let req_msg = get_lsps_message ! ( client_node, service_node_id) ;
510+ let result = service_node. liquidity_manager . handle_custom_message ( req_msg, client_node_id) ;
511+ assert ! ( result. is_ok( ) ) ;
512+ let event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
513+ match event {
514+ LiquidityEvent :: LSPS2Service ( LSPS2ServiceEvent :: GetInfo { .. } ) => { } ,
515+ _ => panic ! ( "Unexpected event" ) ,
516+ }
517+ }
518+
519+ // Test per-peer limit: the next request should be rejected
520+ let rejected_req_id = client_handler. request_opening_params ( service_node_id, None ) ;
521+ let rejected_req_msg = get_lsps_message ! ( client_node, service_node_id) ;
522+
523+ let result =
524+ service_node. liquidity_manager . handle_custom_message ( rejected_req_msg, client_node_id) ;
525+ assert ! ( result. is_err( ) , "We should have hit the per-peer limit" ) ;
526+
527+ let get_info_error_response = get_lsps_message ! ( service_node, client_node_id) ;
528+ let result = client_node
529+ . liquidity_manager
530+ . handle_custom_message ( get_info_error_response, service_node_id) ;
531+ assert ! ( result. is_err( ) ) ;
532+
533+ let event = client_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
534+ match event {
535+ LiquidityEvent :: LSPS2Client ( LSPS2ClientEvent :: GetInfoFailed {
536+ request_id,
537+ counterparty_node_id,
538+ error,
539+ } ) => {
540+ assert_eq ! ( request_id, rejected_req_id) ;
541+ assert_eq ! ( counterparty_node_id, service_node_id) ;
542+ assert_eq ! ( error. code, 1 ) ; // LSPS0_CLIENT_REJECTED_ERROR_CODE
543+ } ,
544+ _ => panic ! ( "Expected LSPS2ClientEvent::GetInfoFailed event" ) ,
545+ }
546+ }
547+
548+ #[ test]
549+ fn max_total_requests_buy_rejected ( ) {
550+ let ( service_node_id, _, service_node, client_node, _) = setup_test_lsps2 ( ) ;
551+
552+ let client_handler = client_node. liquidity_manager . lsps2_client_handler ( ) . unwrap ( ) ;
553+ let service_handler = service_node. liquidity_manager . lsps2_service_handler ( ) . unwrap ( ) ;
554+ let secp = Secp256k1 :: new ( ) ;
555+
556+ let special_sk_bytes = [ 99u8 ; 32 ] ;
557+ let special_sk = SecretKey :: from_slice ( & special_sk_bytes) . unwrap ( ) ;
558+ let special_node_id = PublicKey :: from_secret_key ( & secp, & special_sk) ;
559+
560+ let _ = client_handler. request_opening_params ( service_node_id, None ) ;
561+ let get_info_request = get_lsps_message ! ( client_node, service_node_id) ;
562+ service_node
563+ . liquidity_manager
564+ . handle_custom_message ( get_info_request, special_node_id)
565+ . unwrap ( ) ;
566+
567+ let get_info_event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
568+ match get_info_event {
569+ LiquidityEvent :: LSPS2Service ( LSPS2ServiceEvent :: GetInfo { request_id, .. } ) => {
570+ let raw_opening_params = LSPS2RawOpeningFeeParams {
571+ min_fee_msat : 100 ,
572+ proportional : 21 ,
573+ valid_until : LSPSDateTime :: from_str ( "2035-05-20T08:30:45Z" ) . unwrap ( ) ,
574+ min_lifetime : 144 ,
575+ max_client_to_self_delay : 128 ,
576+ min_payment_size_msat : 1 ,
577+ max_payment_size_msat : 100_000_000 ,
578+ } ;
579+
580+ service_handler
581+ . opening_fee_params_generated (
582+ & special_node_id,
583+ request_id,
584+ vec ! [ raw_opening_params] ,
585+ )
586+ . unwrap ( ) ;
587+ } ,
588+ _ => panic ! ( "Unexpected event" ) ,
589+ }
590+
591+ let get_info_response = get_lsps_message ! ( service_node, special_node_id) ;
592+ client_node
593+ . liquidity_manager
594+ . handle_custom_message ( get_info_response, service_node_id)
595+ . unwrap ( ) ;
596+
597+ let opening_params_event = client_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
598+ let opening_fee_params = match opening_params_event {
599+ LiquidityEvent :: LSPS2Client ( LSPS2ClientEvent :: OpeningParametersReady {
600+ opening_fee_params_menu,
601+ ..
602+ } ) => opening_fee_params_menu. first ( ) . unwrap ( ) . clone ( ) ,
603+ _ => panic ! ( "Unexpected event" ) ,
604+ } ;
605+
606+ // Now fill up the global limit with additional GetInfo requests from other peers
607+ let mut filled = 0 ;
608+ let mut peer_idx = 0 ;
609+
610+ while filled < MAX_TOTAL_PENDING_REQUESTS {
611+ let sk_bytes = [ peer_idx as u8 + 1 ; 32 ] ;
612+ let sk = SecretKey :: from_slice ( & sk_bytes) . unwrap ( ) ;
613+ let peer_node_id = PublicKey :: from_secret_key ( & secp, & sk) ;
614+
615+ // Skip if this is our special node
616+ if peer_node_id == special_node_id {
617+ peer_idx += 1 ;
618+ continue ;
619+ }
620+
621+ for _ in 0 ..MAX_PENDING_REQUESTS_PER_PEER {
622+ if filled >= MAX_TOTAL_PENDING_REQUESTS {
623+ break ;
624+ }
625+
626+ let _ = client_handler. request_opening_params ( service_node_id, None ) ;
627+ let req_msg = get_lsps_message ! ( client_node, service_node_id) ;
628+ let result =
629+ service_node. liquidity_manager . handle_custom_message ( req_msg, peer_node_id) ;
630+ assert ! ( result. is_ok( ) ) ;
631+
632+ let event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
633+ match event {
634+ LiquidityEvent :: LSPS2Service ( LSPS2ServiceEvent :: GetInfo { .. } ) => { } ,
635+ _ => panic ! ( "Unexpected event" ) ,
636+ }
637+
638+ filled += 1 ;
639+ }
640+ peer_idx += 1 ;
641+ }
642+
643+ // Now try to send a Buy request with our special node, which should be rejected
644+ let payment_size_msat = Some ( 1_000_000 ) ;
645+ let buy_request_id = client_handler
646+ . select_opening_params ( service_node_id, payment_size_msat, opening_fee_params)
647+ . unwrap ( ) ;
648+ let buy_request = get_lsps_message ! ( client_node, service_node_id) ;
649+
650+ let result = service_node. liquidity_manager . handle_custom_message ( buy_request, special_node_id) ;
651+ assert ! ( result. is_err( ) , "The Buy request should have been rejected" ) ;
652+
653+ let buy_error_response = get_lsps_message ! ( service_node, special_node_id) ;
654+ let result =
655+ client_node. liquidity_manager . handle_custom_message ( buy_error_response, service_node_id) ;
656+ assert ! ( result. is_err( ) ) ;
657+
658+ let event = client_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
659+ match event {
660+ LiquidityEvent :: LSPS2Client ( LSPS2ClientEvent :: BuyRequestFailed {
661+ request_id,
662+ counterparty_node_id,
663+ error,
664+ } ) => {
665+ assert_eq ! ( request_id, buy_request_id) ;
666+ assert_eq ! ( counterparty_node_id, service_node_id) ;
667+ assert_eq ! ( error. code, 1 ) ; // LSPS0_CLIENT_REJECTED_ERROR_CODE
668+ } ,
669+ _ => panic ! ( "Expected LSPS2ClientEvent::BuyRequestFailed event" ) ,
670+ }
671+ }
672+
673+ #[ test]
674+ fn invalid_token_flow ( ) {
675+ let ( service_node_id, client_node_id, service_node, client_node, _promise_secret) =
676+ setup_test_lsps2 ( ) ;
677+
678+ let client_handler = client_node. liquidity_manager . lsps2_client_handler ( ) . unwrap ( ) ;
679+ let service_handler = service_node. liquidity_manager . lsps2_service_handler ( ) . unwrap ( ) ;
680+
681+ let token = Some ( "invalid_token" . to_string ( ) ) ;
682+ let get_info_request_id = client_handler. request_opening_params ( service_node_id, token) ;
683+ let get_info_request = get_lsps_message ! ( client_node, service_node_id) ;
684+
685+ service_node. liquidity_manager . handle_custom_message ( get_info_request, client_node_id) . unwrap ( ) ;
686+
687+ let get_info_event = service_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
688+ match get_info_event {
689+ LiquidityEvent :: LSPS2Service ( LSPS2ServiceEvent :: GetInfo {
690+ request_id,
691+ counterparty_node_id,
692+ token,
693+ } ) => {
694+ assert_eq ! ( request_id, get_info_request_id) ;
695+ assert_eq ! ( counterparty_node_id, client_node_id) ;
696+ assert_eq ! ( token, Some ( "invalid_token" . to_string( ) ) ) ;
697+
698+ // Service rejects the token as invalid
699+ service_handler. invalid_token_provided ( & client_node_id, request_id. clone ( ) ) . unwrap ( ) ;
700+
701+ // Attempt to respond to the same request again which should fail
702+ // because the request has been removed from pending_requests
703+ let raw_opening_params = LSPS2RawOpeningFeeParams {
704+ min_fee_msat : 100 ,
705+ proportional : 21 ,
706+ valid_until : LSPSDateTime :: from_str ( "2035-05-20T08:30:45Z" ) . unwrap ( ) ,
707+ min_lifetime : 144 ,
708+ max_client_to_self_delay : 128 ,
709+ min_payment_size_msat : 1 ,
710+ max_payment_size_msat : 100_000_000 ,
711+ } ;
712+
713+ let result = service_handler. opening_fee_params_generated (
714+ & client_node_id,
715+ request_id. clone ( ) ,
716+ vec ! [ raw_opening_params] ,
717+ ) ;
718+
719+ assert ! ( result. is_err( ) , "Request should have been removed from pending_requests" ) ;
720+ } ,
721+ _ => panic ! ( "Unexpected event" ) ,
722+ }
723+
724+ let get_info_error_response = get_lsps_message ! ( service_node, client_node_id) ;
725+
726+ client_node
727+ . liquidity_manager
728+ . handle_custom_message ( get_info_error_response, service_node_id)
729+ . unwrap_err ( ) ;
730+
731+ let error_event = client_node. liquidity_manager . next_event ( ) . unwrap ( ) ;
732+ match error_event {
733+ LiquidityEvent :: LSPS2Client ( LSPS2ClientEvent :: GetInfoFailed {
734+ request_id,
735+ counterparty_node_id,
736+ error,
737+ } ) => {
738+ assert_eq ! ( request_id, get_info_request_id) ;
739+ assert_eq ! ( counterparty_node_id, service_node_id) ;
740+ assert_eq ! ( error. code, 200 ) ; // LSPS2_GET_INFO_REQUEST_UNRECOGNIZED_OR_STALE_TOKEN_ERROR_CODE
741+ } ,
742+ _ => panic ! ( "Expected LSPS2ClientEvent::GetInfoFailed event" ) ,
743+ }
744+ }
0 commit comments