Skip to content

Commit 524d7a9

Browse files
add the bolt12 invoice to the PaymentSend event
This commit make two things possible: 1. make persistent BOLT12 invoice through PendingOutboundPayment This commit prepares the code to pass down the BOLT12 invoice inside the `PaymentSent` event. To achieve this, the `bolt12` field has been added to the `PendingOutboundPayment::Retryable` enum, allowing it to be attached to the `PaymentSent` event when the payment is completed. 2. To enable proof of payment, we need to share the bolt12 invoice with the library user. This is already possible if we `manually_handle_bolt12_invoices`, but this approach requires a significant amount of work from the user. This commit adds the bolt12 invoice to the PaymentSend event when the payment is completed. This allows the user to always have the option to perform proof of payment. Link: lightningdevkit#3344 Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent 86e2638 commit 524d7a9

File tree

5 files changed

+118
-51
lines changed

5 files changed

+118
-51
lines changed

lightning/src/events/mod.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -949,6 +949,13 @@ pub enum Event {
949949
///
950950
/// [`Route::get_total_fees`]: crate::routing::router::Route::get_total_fees
951951
fee_paid_msat: Option<u64>,
952+
/// The BOLT 12 invoice that was paid. `None` if the payment was a non BOLT 12 payment.
953+
///
954+
/// The BOLT 12 invoice is useful for proof of payment because it contains the
955+
/// payment hash. A third party can verify that the payment was made by
956+
/// showing the invoice and confirming that the payment hash matches
957+
/// the hash of the payment preimage.
958+
bolt12_invoice: Option<PaidInvoice>,
952959
},
953960
/// Indicates an outbound payment failed. Individual [`Event::PaymentPathFailed`] events
954961
/// provide failure information for each path attempt in the payment, including retries.
@@ -1556,14 +1563,15 @@ impl Writeable for Event {
15561563
(13, payment_id, option),
15571564
});
15581565
},
1559-
&Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat } => {
1566+
&Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat, ref bolt12_invoice } => {
15601567
2u8.write(writer)?;
15611568
write_tlv_fields!(writer, {
15621569
(0, payment_preimage, required),
15631570
(1, payment_hash, required),
15641571
(3, payment_id, option),
15651572
(5, fee_paid_msat, option),
15661573
(7, amount_msat, option),
1574+
(9, bolt12_invoice, option),
15671575
});
15681576
},
15691577
&Event::PaymentPathFailed {
@@ -1898,12 +1906,14 @@ impl MaybeReadable for Event {
18981906
let mut payment_id = None;
18991907
let mut amount_msat = None;
19001908
let mut fee_paid_msat = None;
1909+
let mut bolt12_invoice = None;
19011910
read_tlv_fields!(reader, {
19021911
(0, payment_preimage, required),
19031912
(1, payment_hash, option),
19041913
(3, payment_id, option),
19051914
(5, fee_paid_msat, option),
19061915
(7, amount_msat, option),
1916+
(9, bolt12_invoice, option),
19071917
});
19081918
if payment_hash.is_none() {
19091919
payment_hash = Some(PaymentHash(Sha256::hash(&payment_preimage.0[..]).to_byte_array()));
@@ -1914,6 +1924,7 @@ impl MaybeReadable for Event {
19141924
payment_hash: payment_hash.unwrap(),
19151925
amount_msat,
19161926
fee_paid_msat,
1927+
bolt12_invoice,
19171928
}))
19181929
};
19191930
f()
@@ -2438,3 +2449,18 @@ impl<T: EventHandler> EventHandler for Arc<T> {
24382449
self.deref().handle_event(event)
24392450
}
24402451
}
2452+
2453+
/// Wrapper time to move the bolt12 invoice and the static
2454+
/// invoice across the same event as a unique type.
2455+
#[derive(Clone, Debug, PartialEq, Eq)]
2456+
pub enum PaidInvoice {
2457+
/// Bolt12 invoice
2458+
Bolt12Invoice(crate::offers::invoice::Bolt12Invoice),
2459+
/// Static invoice
2460+
StaticInvoice(crate::offers::static_invoice::StaticInvoice),
2461+
}
2462+
2463+
impl_writeable_tlv_based_enum!(PaidInvoice,
2464+
{0, Bolt12Invoice} => (),
2465+
{2, StaticInvoice} => (),
2466+
);

lightning/src/ln/functional_test_utils.rs

+17-10
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Confirm, Listen, Watch, chainmonitor::Persist};
1414
use crate::chain::channelmonitor::ChannelMonitor;
1515
use crate::chain::transaction::OutPoint;
16-
use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, PathFailure, PaymentPurpose, PaymentFailureReason};
16+
use crate::events::{ClaimedHTLC, ClosureReason, Event, HTLCDestination, PaidInvoice, PathFailure, PaymentFailureReason, PaymentPurpose};
1717
use crate::events::bump_transaction::{BumpTransactionEvent, BumpTransactionEventHandler, Wallet, WalletSource};
1818
use crate::ln::types::ChannelId;
1919
use crate::types::payment::{PaymentPreimage, PaymentHash, PaymentSecret};
@@ -2294,7 +2294,7 @@ macro_rules! expect_payment_claimed {
22942294
pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
22952295
expected_payment_preimage: PaymentPreimage, expected_fee_msat_opt: Option<Option<u64>>,
22962296
expect_per_path_claims: bool, expect_post_ev_mon_update: bool,
2297-
) {
2297+
) -> Option<PaidInvoice> {
22982298
let events = node.node().get_and_clear_pending_events();
22992299
let expected_payment_hash = PaymentHash(
23002300
bitcoin::hashes::sha256::Hash::hash(&expected_payment_preimage.0).to_byte_array());
@@ -2306,8 +2306,11 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
23062306
if expect_post_ev_mon_update {
23072307
check_added_monitors(node, 1);
23082308
}
2309+
// We return the invoice because some test may want to check the invoice details.
2310+
#[allow(unused_assignments)]
2311+
let mut invoice = None;
23092312
let expected_payment_id = match events[0] {
2310-
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat } => {
2313+
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat, ref bolt12_invoice } => {
23112314
assert_eq!(expected_payment_preimage, *payment_preimage);
23122315
assert_eq!(expected_payment_hash, *payment_hash);
23132316
assert!(amount_msat.is_some());
@@ -2316,6 +2319,7 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
23162319
} else {
23172320
assert!(fee_paid_msat.is_some());
23182321
}
2322+
invoice = bolt12_invoice.clone();
23192323
payment_id.unwrap()
23202324
},
23212325
_ => panic!("Unexpected event"),
@@ -2331,19 +2335,20 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
23312335
}
23322336
}
23332337
}
2338+
invoice
23342339
}
23352340

23362341
#[macro_export]
23372342
macro_rules! expect_payment_sent {
23382343
($node: expr, $expected_payment_preimage: expr) => {
2339-
$crate::expect_payment_sent!($node, $expected_payment_preimage, None::<u64>, true);
2344+
$crate::expect_payment_sent!($node, $expected_payment_preimage, None::<u64>, true)
23402345
};
23412346
($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr) => {
2342-
$crate::expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, true);
2347+
$crate::expect_payment_sent!($node, $expected_payment_preimage, $expected_fee_msat_opt, true)
23432348
};
23442349
($node: expr, $expected_payment_preimage: expr, $expected_fee_msat_opt: expr, $expect_paths: expr) => {
23452350
$crate::ln::functional_test_utils::expect_payment_sent(&$node, $expected_payment_preimage,
2346-
$expected_fee_msat_opt.map(|o| Some(o)), $expect_paths, true);
2351+
$expected_fee_msat_opt.map(|o| Some(o)), $expect_paths, true)
23472352
}
23482353
}
23492354

@@ -3106,20 +3111,22 @@ pub fn pass_claimed_payment_along_route(args: ClaimAlongRouteArgs) -> u64 {
31063111

31073112
expected_total_fee_msat
31083113
}
3109-
pub fn claim_payment_along_route(args: ClaimAlongRouteArgs) {
3114+
pub fn claim_payment_along_route(args: ClaimAlongRouteArgs) -> Option<PaidInvoice> {
31103115
let origin_node = args.origin_node;
31113116
let payment_preimage = args.payment_preimage;
31123117
let skip_last = args.skip_last;
31133118
let expected_total_fee_msat = do_claim_payment_along_route(args);
31143119
if !skip_last {
3115-
expect_payment_sent!(origin_node, payment_preimage, Some(expected_total_fee_msat));
3120+
expect_payment_sent!(origin_node, payment_preimage, Some(expected_total_fee_msat))
3121+
} else {
3122+
None
31163123
}
31173124
}
31183125

3119-
pub fn claim_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], our_payment_preimage: PaymentPreimage) {
3126+
pub fn claim_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_route: &[&Node<'a, 'b, 'c>], our_payment_preimage: PaymentPreimage) -> Option<PaidInvoice> {
31203127
claim_payment_along_route(
31213128
ClaimAlongRouteArgs::new(origin_node, &[expected_route], our_payment_preimage)
3122-
);
3129+
)
31233130
}
31243131

31253132
pub const TEST_FINAL_CLTV: u32 = 70;

lightning/src/ln/offers_tests.rs

+17-13
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use crate::blinded_path::IntroductionNode;
4747
use crate::blinded_path::message::BlindedMessagePath;
4848
use crate::blinded_path::payment::{Bolt12OfferContext, Bolt12RefundContext, PaymentContext};
4949
use crate::blinded_path::message::{MessageContext, OffersContext};
50-
use crate::events::{ClosureReason, Event, HTLCDestination, PaymentFailureReason, PaymentPurpose};
50+
use crate::events::{ClosureReason, Event, HTLCDestination, PaidInvoice, PaymentFailureReason, PaymentPurpose};
5151
use crate::ln::channelmanager::{Bolt12PaymentError, MAX_SHORT_LIVED_RELATIVE_EXPIRY, PaymentId, RecentPaymentDetails, RecipientOnionFields, Retry, self};
5252
use crate::types::features::Bolt12InvoiceFeatures;
5353
use crate::ln::functional_test_utils::*;
@@ -168,7 +168,7 @@ fn route_bolt12_payment<'a, 'b, 'c>(
168168
}
169169

170170
fn claim_bolt12_payment<'a, 'b, 'c>(
171-
node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], expected_payment_context: PaymentContext
171+
node: &Node<'a, 'b, 'c>, path: &[&Node<'a, 'b, 'c>], expected_payment_context: PaymentContext, invoice: &Bolt12Invoice
172172
) {
173173
let recipient = &path[path.len() - 1];
174174
let payment_purpose = match get_event!(recipient, Event::PaymentClaimable) {
@@ -188,7 +188,11 @@ fn claim_bolt12_payment<'a, 'b, 'c>(
188188
},
189189
_ => panic!("Unexpected payment purpose: {:?}", payment_purpose),
190190
}
191-
claim_payment(node, path, payment_preimage);
191+
if let Some(inv) = claim_payment(node, path, payment_preimage) {
192+
assert_eq!(inv, PaidInvoice::Bolt12Invoice(invoice.to_owned()));
193+
} else {
194+
panic!("Expected PaidInvoice::Bolt12Invoice");
195+
};
192196
}
193197

194198
fn extract_offer_nonce<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, message: &OnionMessage) -> Nonce {
@@ -597,7 +601,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() {
597601
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
598602
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
599603

600-
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context);
604+
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context, &invoice);
601605
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
602606
}
603607

@@ -680,7 +684,7 @@ fn creates_and_pays_for_refund_using_two_hop_blinded_path() {
680684
route_bolt12_payment(david, &[charlie, bob, alice], &invoice);
681685
expect_recent_payment!(david, RecentPaymentDetails::Pending, payment_id);
682686

683-
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context);
687+
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context, &invoice);
684688
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
685689
}
686690

@@ -747,7 +751,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
747751
route_bolt12_payment(bob, &[alice], &invoice);
748752
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
749753

750-
claim_bolt12_payment(bob, &[alice], payment_context);
754+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
751755
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
752756
}
753757

@@ -803,7 +807,7 @@ fn creates_and_pays_for_refund_using_one_hop_blinded_path() {
803807
route_bolt12_payment(bob, &[alice], &invoice);
804808
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
805809

806-
claim_bolt12_payment(bob, &[alice], payment_context);
810+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
807811
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
808812
}
809813

@@ -857,7 +861,7 @@ fn pays_for_offer_without_blinded_paths() {
857861
route_bolt12_payment(bob, &[alice], &invoice);
858862
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
859863

860-
claim_bolt12_payment(bob, &[alice], payment_context);
864+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
861865
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
862866
}
863867

@@ -900,7 +904,7 @@ fn pays_for_refund_without_blinded_paths() {
900904
route_bolt12_payment(bob, &[alice], &invoice);
901905
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
902906

903-
claim_bolt12_payment(bob, &[alice], payment_context);
907+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
904908
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
905909
}
906910

@@ -1138,7 +1142,7 @@ fn creates_and_pays_for_offer_with_retry() {
11381142
}
11391143
route_bolt12_payment(bob, &[alice], &invoice);
11401144
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
1141-
claim_bolt12_payment(bob, &[alice], payment_context);
1145+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
11421146
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
11431147
}
11441148

@@ -1209,7 +1213,7 @@ fn pays_bolt12_invoice_asynchronously() {
12091213
route_bolt12_payment(bob, &[alice], &invoice);
12101214
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
12111215

1212-
claim_bolt12_payment(bob, &[alice], payment_context);
1216+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
12131217
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
12141218

12151219
assert_eq!(
@@ -1289,7 +1293,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
12891293
route_bolt12_payment(bob, &[alice], &invoice);
12901294
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
12911295

1292-
claim_bolt12_payment(bob, &[alice], payment_context);
1296+
claim_bolt12_payment(bob, &[alice], payment_context, &invoice);
12931297
expect_recent_payment!(bob, RecentPaymentDetails::Fulfilled, payment_id);
12941298
}
12951299

@@ -2145,7 +2149,7 @@ fn fails_paying_invoice_more_than_once() {
21452149
assert!(david.node.get_and_clear_pending_msg_events().is_empty());
21462150

21472151
// Complete paying the first invoice
2148-
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context);
2152+
claim_bolt12_payment(david, &[charlie, bob, alice], payment_context, &invoice1);
21492153
expect_recent_payment!(david, RecentPaymentDetails::Fulfilled, payment_id);
21502154
}
21512155

0 commit comments

Comments
 (0)