Skip to content

Commit bdceefb

Browse files
committed
Make payment_id a required field in Events
The switch to tracking payments by ID happened with LDK Node v0.3.0, which is >1.5 years old by now. We can be pretty certain that nobody is upgrading from an older version to the upcoming v0.8. Here we hence make the `payment_id` fields in `Event` required which is a nice API simplification that will also be utilized in the next commit. Co-Authored-By: HAL 9000
1 parent 8dd06bf commit bdceefb

6 files changed

Lines changed: 40 additions & 44 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@
55
prior LSPS2 fee-limit state stored in `PaymentKind::Bolt11Jit` is not migrated.
66
- Users of the VSS storage backend must upgrade their VSS server to at least version
77
`v0.1.0-alpha.0` before upgrading LDK Node.
8+
- The `payment_id` field on the `PaymentSuccessful`, `PaymentFailed`, and
9+
`PaymentReceived` events is now a required (non-optional) `PaymentId`. Events
10+
persisted by LDK Node v0.2.1 or earlier (which stored `payment_id` as
11+
optional) will fail to deserialize on read; users upgrading from those
12+
versions need to drain pending events before the upgrade.
813

914
# 0.7.0 - Dec. 3, 2025
1015
This seventh minor release introduces numerous new features, bug fixes, and API improvements. In particular, it adds support for channel Splicing, Async Payments, as well as sourcing chain data from a Bitcoin Core REST backend.

src/event.rs

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,7 @@ pub enum Event {
103103
/// A sent payment was successful.
104104
PaymentSuccessful {
105105
/// A local identifier used to track the payment.
106-
///
107-
/// Will only be `None` for events serialized with LDK Node v0.2.1 or prior.
108-
payment_id: Option<PaymentId>,
106+
payment_id: PaymentId,
109107
/// The hash of the payment.
110108
payment_hash: PaymentHash,
111109
/// The preimage to the `payment_hash`.
@@ -131,9 +129,7 @@ pub enum Event {
131129
/// A sent payment has failed.
132130
PaymentFailed {
133131
/// A local identifier used to track the payment.
134-
///
135-
/// Will only be `None` for events serialized with LDK Node v0.2.1 or prior.
136-
payment_id: Option<PaymentId>,
132+
payment_id: PaymentId,
137133
/// The hash of the payment.
138134
///
139135
/// This will be `None` if the payment failed before receiving an invoice when paying a
@@ -149,9 +145,7 @@ pub enum Event {
149145
/// A payment has been received.
150146
PaymentReceived {
151147
/// A local identifier used to track the payment.
152-
///
153-
/// Will only be `None` for events serialized with LDK Node v0.2.1 or prior.
154-
payment_id: Option<PaymentId>,
148+
payment_id: PaymentId,
155149
/// The hash of the payment.
156150
payment_hash: PaymentHash,
157151
/// The value, in thousandths of a satoshi, that has been received.
@@ -298,18 +292,18 @@ impl_writeable_tlv_based_enum!(Event,
298292
(0, PaymentSuccessful) => {
299293
(0, payment_hash, required),
300294
(1, fee_paid_msat, option),
301-
(3, payment_id, option),
295+
(3, payment_id, required),
302296
(5, payment_preimage, option),
303297
(7, bolt12_invoice, option),
304298
},
305299
(1, PaymentFailed) => {
306300
(0, payment_hash, option),
307301
(1, reason, upgradable_option),
308-
(3, payment_id, option),
302+
(3, payment_id, required),
309303
},
310304
(2, PaymentReceived) => {
311305
(0, payment_hash, required),
312-
(1, payment_id, option),
306+
(1, payment_id, required),
313307
(2, amount_msat, required),
314308
(3, custom_records, optional_vec),
315309
},
@@ -1095,7 +1089,7 @@ where
10951089
}
10961090

10971091
let event = Event::PaymentReceived {
1098-
payment_id: Some(payment_id),
1092+
payment_id,
10991093
payment_hash,
11001094
amount_msat,
11011095
custom_records: onion_fields
@@ -1160,7 +1154,7 @@ where
11601154
);
11611155
});
11621156
let event = Event::PaymentSuccessful {
1163-
payment_id: Some(payment_id),
1157+
payment_id,
11641158
payment_hash,
11651159
payment_preimage: Some(payment_preimage),
11661160
fee_paid_msat,
@@ -1196,8 +1190,7 @@ where
11961190
},
11971191
};
11981192

1199-
let event =
1200-
Event::PaymentFailed { payment_id: Some(payment_id), payment_hash, reason };
1193+
let event = Event::PaymentFailed { payment_id, payment_hash, reason };
12011194
match self.event_queue.add_event(event).await {
12021195
Ok(_) => return Ok(()),
12031196
Err(e) => {

tests/common/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,8 +222,8 @@ macro_rules! expect_payment_received_event {
222222
ref e @ Event::PaymentReceived { payment_id, amount_msat, .. } => {
223223
println!("{} got event {:?}", $node.node_id(), e);
224224
assert_eq!(amount_msat, $amount_msat);
225-
let payment = $node.payment(&payment_id.unwrap()).unwrap();
226-
if !matches!(payment.kind, ldk_node::payment::PaymentKind::Onchain { .. }) {
225+
let payment = $node.payment(&payment_id).unwrap();
226+
if !matches!(payment.kind, PaymentKind::Onchain { .. }) {
227227
assert_eq!(payment.fee_paid_msat, None);
228228
}
229229
$node.event_handled().unwrap();
@@ -290,7 +290,7 @@ macro_rules! expect_payment_successful_event {
290290
if let Some(fee_msat) = $fee_paid_msat {
291291
assert_eq!(fee_paid_msat, fee_msat);
292292
}
293-
let payment = $node.payment(&$payment_id.unwrap()).unwrap();
293+
let payment = $node.payment(&$payment_id).unwrap();
294294
assert_eq!(payment.fee_paid_msat, fee_paid_msat);
295295
assert_eq!(payment_id, $payment_id);
296296
$node.event_handled().unwrap();
@@ -1235,7 +1235,7 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
12351235
.claim_for_hash(manual_payment_hash, claimable_amount_msat, manual_preimage)
12361236
.unwrap();
12371237
expect_payment_received_event!(node_b, claimable_amount_msat);
1238-
expect_payment_successful_event!(node_a, Some(manual_payment_id), None);
1238+
expect_payment_successful_event!(node_a, manual_payment_id, None);
12391239
assert_eq!(node_a.payment(&manual_payment_id).unwrap().status, PaymentStatus::Succeeded);
12401240
assert_eq!(node_a.payment(&manual_payment_id).unwrap().direction, PaymentDirection::Outbound);
12411241
assert_eq!(

tests/integration_tests_hrn.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,5 +79,5 @@ async fn unified_send_to_hrn() {
7979
},
8080
};
8181

82-
expect_payment_successful_event!(node_a, Some(offer_payment_id), None);
82+
expect_payment_successful_event!(node_a, offer_payment_id, None);
8383
}

tests/integration_tests_rust.rs

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,12 @@ async fn split_underpaid_bolt11_payment() {
380380
.unwrap();
381381

382382
let receiver_payment_id = expect_payment_received_event!(node_c, amount_msat);
383-
assert_eq!(receiver_payment_id, Some(PaymentId(invoice.payment_hash().0)));
384-
expect_payment_successful_event!(node_a, Some(payment_id_a), None);
385-
expect_payment_successful_event!(node_b, Some(payment_id_b), None);
383+
assert_eq!(receiver_payment_id, PaymentId(invoice.payment_hash().0));
384+
expect_payment_successful_event!(node_a, payment_id_a, None);
385+
expect_payment_successful_event!(node_b, payment_id_b, None);
386386

387387
// The receiver records the full invoice amount; each payer records only its own half.
388-
let receiver_payments =
389-
node_c.list_payments_with_filter(|p| p.id == receiver_payment_id.unwrap());
388+
let receiver_payments = node_c.list_payments_with_filter(|p| p.id == receiver_payment_id);
390389
assert_eq!(receiver_payments.len(), 1);
391390
assert_eq!(receiver_payments.first().unwrap().amount_msat, Some(amount_msat));
392391

@@ -1202,7 +1201,7 @@ async fn splice_channel() {
12021201
let payment_id =
12031202
node_b.spontaneous_payment().send(amount_msat, node_a.node_id(), None).unwrap();
12041203

1205-
expect_payment_successful_event!(node_b, Some(payment_id), None);
1204+
expect_payment_successful_event!(node_b, payment_id, None);
12061205
expect_payment_received_event!(node_a, amount_msat);
12071206

12081207
// Mine a block to give time for the HTLC to resolve
@@ -1298,7 +1297,7 @@ async fn simple_bolt12_send_receive() {
12981297
match event {
12991298
ref e @ Event::PaymentSuccessful { payment_id: ref evt_id, ref bolt12_invoice, .. } => {
13001299
println!("{} got event {:?}", node_a.node_id(), e);
1301-
assert_eq!(*evt_id, Some(payment_id));
1300+
assert_eq!(*evt_id, payment_id);
13021301
assert!(
13031302
bolt12_invoice.is_some(),
13041303
"bolt12_invoice should be present for BOLT12 payments"
@@ -1372,7 +1371,7 @@ async fn simple_bolt12_send_receive() {
13721371
)
13731372
.unwrap();
13741373

1375-
expect_payment_successful_event!(node_a, Some(payment_id), None);
1374+
expect_payment_successful_event!(node_a, payment_id, None);
13761375
let node_a_payments = node_a.list_payments_with_filter(|p| {
13771376
matches!(p.kind, PaymentKind::Bolt12Offer { .. }) && p.id == payment_id
13781377
});
@@ -1445,7 +1444,7 @@ async fn simple_bolt12_send_receive() {
14451444
.first()
14461445
.unwrap()
14471446
.id;
1448-
expect_payment_successful_event!(node_b, Some(node_b_payment_id), None);
1447+
expect_payment_successful_event!(node_b, node_b_payment_id, None);
14491448

14501449
let node_b_payments = node_b.list_payments_with_filter(|p| {
14511450
matches!(p.kind, PaymentKind::Bolt12Refund { .. }) && p.id == node_b_payment_id
@@ -1619,7 +1618,7 @@ async fn async_payment() {
16191618

16201619
node_receiver.start().unwrap();
16211620

1622-
expect_payment_successful_event!(node_sender, Some(payment_id), None);
1621+
expect_payment_successful_event!(node_sender, payment_id, None);
16231622
}
16241623

16251624
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
@@ -1845,7 +1844,7 @@ async fn unified_send_receive_bip21_uri() {
18451844
},
18461845
};
18471846

1848-
expect_payment_successful_event!(node_a, Some(offer_payment_id), None);
1847+
expect_payment_successful_event!(node_a, offer_payment_id, None);
18491848

18501849
// Cut off the BOLT12 part to fallback to BOLT11.
18511850
let uri_str_without_offer = uri_str.split("&lno=").next().unwrap();
@@ -1865,7 +1864,7 @@ async fn unified_send_receive_bip21_uri() {
18651864
panic!("Expected Bolt11 payment but got error: {:?}", e);
18661865
},
18671866
};
1868-
expect_payment_successful_event!(node_a, Some(invoice_payment_id), None);
1867+
expect_payment_successful_event!(node_a, invoice_payment_id, None);
18691868

18701869
let expect_onchain_amount_sats = 800_000;
18711870
let onchain_uni_payment =
@@ -2000,9 +1999,9 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
20001999

20012000
let service_fee_msat = (jit_amount_msat * channel_opening_fee_ppm as u64) / 1_000_000;
20022001
let expected_received_amount_msat = jit_amount_msat - service_fee_msat;
2003-
expect_payment_successful_event!(payer_node, Some(payment_id), None);
2002+
expect_payment_successful_event!(payer_node, payment_id, None);
20042003
let client_payment_id =
2005-
expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap();
2004+
expect_payment_received_event!(client_node, expected_received_amount_msat);
20062005
let client_payment = client_node.payment(&client_payment_id).unwrap();
20072006
match client_payment.kind {
20082007
PaymentKind::Bolt11 { counterparty_skimmed_fee_msat, .. } => {
@@ -2029,7 +2028,7 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
20292028
// are working as expected.
20302029
println!("Paying regular invoice!");
20312030
let payment_id = payer_node.bolt11_payment().send(&invoice, None).unwrap();
2032-
expect_payment_successful_event!(payer_node, Some(payment_id), None);
2031+
expect_payment_successful_event!(payer_node, payment_id, None);
20332032
expect_event!(service_node, PaymentForwarded);
20342033
expect_payment_received_event!(client_node, amount_msat);
20352034

@@ -2075,9 +2074,9 @@ async fn do_lsps2_client_service_integration(client_trusts_lsp: bool) {
20752074
.unwrap();
20762075

20772076
expect_event!(service_node, PaymentForwarded);
2078-
expect_payment_successful_event!(payer_node, Some(payment_id), None);
2077+
expect_payment_successful_event!(payer_node, payment_id, None);
20792078
let client_payment_id =
2080-
expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap();
2079+
expect_payment_received_event!(client_node, expected_received_amount_msat);
20812080
let client_payment = client_node.payment(&client_payment_id).unwrap();
20822081
match client_payment.kind {
20832082
PaymentKind::Bolt11 { counterparty_skimmed_fee_msat, .. } => {
@@ -2182,7 +2181,7 @@ async fn spontaneous_send_with_custom_preimage() {
21822181
.unwrap();
21832182

21842183
// check payment status and verify stored preimage
2185-
expect_payment_successful_event!(node_a, Some(payment_id), None);
2184+
expect_payment_successful_event!(node_a, payment_id, None);
21862185
let details: PaymentDetails =
21872186
node_a.list_payments_with_filter(|p| p.id == payment_id).first().unwrap().clone();
21882187
assert_eq!(details.status, PaymentStatus::Succeeded);
@@ -2368,9 +2367,9 @@ async fn lsps2_client_trusts_lsp() {
23682367
.claim_for_hash(manual_payment_hash, jit_amount_msat, manual_preimage)
23692368
.unwrap();
23702369

2371-
expect_payment_successful_event!(payer_node, Some(payment_id), None);
2370+
expect_payment_successful_event!(payer_node, payment_id, None);
23722371

2373-
let _ = expect_payment_received_event!(client_node, expected_received_amount_msat).unwrap();
2372+
let _ = expect_payment_received_event!(client_node, expected_received_amount_msat);
23742373

23752374
// Check the nodes pick up on the confirmed funding tx now.
23762375
wait_for_tx(&electrsd.client, funding_txo.txid).await;

tests/upgrade_downgrade_tests.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ async fn expect_current_payment_successful(
302302
) {
303303
match next_current_event(node).await {
304304
ldk_node::Event::PaymentSuccessful { payment_id, .. } => {
305-
assert_eq!(payment_id.as_ref(), Some(expected_payment_id));
305+
assert_eq!(&payment_id, expected_payment_id);
306306
node.event_handled().unwrap();
307307
},
308308
event => panic!("{} got unexpected event: {:?}", node.node_id(), event),
@@ -311,9 +311,8 @@ async fn expect_current_payment_successful(
311311

312312
async fn expect_current_payment_received(node: &CurrentNode, expected_amount_msat: u64) {
313313
match next_current_event(node).await {
314-
ldk_node::Event::PaymentReceived { amount_msat, payment_id, .. } => {
314+
ldk_node::Event::PaymentReceived { amount_msat, .. } => {
315315
assert_eq!(amount_msat, expected_amount_msat);
316-
assert!(payment_id.is_some());
317316
node.event_handled().unwrap();
318317
},
319318
event => panic!("{} got unexpected event: {:?}", node.node_id(), event),

0 commit comments

Comments
 (0)