Skip to content

Commit 85d807b

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 05e82c8 commit 85d807b

File tree

2 files changed

+33
-19
lines changed

2 files changed

+33
-19
lines changed

Diff for: lightning/src/ln/functional_test_utils.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2307,7 +2307,7 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
23072307
check_added_monitors(node, 1);
23082308
}
23092309
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 } => {
2310+
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref amount_msat, ref fee_paid_msat, .. } => {
23112311
assert_eq!(expected_payment_preimage, *payment_preimage);
23122312
assert_eq!(expected_payment_hash, *payment_hash);
23132313
assert!(amount_msat.is_some());

Diff for: lightning/src/ln/outbound_payment.rs

+32-18
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ pub(crate) enum PendingOutboundPayment {
106106
payment_metadata: Option<Vec<u8>>,
107107
keysend_preimage: Option<PaymentPreimage>,
108108
invoice_request: Option<InvoiceRequest>,
109+
// Storing the bolt12 invoice here to allow Proof of Payment after
110+
// the payment is made.
111+
bolt12_invoice: Option<Bolt12Invoice>,
109112
custom_tlvs: Vec<(u64, Vec<u8>)>,
110113
pending_amt_msat: u64,
111114
/// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+.
@@ -155,6 +158,12 @@ impl_writeable_tlv_based!(RetryableInvoiceRequest, {
155158
});
156159

157160
impl PendingOutboundPayment {
161+
fn bolt12_invoice(&self) -> Option<&Bolt12Invoice> {
162+
match self {
163+
PendingOutboundPayment::Retryable { bolt12_invoice, .. } => bolt12_invoice.as_ref(),
164+
_ => None,
165+
}
166+
}
158167
fn increment_attempts(&mut self) {
159168
if let PendingOutboundPayment::Retryable { attempts, .. } = self {
160169
attempts.count += 1;
@@ -831,7 +840,7 @@ impl OutboundPayments {
831840
IH: Fn() -> InFlightHtlcs,
832841
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
833842
{
834-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, None, retry_strategy,
843+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, None, retry_strategy,
835844
route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
836845
best_block_height, logger, pending_events, &send_payment_along_path)
837846
}
@@ -854,7 +863,7 @@ impl OutboundPayments {
854863
let preimage = payment_preimage
855864
.unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
856865
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array());
857-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, Some(preimage),
866+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, Some(preimage),
858867
retry_strategy, route_params, router, first_hops, inflight_htlcs, entropy_source,
859868
node_signer, best_block_height, logger, pending_events, send_payment_along_path)
860869
.map(|()| payment_hash)
@@ -897,7 +906,7 @@ impl OutboundPayments {
897906
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
898907
}
899908

900-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, None, retry_strategy, route_params,
909+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, None, retry_strategy, route_params,
901910
router, first_hops, compute_inflight_htlcs,
902911
entropy_source, node_signer, best_block_height, logger,
903912
pending_events, send_payment_along_path
@@ -959,7 +968,7 @@ impl OutboundPayments {
959968
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
960969
}
961970
self.send_payment_for_bolt12_invoice_internal(
962-
payment_id, payment_hash, None, None, route_params, retry_strategy, router, first_hops,
971+
payment_id, payment_hash, None, None, Some(invoice), route_params, retry_strategy, router, first_hops,
963972
inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height,
964973
logger, pending_events, send_payment_along_path
965974
)
@@ -970,6 +979,7 @@ impl OutboundPayments {
970979
>(
971980
&self, payment_id: PaymentId, payment_hash: PaymentHash,
972981
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
982+
bolt12_invoice: Option<&Bolt12Invoice>,
973983
mut route_params: RouteParameters, retry_strategy: Retry, router: &R,
974984
first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
975985
node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
@@ -1032,8 +1042,8 @@ impl OutboundPayments {
10321042
hash_map::Entry::Occupied(entry) => match entry.get() {
10331043
PendingOutboundPayment::InvoiceReceived { .. } => {
10341044
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
1035-
payment_hash, recipient_onion.clone(), keysend_preimage, None, &route,
1036-
Some(retry_strategy), payment_params, entropy_source, best_block_height
1045+
payment_hash, recipient_onion.clone(), keysend_preimage, None, bolt12_invoice.cloned(), &route,
1046+
Some(retry_strategy), payment_params, entropy_source, best_block_height,
10371047
);
10381048
*entry.into_mut() = retryable_payment;
10391049
onion_session_privs
@@ -1043,7 +1053,7 @@ impl OutboundPayments {
10431053
invoice_request
10441054
} else { unreachable!() };
10451055
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
1046-
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), &route,
1056+
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), bolt12_invoice.cloned(), &route,
10471057
Some(retry_strategy), payment_params, entropy_source, best_block_height
10481058
);
10491059
outbounds.insert(payment_id, retryable_payment);
@@ -1194,7 +1204,7 @@ impl OutboundPayments {
11941204
};
11951205

11961206
self.send_payment_for_bolt12_invoice_internal(
1197-
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), route_params,
1207+
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), None, route_params,
11981208
retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer,
11991209
node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path
12001210
)
@@ -1318,7 +1328,7 @@ impl OutboundPayments {
13181328
///
13191329
/// [`Event::PaymentPathFailed`]: crate::events::Event::PaymentPathFailed
13201330
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
1321-
fn send_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
1331+
fn send_payment_for_non_bolt12_invoice<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
13221332
&self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
13231333
keysend_preimage: Option<PaymentPreimage>, retry_strategy: Retry, mut route_params: RouteParameters,
13241334
router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
@@ -1340,7 +1350,7 @@ impl OutboundPayments {
13401350

13411351
let onion_session_privs = self.add_new_pending_payment(payment_hash,
13421352
recipient_onion.clone(), payment_id, keysend_preimage, &route, Some(retry_strategy),
1343-
Some(route_params.payment_params.clone()), entropy_source, best_block_height)
1353+
Some(route_params.payment_params.clone()), entropy_source, best_block_height, None)
13441354
.map_err(|_| {
13451355
log_error!(logger, "Payment with id {} is already pending. New payment had payment hash {}",
13461356
payment_id, payment_hash);
@@ -1654,7 +1664,7 @@ impl OutboundPayments {
16541664
let route = Route { paths: vec![path], route_params: None };
16551665
let onion_session_privs = self.add_new_pending_payment(payment_hash,
16561666
RecipientOnionFields::secret_only(payment_secret), payment_id, None, &route, None, None,
1657-
entropy_source, best_block_height
1667+
entropy_source, best_block_height, None
16581668
).map_err(|e| {
16591669
debug_assert!(matches!(e, PaymentSendFailure::DuplicatePayment));
16601670
ProbeSendFailure::DuplicateProbe
@@ -1709,20 +1719,21 @@ impl OutboundPayments {
17091719
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
17101720
route: &Route, retry_strategy: Option<Retry>, entropy_source: &ES, best_block_height: u32
17111721
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
1712-
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height)
1722+
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height, None)
17131723
}
17141724

17151725
pub(super) fn add_new_pending_payment<ES: Deref>(
17161726
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
17171727
keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
1718-
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
1728+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32,
1729+
bolt12_invoice: Option<Bolt12Invoice>
17191730
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
17201731
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
17211732
match pending_outbounds.entry(payment_id) {
17221733
hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
17231734
hash_map::Entry::Vacant(entry) => {
17241735
let (payment, onion_session_privs) = Self::create_pending_payment(
1725-
payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy,
1736+
payment_hash, recipient_onion, keysend_preimage, None, bolt12_invoice, route, retry_strategy,
17261737
payment_params, entropy_source, best_block_height
17271738
);
17281739
entry.insert(payment);
@@ -1734,8 +1745,8 @@ impl OutboundPayments {
17341745
fn create_pending_payment<ES: Deref>(
17351746
payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
17361747
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<InvoiceRequest>,
1737-
route: &Route, retry_strategy: Option<Retry>, payment_params: Option<PaymentParameters>,
1738-
entropy_source: &ES, best_block_height: u32
1748+
bolt12_invoice: Option<Bolt12Invoice>, route: &Route, retry_strategy: Option<Retry>,
1749+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
17391750
) -> (PendingOutboundPayment, Vec<[u8; 32]>)
17401751
where
17411752
ES::Target: EntropySource,
@@ -1757,6 +1768,7 @@ impl OutboundPayments {
17571768
payment_metadata: recipient_onion.payment_metadata,
17581769
keysend_preimage,
17591770
invoice_request,
1771+
bolt12_invoice,
17601772
custom_tlvs: recipient_onion.custom_tlvs,
17611773
starting_block_height: best_block_height,
17621774
total_msat: route.get_total_amount(),
@@ -2374,6 +2386,7 @@ impl OutboundPayments {
23742386
payment_metadata: None, // only used for retries, and we'll never retry on startup
23752387
keysend_preimage: None, // only used for retries, and we'll never retry on startup
23762388
invoice_request: None, // only used for retries, and we'll never retry on startup
2389+
bolt12_invoice: None, // only used for retries, and we'll never retry on startup! TODO(vincenzopalazzo): double check this
23772390
custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup
23782391
pending_amt_msat: path_amt,
23792392
pending_fee_msat: Some(path_fee),
@@ -2463,6 +2476,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
24632476
(10, starting_block_height, required),
24642477
(11, remaining_max_total_routing_fee_msat, option),
24652478
(13, invoice_request, option),
2479+
(15, bolt12_invoice, option),
24662480
(not_written, retry_strategy, (static_value, None)),
24672481
(not_written, attempts, (static_value, PaymentAttempts::new())),
24682482
},
@@ -2613,7 +2627,7 @@ mod tests {
26132627
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
26142628
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
26152629
Some(Retry::Attempts(1)), Some(expired_route_params.payment_params.clone()),
2616-
&&keys_manager, 0).unwrap();
2630+
&&keys_manager, 0, None).unwrap();
26172631
outbound_payments.find_route_and_send_payment(
26182632
PaymentHash([0; 32]), PaymentId([0; 32]), expired_route_params, &&router, vec![],
26192633
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
@@ -2656,7 +2670,7 @@ mod tests {
26562670
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
26572671
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
26582672
Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()),
2659-
&&keys_manager, 0).unwrap();
2673+
&&keys_manager, 0, None).unwrap();
26602674
outbound_payments.find_route_and_send_payment(
26612675
PaymentHash([0; 32]), PaymentId([0; 32]), route_params, &&router, vec![],
26622676
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,

0 commit comments

Comments
 (0)