@@ -3684,10 +3684,14 @@ async fn bolt12_lsps2_client_service_integration() {
36843684 let service_addr = service_node. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ;
36853685
36863686 let client_config = random_config ( ) ;
3687+ let client_store =
3688+ TestSyncStore :: new ( client_config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
36873689 setup_builder ! ( client_builder, client_config. node_config) ;
36883690 client_builder. set_chain_source_esplora ( esplora_url. clone ( ) , Some ( sync_config) ) ;
3689- client_builder. add_liquidity_source ( service_node_id, service_addr, None , true ) ;
3690- let client_node = client_builder. build ( client_config. node_entropy . into ( ) ) . unwrap ( ) ;
3691+ client_builder. add_liquidity_source ( service_node_id, service_addr. clone ( ) , None , true ) ;
3692+ let client_node = client_builder
3693+ . build_with_store ( client_config. node_entropy . into ( ) , client_store. clone ( ) )
3694+ . unwrap ( ) ;
36913695 client_node. start ( ) . unwrap ( ) ;
36923696
36933697 let payer_config = random_config ( ) ;
@@ -3779,8 +3783,93 @@ async fn bolt12_lsps2_client_service_integration() {
37793783 assert_eq ! ( client_node. list_channels( ) . len( ) , client_channel_count) ;
37803784 assert_eq ! ( service_node. list_channels( ) . len( ) , service_channel_count) ;
37813785
3782- // The first JIT channel cannot carry this larger variable payment. The variable offer disables
3783- // MPP, so the payer must use the fresh JIT path rather than splitting across both paths.
3786+ let persisted_lease_key =
3787+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) , async {
3788+ loop {
3789+ let keys = KVStore :: list ( & client_store, "lsps2_leases" , "" ) . await . unwrap ( ) ;
3790+ if let Some ( key) = keys. first ( ) {
3791+ return key. clone ( ) ;
3792+ }
3793+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
3794+ }
3795+ } )
3796+ . await
3797+ . expect ( "replacement lease should be persisted" ) ;
3798+ assert ! ( KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_ok( ) ) ;
3799+
3800+ let client_node_id = client_node. node_id ( ) ;
3801+ client_node. stop ( ) . unwrap ( ) ;
3802+ drop ( client_node) ;
3803+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) , async {
3804+ while payer_node. list_peers ( ) . iter ( ) . any ( |peer| peer. node_id == client_node_id)
3805+ || service_node. list_peers ( ) . iter ( ) . any ( |peer| peer. node_id == client_node_id)
3806+ {
3807+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
3808+ }
3809+ } )
3810+ . await
3811+ . expect ( "peers should observe the stopped client" ) ;
3812+
3813+ setup_builder ! ( restarted_client_builder, client_config. node_config) ;
3814+ restarted_client_builder. set_chain_source_esplora ( esplora_url. clone ( ) , Some ( sync_config) ) ;
3815+ restarted_client_builder. add_liquidity_source (
3816+ service_node_id,
3817+ service_addr. clone ( ) ,
3818+ None ,
3819+ true ,
3820+ ) ;
3821+ let client_node = restarted_client_builder
3822+ . build_with_store ( client_config. node_entropy . into ( ) , client_store. clone ( ) )
3823+ . unwrap ( ) ;
3824+ assert_eq ! ( client_node. node_id( ) , client_node_id) ;
3825+ assert ! ( KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_ok( ) ) ;
3826+ client_node. start ( ) . unwrap ( ) ;
3827+ let client_addr = client_node. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ;
3828+ payer_node. connect ( client_node. node_id ( ) , client_addr, false ) . unwrap ( ) ;
3829+
3830+ let restored_payment_id =
3831+ payer_node. bolt12_payment ( ) . send ( & fixed_offer, None , None , None ) . unwrap ( ) ;
3832+ expect_channel_pending_event ! ( service_node, client_node. node_id( ) ) ;
3833+ expect_channel_ready_event ! ( service_node, client_node. node_id( ) ) ;
3834+ expect_event ! ( service_node, PaymentForwarded ) ;
3835+ loop {
3836+ let event = tokio:: time:: timeout (
3837+ std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) ,
3838+ client_node. next_event_async ( ) ,
3839+ )
3840+ . await
3841+ . expect ( "restored client should receive a payment event" ) ;
3842+ match event {
3843+ Event :: ChannelPending { counterparty_node_id, .. } => {
3844+ assert_eq ! ( counterparty_node_id, service_node. node_id( ) ) ;
3845+ client_node. event_handled ( ) . unwrap ( ) ;
3846+ break ;
3847+ } ,
3848+ Event :: PaymentReceived { payment_id, amount_msat, .. } => {
3849+ assert_eq ! ( payment_id, ordinary_receiver_payment_id) ;
3850+ assert_eq ! ( amount_msat, ordinary_amount_msat) ;
3851+ client_node. event_handled ( ) . unwrap ( ) ;
3852+ } ,
3853+ unexpected => panic ! ( "Unexpected event after restoring client: {unexpected:?}" ) ,
3854+ }
3855+ }
3856+ expect_channel_ready_event ! ( client_node, service_node. node_id( ) ) ;
3857+ expect_payment_successful_event ! ( payer_node, restored_payment_id, None ) ;
3858+ let restored_receiver_payment_id =
3859+ expect_payment_received_event ! ( client_node, fixed_received_msat) ;
3860+ match client_node. payment ( & restored_receiver_payment_id) . unwrap ( ) . kind {
3861+ PaymentKind :: Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3862+ assert_eq ! ( counterparty_skimmed_fee_msat, Some ( fixed_fee_msat) ) ;
3863+ } ,
3864+ _ => panic ! ( "Unexpected payment kind" ) ,
3865+ }
3866+ assert ! (
3867+ KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_err( ) ,
3868+ "the restored lease must be consumed instead of renegotiating"
3869+ ) ;
3870+
3871+ // The fixed JIT channels cannot carry this larger variable payment. The variable offer disables
3872+ // MPP, so the payer must use the fresh JIT path rather than splitting across the existing paths.
37843873 let variable_amount_msat = 200_000_000 ;
37853874 let variable_offer =
37863875 client_node. bolt12_payment ( ) . receive_variable_amount ( "variable" , None ) . unwrap ( ) ;
0 commit comments