Skip to content

Commit befcdce

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 f074860 commit befcdce

1 file changed

Lines changed: 157 additions & 0 deletions

File tree

tests/integration_tests_rust.rs

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3147,6 +3147,163 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
31473147
assert_eq!(client_node.payment(&payment_id).unwrap().status, PaymentStatus::Failed);
31483148
}
31493149

3150+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
3151+
async fn bolt12_lsps2_client_service_integration() {
3152+
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
3153+
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
3154+
3155+
let mut sync_config = EsploraSyncConfig::default();
3156+
sync_config.background_sync_config = None;
3157+
3158+
let channel_opening_fee_ppm = 10_000;
3159+
let lsps2_service_config = LSPS2ServiceConfig {
3160+
require_token: None,
3161+
advertise_service: false,
3162+
channel_opening_fee_ppm,
3163+
channel_over_provisioning_ppm: 100_000,
3164+
max_payment_size_msat: 1_000_000_000,
3165+
min_payment_size_msat: 0,
3166+
min_channel_lifetime: 100,
3167+
min_channel_opening_fee_msat: 0,
3168+
max_client_to_self_delay: 1024,
3169+
client_trusts_lsp: true,
3170+
disable_client_reserve: false,
3171+
};
3172+
3173+
let service_config = random_config();
3174+
setup_builder!(service_builder, service_config.node_config);
3175+
service_builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config));
3176+
service_builder.enable_liquidity_provider(lsps2_service_config);
3177+
let service_node = service_builder.build(service_config.node_entropy.into()).unwrap();
3178+
service_node.start().unwrap();
3179+
3180+
let service_node_id = service_node.node_id();
3181+
let service_addr = service_node.listening_addresses().unwrap().first().unwrap().clone();
3182+
3183+
let client_config = random_config();
3184+
setup_builder!(client_builder, client_config.node_config);
3185+
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_node.start().unwrap();
3189+
3190+
let payer_config = random_config();
3191+
setup_builder!(payer_builder, payer_config.node_config);
3192+
payer_builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config));
3193+
let payer_node = payer_builder.build(payer_config.node_entropy.into()).unwrap();
3194+
payer_node.start().unwrap();
3195+
3196+
let client_addr = client_node.listening_addresses().unwrap().first().unwrap().clone();
3197+
payer_node.connect(client_node.node_id(), client_addr, false).unwrap();
3198+
3199+
let service_onchain_addr = service_node.onchain_payment().new_address().unwrap();
3200+
let client_onchain_addr = client_node.onchain_payment().new_address().unwrap();
3201+
let payer_onchain_addr = payer_node.onchain_payment().new_address().unwrap();
3202+
premine_and_distribute_funds(
3203+
&bitcoind.client,
3204+
&electrsd.client,
3205+
vec![service_onchain_addr, client_onchain_addr, payer_onchain_addr],
3206+
Amount::from_sat(10_000_000),
3207+
)
3208+
.await;
3209+
service_node.sync_wallets().unwrap();
3210+
client_node.sync_wallets().unwrap();
3211+
payer_node.sync_wallets().unwrap();
3212+
3213+
open_channel(&payer_node, &service_node, 5_000_000, true, &electrsd).await;
3214+
generate_blocks_and_wait(&bitcoind.client, &electrsd.client, 6).await;
3215+
service_node.sync_wallets().unwrap();
3216+
payer_node.sync_wallets().unwrap();
3217+
expect_channel_ready_event!(payer_node, service_node.node_id());
3218+
expect_channel_ready_event!(service_node, payer_node.node_id());
3219+
while payer_node.status().latest_node_announcement_broadcast_timestamp.is_none() {
3220+
tokio::time::sleep(std::time::Duration::from_millis(10)).await;
3221+
}
3222+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
3223+
3224+
let fixed_amount_msat = 100_000_000;
3225+
// The recipient has no channel yet, but the connected payer gives the default message router a
3226+
// peer through which it can construct an offer path. This keeps the long-lived offer addressed
3227+
// by a blinded node path; the single-use intercept SCID is introduced only in the invoice.
3228+
assert!(client_node.list_channels().is_empty());
3229+
let fixed_offer =
3230+
client_node.bolt12_payment().receive(fixed_amount_msat, "fixed", None, None).unwrap();
3231+
assert!(!fixed_offer.paths().is_empty());
3232+
assert_ne!(fixed_offer.issuer_signing_pubkey(), Some(client_node.node_id()));
3233+
let fixed_payment_id =
3234+
payer_node.bolt12_payment().send(&fixed_offer, None, None, None).unwrap();
3235+
3236+
expect_channel_pending_event!(service_node, client_node.node_id());
3237+
expect_channel_ready_event!(service_node, client_node.node_id());
3238+
expect_event!(service_node, PaymentForwarded);
3239+
expect_channel_pending_event!(client_node, service_node.node_id());
3240+
expect_channel_ready_event!(client_node, service_node.node_id());
3241+
expect_payment_successful_event!(payer_node, Some(fixed_payment_id), None);
3242+
let fixed_fee_msat = fixed_amount_msat * channel_opening_fee_ppm as u64 / 1_000_000;
3243+
let fixed_received_msat = fixed_amount_msat - fixed_fee_msat;
3244+
let fixed_receiver_payment_id =
3245+
expect_payment_received_event!(client_node, fixed_received_msat).unwrap();
3246+
match client_node.payment(&fixed_receiver_payment_id).unwrap().kind {
3247+
PaymentKind::Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3248+
assert_eq!(counterparty_skimmed_fee_msat, Some(fixed_fee_msat));
3249+
},
3250+
_ => panic!("Unexpected payment kind"),
3251+
}
3252+
3253+
// The over-provisioned part of the first JIT channel can receive this payment in full. The
3254+
// offers flow must therefore keep the ordinary blinded path and avoid negotiating or exposing a
3255+
// second intercept SCID.
3256+
let client_channel_count = client_node.list_channels().len();
3257+
let service_channel_count = service_node.list_channels().len();
3258+
let ordinary_amount_msat = 5_000_000;
3259+
let ordinary_offer = client_node
3260+
.bolt12_payment()
3261+
.receive(ordinary_amount_msat, "existing inbound", None, None)
3262+
.unwrap();
3263+
let ordinary_payment_id =
3264+
payer_node.bolt12_payment().send(&ordinary_offer, None, None, None).unwrap();
3265+
3266+
expect_event!(service_node, PaymentForwarded);
3267+
expect_payment_successful_event!(payer_node, Some(ordinary_payment_id), None);
3268+
let ordinary_receiver_payment_id =
3269+
expect_payment_received_event!(client_node, ordinary_amount_msat).unwrap();
3270+
match client_node.payment(&ordinary_receiver_payment_id).unwrap().kind {
3271+
PaymentKind::Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3272+
assert_eq!(counterparty_skimmed_fee_msat, None);
3273+
},
3274+
_ => panic!("Unexpected payment kind"),
3275+
}
3276+
assert_eq!(client_node.list_channels().len(), client_channel_count);
3277+
assert_eq!(service_node.list_channels().len(), service_channel_count);
3278+
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.
3281+
let variable_amount_msat = 200_000_000;
3282+
let variable_offer =
3283+
client_node.bolt12_payment().receive_variable_amount("variable", None).unwrap();
3284+
let variable_payment_id = payer_node
3285+
.bolt12_payment()
3286+
.send_using_amount(&variable_offer, variable_amount_msat, None, None, None)
3287+
.unwrap();
3288+
3289+
expect_channel_pending_event!(service_node, client_node.node_id());
3290+
expect_channel_ready_event!(service_node, client_node.node_id());
3291+
expect_event!(service_node, PaymentForwarded);
3292+
expect_channel_pending_event!(client_node, service_node.node_id());
3293+
expect_channel_ready_event!(client_node, service_node.node_id());
3294+
expect_payment_successful_event!(payer_node, Some(variable_payment_id), None);
3295+
let variable_fee_msat = variable_amount_msat * channel_opening_fee_ppm as u64 / 1_000_000;
3296+
let variable_received_msat = variable_amount_msat - variable_fee_msat;
3297+
let variable_receiver_payment_id =
3298+
expect_payment_received_event!(client_node, variable_received_msat).unwrap();
3299+
match client_node.payment(&variable_receiver_payment_id).unwrap().kind {
3300+
PaymentKind::Bolt12Offer { counterparty_skimmed_fee_msat, .. } => {
3301+
assert_eq!(counterparty_skimmed_fee_msat, Some(variable_fee_msat));
3302+
},
3303+
_ => panic!("Unexpected payment kind"),
3304+
}
3305+
}
3306+
31503307
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
31513308
async fn facade_logging() {
31523309
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();

0 commit comments

Comments
 (0)