Skip to content

Commit 6bc7dcb

Browse files
committed
lsps2: Test BOLT12 JIT payments
Cover fixed and variable BOLT12 offers through a real LSPS2 service. Verify node-ID offer addressing, fee withholding, fresh JIT channels, and the variable-amount single-path behavior. Co-Authored-By: HAL 9000
1 parent 37728cb commit 6bc7dcb

1 file changed

Lines changed: 131 additions & 0 deletions

File tree

tests/integration_tests_rust.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2986,6 +2986,137 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
29862986
assert_eq!(client_node.payment(&payment_id).unwrap().status, PaymentStatus::Failed);
29872987
}
29882988

2989+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
2990+
async fn bolt12_lsps2_client_service_integration() {
2991+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
2992+
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
2993+
2994+
let mut sync_config = EsploraSyncConfig::default();
2995+
sync_config.background_sync_config = None;
2996+
2997+
let channel_opening_fee_ppm = 10_000;
2998+
let lsps2_service_config = LSPS2ServiceConfig {
2999+
require_token: None,
3000+
advertise_service: false,
3001+
channel_opening_fee_ppm,
3002+
channel_over_provisioning_ppm: 100_000,
3003+
max_payment_size_msat: 1_000_000_000,
3004+
min_payment_size_msat: 0,
3005+
min_channel_lifetime: 100,
3006+
min_channel_opening_fee_msat: 0,
3007+
max_client_to_self_delay: 1024,
3008+
client_trusts_lsp: true,
3009+
disable_client_reserve: false,
3010+
};
3011+
3012+
let service_config = random_config();
3013+
setup_builder!(service_builder, service_config.node_config);
3014+
service_builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config));
3015+
service_builder.enable_liquidity_provider(lsps2_service_config);
3016+
let service_node = service_builder.build(service_config.node_entropy.into()).unwrap();
3017+
service_node.start().unwrap();
3018+
3019+
let service_node_id = service_node.node_id();
3020+
let service_addr = service_node.listening_addresses().unwrap().first().unwrap().clone();
3021+
3022+
let client_config = random_config();
3023+
setup_builder!(client_builder, client_config.node_config);
3024+
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();
3027+
client_node.start().unwrap();
3028+
3029+
let payer_config = random_config();
3030+
setup_builder!(payer_builder, payer_config.node_config);
3031+
payer_builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config));
3032+
let payer_node = payer_builder.build(payer_config.node_entropy.into()).unwrap();
3033+
payer_node.start().unwrap();
3034+
3035+
let client_addr = client_node.listening_addresses().unwrap().first().unwrap().clone();
3036+
payer_node.connect(client_node.node_id(), client_addr, false).unwrap();
3037+
3038+
let service_onchain_addr = service_node.onchain_payment().new_address().unwrap();
3039+
let client_onchain_addr = client_node.onchain_payment().new_address().unwrap();
3040+
let payer_onchain_addr = payer_node.onchain_payment().new_address().unwrap();
3041+
premine_and_distribute_funds(
3042+
&bitcoind.client,
3043+
&electrsd.client,
3044+
vec![service_onchain_addr, client_onchain_addr, payer_onchain_addr],
3045+
Amount::from_sat(10_000_000),
3046+
)
3047+
.await;
3048+
service_node.sync_wallets().unwrap();
3049+
client_node.sync_wallets().unwrap();
3050+
payer_node.sync_wallets().unwrap();
3051+
3052+
open_channel(&payer_node, &service_node, 5_000_000, true, &electrsd).await;
3053+
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
3054+
service_node.sync_wallets().unwrap();
3055+
payer_node.sync_wallets().unwrap();
3056+
expect_channel_ready_event!(payer_node, service_node.node_id());
3057+
expect_channel_ready_event!(service_node, payer_node.node_id());
3058+
while payer_node.status().latest_node_announcement_broadcast_timestamp.is_none() {
3059+
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
3060+
}
3061+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
3062+
3063+
let fixed_amount_msat = 100_000_000;
3064+
let fixed_offer = client_node
3065+
.bolt12_payment()
3066+
.receive_via_jit_channel(fixed_amount_msat, "fixed", None, None, None)
3067+
.unwrap();
3068+
assert!(fixed_offer.paths().is_empty());
3069+
assert_eq!(fixed_offer.issuer_signing_pubkey(), Some(client_node.node_id()));
3070+
let fixed_payment_id =
3071+
payer_node.bolt12_payment().send(&fixed_offer, None, None, None).unwrap();
3072+
3073+
expect_channel_pending_event!(service_node, client_node.node_id());
3074+
expect_channel_ready_event!(service_node, client_node.node_id());
3075+
expect_event!(service_node, PaymentForwarded);
3076+
expect_channel_pending_event!(client_node, service_node.node_id());
3077+
expect_channel_ready_event!(client_node, service_node.node_id());
3078+
expect_payment_successful_event!(payer_node, Some(fixed_payment_id), None);
3079+
let fixed_fee_msat = fixed_amount_msat * channel_opening_fee_ppm as u64 / 1_000_000;
3080+
let fixed_received_msat = fixed_amount_msat - fixed_fee_msat;
3081+
let fixed_receiver_payment_id =
3082+
expect_payment_received_event!(client_node, fixed_received_msat).unwrap();
3083+
match client_node.payment(&fixed_receiver_payment_id).unwrap().kind {
3084+
PaymentKind::Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3085+
assert_eq!(counterparty_skimmed_fee_msat, Some(fixed_fee_msat));
3086+
},
3087+
_ => panic!("Unexpected payment kind"),
3088+
}
3089+
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.
3092+
let variable_amount_msat = 200_000_000;
3093+
let variable_offer = client_node
3094+
.bolt12_payment()
3095+
.receive_variable_amount_via_jit_channel("variable", None, None)
3096+
.unwrap();
3097+
let variable_payment_id = payer_node
3098+
.bolt12_payment()
3099+
.send_using_amount(&variable_offer, variable_amount_msat, None, None, None)
3100+
.unwrap();
3101+
3102+
expect_channel_pending_event!(service_node, client_node.node_id());
3103+
expect_channel_ready_event!(service_node, client_node.node_id());
3104+
expect_event!(service_node, PaymentForwarded);
3105+
expect_channel_pending_event!(client_node, service_node.node_id());
3106+
expect_channel_ready_event!(client_node, service_node.node_id());
3107+
expect_payment_successful_event!(payer_node, Some(variable_payment_id), None);
3108+
let variable_fee_msat = variable_amount_msat * channel_opening_fee_ppm as u64 / 1_000_000;
3109+
let variable_received_msat = variable_amount_msat - variable_fee_msat;
3110+
let variable_receiver_payment_id =
3111+
expect_payment_received_event!(client_node, variable_received_msat).unwrap();
3112+
match client_node.payment(&variable_receiver_payment_id).unwrap().kind {
3113+
PaymentKind::Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3114+
assert_eq!(counterparty_skimmed_fee_msat, Some(variable_fee_msat));
3115+
},
3116+
_ => panic!("Unexpected payment kind"),
3117+
}
3118+
}
3119+
29893120
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
29903121
async fn facade_logging() {
29913122
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();

0 commit comments

Comments
 (0)