Skip to content

Commit 8fc57c2

Browse files
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. Link: lightningdevkit#3344 Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent bce5db7 commit 8fc57c2

File tree

2 files changed

+31
-15
lines changed

2 files changed

+31
-15
lines changed

lightning/src/ln/functional_test_utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2305,7 +2305,7 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
23052305
check_added_monitors(node, 1);
23062306
}
23072307
let expected_payment_id = match events[0] {
2308-
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat } => {
2308+
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat, .. } => {
23092309
assert_eq!(expected_payment_preimage, *payment_preimage);
23102310
assert_eq!(expected_payment_hash, *payment_hash);
23112311
assert!(amount_msat.is_some());

lightning/src/ln/outbound_payment.rs

+30-14
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,9 @@ pub(crate) enum PendingOutboundPayment {
104104
payment_metadata: Option<Vec<u8>>,
105105
keysend_preimage: Option<PaymentPreimage>,
106106
invoice_request: Option<InvoiceRequest>,
107+
// Storing the bolt12 invoice here to allow Proof of Payment after
108+
// the payment is made.
109+
bolt12_invoice: Option<Bolt12Invoice>,
107110
custom_tlvs: Vec<(u64, Vec<u8>)>,
108111
pending_amt_msat: u64,
109112
/// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+.
@@ -153,6 +156,12 @@ impl_writeable_tlv_based!(RetryableInvoiceRequest, {
153156
});
154157

155158
impl PendingOutboundPayment {
159+
fn bolt12_invoice(&self) -> Option<&Bolt12Invoice> {
160+
match self {
161+
PendingOutboundPayment::Retryable { bolt12_invoice, .. } => bolt12_invoice.as_ref(),
162+
_ => None,
163+
}
164+
}
156165
fn increment_attempts(&mut self) {
157166
if let PendingOutboundPayment::Retryable { attempts, .. } = self {
158167
attempts.count += 1;
@@ -896,7 +905,7 @@ impl OutboundPayments {
896905
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
897906
}
898907
self.send_payment_for_bolt12_invoice_internal(
899-
payment_id, payment_hash, None, None, route_params, retry_strategy, router, first_hops,
908+
payment_id, payment_hash, None, None, Some(invoice), route_params, retry_strategy, router, first_hops,
900909
inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height,
901910
logger, pending_events, send_payment_along_path
902911
)
@@ -907,6 +916,7 @@ impl OutboundPayments {
907916
>(
908917
&self, payment_id: PaymentId, payment_hash: PaymentHash,
909918
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
919+
bolt12_invoice: Option<&Bolt12Invoice>,
910920
mut route_params: RouteParameters, retry_strategy: Retry, router: &R,
911921
first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
912922
node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
@@ -969,18 +979,20 @@ impl OutboundPayments {
969979
hash_map::Entry::Occupied(entry) => match entry.get() {
970980
PendingOutboundPayment::InvoiceReceived { .. } => {
971981
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
972-
payment_hash, recipient_onion.clone(), keysend_preimage, None, &route,
973-
Some(retry_strategy), payment_params, entropy_source, best_block_height
982+
payment_hash, recipient_onion.clone(), keysend_preimage, None, bolt12_invoice.cloned(), &route,
983+
Some(retry_strategy), payment_params, entropy_source, best_block_height,
974984
);
975985
*entry.into_mut() = retryable_payment;
976986
onion_session_privs
977987
},
988+
// TODO(vincenzopalazzo): What about static invoices? There is no proof of payment with async payment because we need PTLC
989+
// so we can ingore it for now
978990
PendingOutboundPayment::StaticInvoiceReceived { .. } => {
979991
let invreq = if let PendingOutboundPayment::StaticInvoiceReceived { invoice_request, .. } = entry.remove() {
980992
invoice_request
981993
} else { unreachable!() };
982994
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
983-
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), &route,
995+
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), None, &route,
984996
Some(retry_strategy), payment_params, entropy_source, best_block_height
985997
);
986998
outbounds.insert(payment_id, retryable_payment);
@@ -1130,7 +1142,7 @@ impl OutboundPayments {
11301142
};
11311143

11321144
self.send_payment_for_bolt12_invoice_internal(
1133-
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), route_params,
1145+
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), None, route_params,
11341146
retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer,
11351147
node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path
11361148
)
@@ -1276,7 +1288,7 @@ impl OutboundPayments {
12761288

12771289
let onion_session_privs = self.add_new_pending_payment(payment_hash,
12781290
recipient_onion.clone(), payment_id, keysend_preimage, &route, Some(retry_strategy),
1279-
Some(route_params.payment_params.clone()), entropy_source, best_block_height)
1291+
Some(route_params.payment_params.clone()), entropy_source, best_block_height, None)
12801292
.map_err(|_| {
12811293
log_error!(logger, "Payment with id {} is already pending. New payment had payment hash {}",
12821294
payment_id, payment_hash);
@@ -1590,7 +1602,7 @@ impl OutboundPayments {
15901602
let route = Route { paths: vec![path], route_params: None };
15911603
let onion_session_privs = self.add_new_pending_payment(payment_hash,
15921604
RecipientOnionFields::secret_only(payment_secret), payment_id, None, &route, None, None,
1593-
entropy_source, best_block_height
1605+
entropy_source, best_block_height, None
15941606
).map_err(|e| {
15951607
debug_assert!(matches!(e, PaymentSendFailure::DuplicatePayment));
15961608
ProbeSendFailure::DuplicateProbe
@@ -1645,20 +1657,21 @@ impl OutboundPayments {
16451657
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16461658
route: &Route, retry_strategy: Option<Retry>, entropy_source: &ES, best_block_height: u32
16471659
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
1648-
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height)
1660+
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height, None)
16491661
}
16501662

16511663
pub(super) fn add_new_pending_payment<ES: Deref>(
16521664
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16531665
keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
1654-
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
1666+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32,
1667+
bolt12_invoice: Option<Bolt12Invoice>
16551668
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
16561669
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
16571670
match pending_outbounds.entry(payment_id) {
16581671
hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
16591672
hash_map::Entry::Vacant(entry) => {
16601673
let (payment, onion_session_privs) = Self::create_pending_payment(
1661-
payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy,
1674+
payment_hash, recipient_onion, keysend_preimage, None, bolt12_invoice, route, retry_strategy,
16621675
payment_params, entropy_source, best_block_height
16631676
);
16641677
entry.insert(payment);
@@ -1670,8 +1683,8 @@ impl OutboundPayments {
16701683
fn create_pending_payment<ES: Deref>(
16711684
payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
16721685
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<InvoiceRequest>,
1673-
route: &Route, retry_strategy: Option<Retry>, payment_params: Option<PaymentParameters>,
1674-
entropy_source: &ES, best_block_height: u32
1686+
bolt12_invoice: Option<Bolt12Invoice>, route: &Route, retry_strategy: Option<Retry>,
1687+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
16751688
) -> (PendingOutboundPayment, Vec<[u8; 32]>)
16761689
where
16771690
ES::Target: EntropySource,
@@ -1693,6 +1706,7 @@ impl OutboundPayments {
16931706
payment_metadata: recipient_onion.payment_metadata,
16941707
keysend_preimage,
16951708
invoice_request,
1709+
bolt12_invoice,
16961710
custom_tlvs: recipient_onion.custom_tlvs,
16971711
starting_block_height: best_block_height,
16981712
total_msat: route.get_total_amount(),
@@ -2310,6 +2324,7 @@ impl OutboundPayments {
23102324
payment_metadata: None, // only used for retries, and we'll never retry on startup
23112325
keysend_preimage: None, // only used for retries, and we'll never retry on startup
23122326
invoice_request: None, // only used for retries, and we'll never retry on startup
2327+
bolt12_invoice: None, // only used for retries, and we'll never retry on startup! TODO(vincenzopalazzo): double check this
23132328
custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup
23142329
pending_amt_msat: path_amt,
23152330
pending_fee_msat: Some(path_fee),
@@ -2399,6 +2414,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
23992414
(10, starting_block_height, required),
24002415
(11, remaining_max_total_routing_fee_msat, option),
24012416
(13, invoice_request, option),
2417+
(15, bolt12_invoice, option),
24022418
(not_written, retry_strategy, (static_value, None)),
24032419
(not_written, attempts, (static_value, PaymentAttempts::new())),
24042420
},
@@ -2516,7 +2532,7 @@ mod tests {
25162532
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25172533
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25182534
Some(Retry::Attempts(1)), Some(expired_route_params.payment_params.clone()),
2519-
&&keys_manager, 0).unwrap();
2535+
&&keys_manager, 0, None).unwrap();
25202536
outbound_payments.find_route_and_send_payment(
25212537
PaymentHash([0; 32]), PaymentId([0; 32]), expired_route_params, &&router, vec![],
25222538
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
@@ -2559,7 +2575,7 @@ mod tests {
25592575
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25602576
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25612577
Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()),
2562-
&&keys_manager, 0).unwrap();
2578+
&&keys_manager, 0, None).unwrap();
25632579
outbound_payments.find_route_and_send_payment(
25642580
PaymentHash([0; 32]), PaymentId([0; 32]), route_params, &&router, vec![],
25652581
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,

0 commit comments

Comments
 (0)