@@ -40,6 +40,7 @@ use ldk_node::{BuildError, Builder, Event, Node, NodeError, ReserveType};
4040use lightning:: ln:: channelmanager:: PaymentId ;
4141use lightning:: routing:: gossip:: { NodeAlias , NodeId } ;
4242use lightning:: routing:: router:: RouteParametersConfig ;
43+ use lightning:: util:: persist:: KVStore ;
4344use lightning_invoice:: { Bolt11InvoiceDescription , Description } ;
4445use lightning_types:: payment:: { PaymentHash , PaymentPreimage } ;
4546use log:: LevelFilter ;
@@ -3020,10 +3021,14 @@ async fn bolt12_lsps2_client_service_integration() {
30203021 let service_addr = service_node. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ;
30213022
30223023 let client_config = random_config ( ) ;
3024+ let client_store =
3025+ TestSyncStore :: new ( client_config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
30233026 setup_builder ! ( client_builder, client_config. node_config) ;
30243027 client_builder. set_chain_source_esplora ( esplora_url. clone ( ) , Some ( sync_config) ) ;
3025- client_builder. add_liquidity_source ( service_node_id, service_addr, None , true ) ;
3026- let client_node = client_builder. build ( client_config. node_entropy . into ( ) ) . unwrap ( ) ;
3028+ client_builder. add_liquidity_source ( service_node_id, service_addr. clone ( ) , None , true ) ;
3029+ let client_node = client_builder
3030+ . build_with_store ( client_config. node_entropy . into ( ) , client_store. clone ( ) )
3031+ . unwrap ( ) ;
30273032 client_node. start ( ) . unwrap ( ) ;
30283033
30293034 let payer_config = random_config ( ) ;
@@ -3087,8 +3092,93 @@ async fn bolt12_lsps2_client_service_integration() {
30873092 _ => panic ! ( "Unexpected payment kind" ) ,
30883093 }
30893094
3090- // The first JIT channel cannot carry this larger variable payment. The variable offer disables
3091- // MPP, so the payer must use the fresh JIT path rather than splitting across both paths.
3095+ let persisted_lease_key =
3096+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) , async {
3097+ loop {
3098+ let keys = KVStore :: list ( & client_store, "lsps2_leases" , "" ) . await . unwrap ( ) ;
3099+ if let Some ( key) = keys. first ( ) {
3100+ return key. clone ( ) ;
3101+ }
3102+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
3103+ }
3104+ } )
3105+ . await
3106+ . expect ( "replacement lease should be persisted" ) ;
3107+ assert ! ( KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_ok( ) ) ;
3108+
3109+ let client_node_id = client_node. node_id ( ) ;
3110+ client_node. stop ( ) . unwrap ( ) ;
3111+ drop ( client_node) ;
3112+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) , async {
3113+ while payer_node. list_peers ( ) . iter ( ) . any ( |peer| peer. node_id == client_node_id)
3114+ || service_node. list_peers ( ) . iter ( ) . any ( |peer| peer. node_id == client_node_id)
3115+ {
3116+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 10 ) ) . await ;
3117+ }
3118+ } )
3119+ . await
3120+ . expect ( "peers should observe the stopped client" ) ;
3121+
3122+ setup_builder ! ( restarted_client_builder, client_config. node_config) ;
3123+ restarted_client_builder. set_chain_source_esplora ( esplora_url. clone ( ) , Some ( sync_config) ) ;
3124+ restarted_client_builder. add_liquidity_source (
3125+ service_node_id,
3126+ service_addr. clone ( ) ,
3127+ None ,
3128+ true ,
3129+ ) ;
3130+ let client_node = restarted_client_builder
3131+ . build_with_store ( client_config. node_entropy . into ( ) , client_store. clone ( ) )
3132+ . unwrap ( ) ;
3133+ assert_eq ! ( client_node. node_id( ) , client_node_id) ;
3134+ assert ! ( KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_ok( ) ) ;
3135+ client_node. start ( ) . unwrap ( ) ;
3136+ let client_addr = client_node. listening_addresses ( ) . unwrap ( ) . first ( ) . unwrap ( ) . clone ( ) ;
3137+ payer_node. connect ( client_node. node_id ( ) , client_addr, false ) . unwrap ( ) ;
3138+
3139+ let restored_payment_id =
3140+ payer_node. bolt12_payment ( ) . send ( & fixed_offer, None , None , None ) . unwrap ( ) ;
3141+ expect_channel_pending_event ! ( service_node, client_node. node_id( ) ) ;
3142+ expect_channel_ready_event ! ( service_node, client_node. node_id( ) ) ;
3143+ expect_event ! ( service_node, PaymentForwarded ) ;
3144+ loop {
3145+ let event = tokio:: time:: timeout (
3146+ std:: time:: Duration :: from_secs ( common:: INTEROP_TIMEOUT_SECS ) ,
3147+ client_node. next_event_async ( ) ,
3148+ )
3149+ . await
3150+ . expect ( "restored client should receive a payment event" ) ;
3151+ match event {
3152+ Event :: ChannelPending { counterparty_node_id, .. } => {
3153+ assert_eq ! ( counterparty_node_id, service_node. node_id( ) ) ;
3154+ client_node. event_handled ( ) . unwrap ( ) ;
3155+ break ;
3156+ } ,
3157+ Event :: PaymentReceived { payment_id, amount_msat, .. } => {
3158+ assert_eq ! ( payment_id, Some ( fixed_receiver_payment_id) ) ;
3159+ assert_eq ! ( amount_msat, fixed_received_msat) ;
3160+ client_node. event_handled ( ) . unwrap ( ) ;
3161+ } ,
3162+ unexpected => panic ! ( "Unexpected event after restoring client: {unexpected:?}" ) ,
3163+ }
3164+ }
3165+ expect_channel_ready_event ! ( client_node, service_node. node_id( ) ) ;
3166+ expect_payment_successful_event ! ( payer_node, Some ( restored_payment_id) , None ) ;
3167+ let restored_receiver_payment_id =
3168+ expect_payment_received_event ! ( client_node, fixed_received_msat) . unwrap ( ) ;
3169+ match client_node. payment ( & restored_receiver_payment_id) . unwrap ( ) . kind {
3170+ PaymentKind :: Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3171+ assert_eq ! ( counterparty_skimmed_fee_msat, Some ( fixed_fee_msat) ) ;
3172+ } ,
3173+ _ => panic ! ( "Unexpected payment kind" ) ,
3174+ }
3175+ assert ! (
3176+ KVStore :: read( & client_store, "lsps2_leases" , "" , & persisted_lease_key) . await . is_err( ) ,
3177+ "the restored lease must be consumed instead of renegotiating"
3178+ ) ;
3179+
3180+ // The fixed JIT channels cannot carry this larger variable payment. The variable offer disables
3181+ // MPP, so the payer must use the fresh JIT path rather than splitting across the existing paths.
30923182 let variable_amount_msat = 200_000_000 ;
30933183 let variable_offer = client_node
30943184 . bolt12_payment ( )
0 commit comments