Skip to content

Commit d1ef13f

Browse files
committed
lsps2: Test restored BOLT12 leases
Rebuild the receiver from its persisted store and pay the same long-lived offer again. Verify the pending offer survives and the exact cached lease is consumed before its replacement is negotiated. Co-Authored-By: HAL 9000
1 parent a5456d8 commit d1ef13f

1 file changed

Lines changed: 94 additions & 4 deletions

File tree

tests/integration_tests_rust.rs

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use ldk_node::{BuildError, Builder, Event, Node, NodeError, ReserveType};
4040
use lightning::ln::channelmanager::PaymentId;
4141
use lightning::routing::gossip::{NodeAlias, NodeId};
4242
use lightning::routing::router::RouteParametersConfig;
43+
use lightning::util::persist::KVStore;
4344
use lightning_invoice::{Bolt11InvoiceDescription, Description};
4445
use lightning_types::payment::{PaymentHash, PaymentPreimage};
4546
use 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

Comments
 (0)