Skip to content

Commit f99b95c

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 f99b95c

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
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

+31-17
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;
@@ -813,7 +822,7 @@ impl OutboundPayments {
813822
IH: Fn() -> InFlightHtlcs,
814823
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
815824
{
816-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, None, retry_strategy,
825+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, None, retry_strategy,
817826
route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
818827
best_block_height, logger, pending_events, &send_payment_along_path)
819828
}
@@ -836,7 +845,7 @@ impl OutboundPayments {
836845
let preimage = payment_preimage
837846
.unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
838847
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array());
839-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, Some(preimage),
848+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, Some(preimage),
840849
retry_strategy, route_params, router, first_hops, inflight_htlcs, entropy_source,
841850
node_signer, best_block_height, logger, pending_events, send_payment_along_path)
842851
.map(|()| payment_hash)
@@ -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,8 +979,8 @@ 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
@@ -980,7 +990,7 @@ impl OutboundPayments {
980990
invoice_request
981991
} else { unreachable!() };
982992
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
983-
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), &route,
993+
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), bolt12_invoice.cloned(), &route,
984994
Some(retry_strategy), payment_params, entropy_source, best_block_height
985995
);
986996
outbounds.insert(payment_id, retryable_payment);
@@ -1130,7 +1140,7 @@ impl OutboundPayments {
11301140
};
11311141

11321142
self.send_payment_for_bolt12_invoice_internal(
1133-
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), route_params,
1143+
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), None, route_params,
11341144
retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer,
11351145
node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path
11361146
)
@@ -1254,7 +1264,7 @@ impl OutboundPayments {
12541264
///
12551265
/// [`Event::PaymentPathFailed`]: crate::events::Event::PaymentPathFailed
12561266
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
1257-
fn send_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
1267+
fn send_payment_for_non_bolt12_invoice<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
12581268
&self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
12591269
keysend_preimage: Option<PaymentPreimage>, retry_strategy: Retry, mut route_params: RouteParameters,
12601270
router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
@@ -1276,7 +1286,7 @@ impl OutboundPayments {
12761286

12771287
let onion_session_privs = self.add_new_pending_payment(payment_hash,
12781288
recipient_onion.clone(), payment_id, keysend_preimage, &route, Some(retry_strategy),
1279-
Some(route_params.payment_params.clone()), entropy_source, best_block_height)
1289+
Some(route_params.payment_params.clone()), entropy_source, best_block_height, None)
12801290
.map_err(|_| {
12811291
log_error!(logger, "Payment with id {} is already pending. New payment had payment hash {}",
12821292
payment_id, payment_hash);
@@ -1590,7 +1600,7 @@ impl OutboundPayments {
15901600
let route = Route { paths: vec![path], route_params: None };
15911601
let onion_session_privs = self.add_new_pending_payment(payment_hash,
15921602
RecipientOnionFields::secret_only(payment_secret), payment_id, None, &route, None, None,
1593-
entropy_source, best_block_height
1603+
entropy_source, best_block_height, None
15941604
).map_err(|e| {
15951605
debug_assert!(matches!(e, PaymentSendFailure::DuplicatePayment));
15961606
ProbeSendFailure::DuplicateProbe
@@ -1645,20 +1655,21 @@ impl OutboundPayments {
16451655
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16461656
route: &Route, retry_strategy: Option<Retry>, entropy_source: &ES, best_block_height: u32
16471657
) -> 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)
1658+
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height, None)
16491659
}
16501660

16511661
pub(super) fn add_new_pending_payment<ES: Deref>(
16521662
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16531663
keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
1654-
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
1664+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32,
1665+
bolt12_invoice: Option<Bolt12Invoice>
16551666
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
16561667
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
16571668
match pending_outbounds.entry(payment_id) {
16581669
hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
16591670
hash_map::Entry::Vacant(entry) => {
16601671
let (payment, onion_session_privs) = Self::create_pending_payment(
1661-
payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy,
1672+
payment_hash, recipient_onion, keysend_preimage, None, bolt12_invoice, route, retry_strategy,
16621673
payment_params, entropy_source, best_block_height
16631674
);
16641675
entry.insert(payment);
@@ -1670,8 +1681,8 @@ impl OutboundPayments {
16701681
fn create_pending_payment<ES: Deref>(
16711682
payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
16721683
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
1684+
bolt12_invoice: Option<Bolt12Invoice>, route: &Route, retry_strategy: Option<Retry>,
1685+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
16751686
) -> (PendingOutboundPayment, Vec<[u8; 32]>)
16761687
where
16771688
ES::Target: EntropySource,
@@ -1693,6 +1704,7 @@ impl OutboundPayments {
16931704
payment_metadata: recipient_onion.payment_metadata,
16941705
keysend_preimage,
16951706
invoice_request,
1707+
bolt12_invoice,
16961708
custom_tlvs: recipient_onion.custom_tlvs,
16971709
starting_block_height: best_block_height,
16981710
total_msat: route.get_total_amount(),
@@ -2310,6 +2322,7 @@ impl OutboundPayments {
23102322
payment_metadata: None, // only used for retries, and we'll never retry on startup
23112323
keysend_preimage: None, // only used for retries, and we'll never retry on startup
23122324
invoice_request: None, // only used for retries, and we'll never retry on startup
2325+
bolt12_invoice: None, // only used for retries, and we'll never retry on startup! TODO(vincenzopalazzo): double check this
23132326
custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup
23142327
pending_amt_msat: path_amt,
23152328
pending_fee_msat: Some(path_fee),
@@ -2399,6 +2412,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
23992412
(10, starting_block_height, required),
24002413
(11, remaining_max_total_routing_fee_msat, option),
24012414
(13, invoice_request, option),
2415+
(15, bolt12_invoice, option),
24022416
(not_written, retry_strategy, (static_value, None)),
24032417
(not_written, attempts, (static_value, PaymentAttempts::new())),
24042418
},
@@ -2516,7 +2530,7 @@ mod tests {
25162530
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25172531
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25182532
Some(Retry::Attempts(1)), Some(expired_route_params.payment_params.clone()),
2519-
&&keys_manager, 0).unwrap();
2533+
&&keys_manager, 0, None).unwrap();
25202534
outbound_payments.find_route_and_send_payment(
25212535
PaymentHash([0; 32]), PaymentId([0; 32]), expired_route_params, &&router, vec![],
25222536
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
@@ -2559,7 +2573,7 @@ mod tests {
25592573
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25602574
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25612575
Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()),
2562-
&&keys_manager, 0).unwrap();
2576+
&&keys_manager, 0, None).unwrap();
25632577
outbound_payments.find_route_and_send_payment(
25642578
PaymentHash([0; 32]), PaymentId([0; 32]), route_params, &&router, vec![],
25652579
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,

0 commit comments

Comments
 (0)