@@ -3181,10 +3181,14 @@ async fn bolt12_lsps2_client_service_integration() {
31813181 let service_addr = service_node. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ;
31823182
31833183 let client_config = random_config ( ) ;
3184+ let client_store =
3185+ TestSyncStore :: new ( client_config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
31843186 setup_builder ! ( client_builder, client_config. node_config) ;
31853187 client_builder. set_chain_source_esplora ( esplora_url. clone ( ) , Some ( sync_config) ) ;
3186- client_builder. add_liquidity_source ( service_node_id, service_addr, None , true ) ;
3187- let client_node = client_builder. build ( client_config. node_entropy . into ( ) ) . unwrap ( ) ;
3188+ client_builder. add_liquidity_source ( service_node_id, service_addr. clone ( ) , None , true ) ;
3189+ let client_node = client_builder
3190+ . build_with_store ( client_config. node_entropy . into ( ) , client_store. clone ( ) )
3191+ . unwrap ( ) ;
31883192 client_node. start ( ) . unwrap ( ) ;
31893193
31903194 let payer_config = random_config ( ) ;
@@ -3276,8 +3280,93 @@ async fn bolt12_lsps2_client_service_integration() {
32763280 assert_eq ! ( client_node. list_channels( ) . len( ) , client_channel_count) ;
32773281 assert_eq ! ( service_node. list_channels( ) . len( ) , service_channel_count) ;
32783282
3279- // The first JIT channel cannot carry this larger variable payment. The variable offer disables
3280- // MPP, so the payer must use the fresh JIT path rather than splitting across both paths.
3283+ let persisted_lease_key =
3284+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) , async {
3285+ loop {
3286+ let keys = KVStore :: list ( & client_store, "lsps2_leases" , "" ) . await . unwrap ( ) ;
3287+ if let Some ( key) = keys. first ( ) {
3288+ return key. clone ( ) ;
3289+ }
3290+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
3291+ }
3292+ } )
3293+ . await
3294+ . expect ( "replacement lease should be persisted" ) ;
3295+ assert ! ( KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_ok( ) ) ;
3296+
3297+ let client_node_id = client_node. node_id ( ) ;
3298+ client_node. stop ( ) . unwrap ( ) ;
3299+ drop ( client_node) ;
3300+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) , async {
3301+ while payer_node. list_peers ( ) . iter ( ) . any ( |peer| peer. node_id == client_node_id)
3302+ || service_node. list_peers ( ) . iter ( ) . any ( |peer| peer. node_id == client_node_id)
3303+ {
3304+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
3305+ }
3306+ } )
3307+ . await
3308+ . expect ( "peers should observe the stopped client" ) ;
3309+
3310+ setup_builder ! ( restarted_client_builder, client_config. node_config) ;
3311+ restarted_client_builder. set_chain_source_esplora ( esplora_url. clone ( ) , Some ( sync_config) ) ;
3312+ restarted_client_builder. add_liquidity_source (
3313+ service_node_id,
3314+ service_addr. clone ( ) ,
3315+ None ,
3316+ true ,
3317+ ) ;
3318+ let client_node = restarted_client_builder
3319+ . build_with_store ( client_config. node_entropy . into ( ) , client_store. clone ( ) )
3320+ . unwrap ( ) ;
3321+ assert_eq ! ( client_node. node_id( ) , client_node_id) ;
3322+ assert ! ( KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_ok( ) ) ;
3323+ client_node. start ( ) . unwrap ( ) ;
3324+ let client_addr = client_node. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ;
3325+ payer_node. connect ( client_node. node_id ( ) , client_addr, false ) . unwrap ( ) ;
3326+
3327+ let restored_payment_id =
3328+ payer_node. bolt12_payment ( ) . send ( & fixed_offer, None , None , None ) . unwrap ( ) ;
3329+ expect_channel_pending_event ! ( service_node, client_node. node_id( ) ) ;
3330+ expect_channel_ready_event ! ( service_node, client_node. node_id( ) ) ;
3331+ expect_event ! ( service_node, PaymentForwarded ) ;
3332+ loop {
3333+ let event = tokio:: time:: timeout (
3334+ std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) ,
3335+ client_node. next_event_async ( ) ,
3336+ )
3337+ . await
3338+ . expect ( "restored client should receive a payment event" ) ;
3339+ match event {
3340+ Event :: ChannelPending { counterparty_node_id, .. } => {
3341+ assert_eq ! ( counterparty_node_id, service_node. node_id( ) ) ;
3342+ client_node. event_handled ( ) . unwrap ( ) ;
3343+ break ;
3344+ } ,
3345+ Event :: PaymentReceived { payment_id, amount_msat, .. } => {
3346+ assert_eq ! ( payment_id, Some ( ordinary_receiver_payment_id) ) ;
3347+ assert_eq ! ( amount_msat, ordinary_amount_msat) ;
3348+ client_node. event_handled ( ) . unwrap ( ) ;
3349+ } ,
3350+ unexpected => panic ! ( "Unexpected event after restoring client: {unexpected:?}" ) ,
3351+ }
3352+ }
3353+ expect_channel_ready_event ! ( client_node, service_node. node_id( ) ) ;
3354+ expect_payment_successful_event ! ( payer_node, Some ( restored_payment_id) , None ) ;
3355+ let restored_receiver_payment_id =
3356+ expect_payment_received_event ! ( client_node, fixed_received_msat) . unwrap ( ) ;
3357+ match client_node. payment ( & restored_receiver_payment_id) . unwrap ( ) . kind {
3358+ PaymentKind :: Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3359+ assert_eq ! ( counterparty_skimmed_fee_msat, Some ( fixed_fee_msat) ) ;
3360+ } ,
3361+ _ => panic ! ( "Unexpected payment kind" ) ,
3362+ }
3363+ assert ! (
3364+ KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_err( ) ,
3365+ "the restored lease must be consumed instead of renegotiating"
3366+ ) ;
3367+
3368+ // The fixed JIT channels cannot carry this larger variable payment. The variable offer disables
3369+ // MPP, so the payer must use the fresh JIT path rather than splitting across the existing paths.
32813370 let variable_amount_msat = 200_000_000 ;
32823371 let variable_offer =
32833372 client_node. bolt12_payment ( ) . receive_variable_amount ( "variable" , None ) . unwrap ( ) ;
0 commit comments