Skip to content

Commit aa20cfc

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 5786674 commit aa20cfc

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
@@ -105,6 +105,9 @@ pub(crate) enum PendingOutboundPayment {
105105
payment_metadata: Option<Vec<u8>>,
106106
keysend_preimage: Option<PaymentPreimage>,
107107
invoice_request: Option<InvoiceRequest>,
108+
// Storing the bolt12 invoice here to allow Proof of Payment after
109+
// the payment is made.
110+
bolt12_invoice: Option<Bolt12Invoice>,
108111
custom_tlvs: Vec<(u64, Vec<u8>)>,
109112
pending_amt_msat: u64,
110113
/// Used to track the fee paid. Present iff the payment was serialized on 0.0.103+.
@@ -154,6 +157,12 @@ impl_writeable_tlv_based!(RetryableInvoiceRequest, {
154157
});
155158

156159
impl PendingOutboundPayment {
160+
fn bolt12_invoice(&self) -> Option<&Bolt12Invoice> {
161+
match self {
162+
PendingOutboundPayment::Retryable { bolt12_invoice, .. } => bolt12_invoice.as_ref(),
163+
_ => None,
164+
}
165+
}
157166
fn increment_attempts(&mut self) {
158167
if let PendingOutboundPayment::Retryable { attempts, .. } = self {
159168
attempts.count += 1;
@@ -814,7 +823,7 @@ impl OutboundPayments {
814823
IH: Fn() -> InFlightHtlcs,
815824
SP: Fn(SendAlongPathArgs) -> Result<(), APIError>,
816825
{
817-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, None, retry_strategy,
826+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, None, retry_strategy,
818827
route_params, router, first_hops, &compute_inflight_htlcs, entropy_source, node_signer,
819828
best_block_height, logger, pending_events, &send_payment_along_path)
820829
}
@@ -837,7 +846,7 @@ impl OutboundPayments {
837846
let preimage = payment_preimage
838847
.unwrap_or_else(|| PaymentPreimage(entropy_source.get_secure_random_bytes()));
839848
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).to_byte_array());
840-
self.send_payment_internal(payment_id, payment_hash, recipient_onion, Some(preimage),
849+
self.send_payment_for_non_bolt12_invoice(payment_id, payment_hash, recipient_onion, Some(preimage),
841850
retry_strategy, route_params, router, first_hops, inflight_htlcs, entropy_source,
842851
node_signer, best_block_height, logger, pending_events, send_payment_along_path)
843852
.map(|()| payment_hash)
@@ -898,7 +907,7 @@ impl OutboundPayments {
898907
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
899908
}
900909
self.send_payment_for_bolt12_invoice_internal(
901-
payment_id, payment_hash, None, None, route_params, retry_strategy, router, first_hops,
910+
payment_id, payment_hash, None, None, Some(invoice), route_params, retry_strategy, router, first_hops,
902911
inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height,
903912
logger, pending_events, send_payment_along_path
904913
)
@@ -909,6 +918,7 @@ impl OutboundPayments {
909918
>(
910919
&self, payment_id: PaymentId, payment_hash: PaymentHash,
911920
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
921+
bolt12_invoice: Option<&Bolt12Invoice>,
912922
mut route_params: RouteParameters, retry_strategy: Retry, router: &R,
913923
first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
914924
node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
@@ -971,8 +981,8 @@ impl OutboundPayments {
971981
hash_map::Entry::Occupied(entry) => match entry.get() {
972982
PendingOutboundPayment::InvoiceReceived { .. } => {
973983
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
974-
payment_hash, recipient_onion.clone(), keysend_preimage, None, &route,
975-
Some(retry_strategy), payment_params, entropy_source, best_block_height
984+
payment_hash, recipient_onion.clone(), keysend_preimage, None, bolt12_invoice.cloned(), &route,
985+
Some(retry_strategy), payment_params, entropy_source, best_block_height,
976986
);
977987
*entry.into_mut() = retryable_payment;
978988
onion_session_privs
@@ -982,7 +992,7 @@ impl OutboundPayments {
982992
invoice_request
983993
} else { unreachable!() };
984994
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
985-
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), &route,
995+
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), bolt12_invoice.cloned(), &route,
986996
Some(retry_strategy), payment_params, entropy_source, best_block_height
987997
);
988998
outbounds.insert(payment_id, retryable_payment);
@@ -1133,7 +1143,7 @@ impl OutboundPayments {
11331143
};
11341144

11351145
self.send_payment_for_bolt12_invoice_internal(
1136-
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), route_params,
1146+
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), None, route_params,
11371147
retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer,
11381148
node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path
11391149
)
@@ -1257,7 +1267,7 @@ impl OutboundPayments {
12571267
///
12581268
/// [`Event::PaymentPathFailed`]: crate::events::Event::PaymentPathFailed
12591269
/// [`Event::PaymentFailed`]: crate::events::Event::PaymentFailed
1260-
fn send_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
1270+
fn send_payment_for_non_bolt12_invoice<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
12611271
&self, payment_id: PaymentId, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
12621272
keysend_preimage: Option<PaymentPreimage>, retry_strategy: Retry, mut route_params: RouteParameters,
12631273
router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES,
@@ -1279,7 +1289,7 @@ impl OutboundPayments {
12791289

12801290
let onion_session_privs = self.add_new_pending_payment(payment_hash,
12811291
recipient_onion.clone(), payment_id, keysend_preimage, &route, Some(retry_strategy),
1282-
Some(route_params.payment_params.clone()), entropy_source, best_block_height)
1292+
Some(route_params.payment_params.clone()), entropy_source, best_block_height, None)
12831293
.map_err(|_| {
12841294
log_error!(logger, "Payment with id {} is already pending. New payment had payment hash {}",
12851295
payment_id, payment_hash);
@@ -1593,7 +1603,7 @@ impl OutboundPayments {
15931603
let route = Route { paths: vec![path], route_params: None };
15941604
let onion_session_privs = self.add_new_pending_payment(payment_hash,
15951605
RecipientOnionFields::secret_only(payment_secret), payment_id, None, &route, None, None,
1596-
entropy_source, best_block_height
1606+
entropy_source, best_block_height, None
15971607
).map_err(|e| {
15981608
debug_assert!(matches!(e, PaymentSendFailure::DuplicatePayment));
15991609
ProbeSendFailure::DuplicateProbe
@@ -1648,20 +1658,21 @@ impl OutboundPayments {
16481658
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16491659
route: &Route, retry_strategy: Option<Retry>, entropy_source: &ES, best_block_height: u32
16501660
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
1651-
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height)
1661+
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height, None)
16521662
}
16531663

16541664
pub(super) fn add_new_pending_payment<ES: Deref>(
16551665
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16561666
keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
1657-
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
1667+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32,
1668+
bolt12_invoice: Option<Bolt12Invoice>
16581669
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
16591670
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
16601671
match pending_outbounds.entry(payment_id) {
16611672
hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
16621673
hash_map::Entry::Vacant(entry) => {
16631674
let (payment, onion_session_privs) = Self::create_pending_payment(
1664-
payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy,
1675+
payment_hash, recipient_onion, keysend_preimage, None, bolt12_invoice, route, retry_strategy,
16651676
payment_params, entropy_source, best_block_height
16661677
);
16671678
entry.insert(payment);
@@ -1673,8 +1684,8 @@ impl OutboundPayments {
16731684
fn create_pending_payment<ES: Deref>(
16741685
payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
16751686
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<InvoiceRequest>,
1676-
route: &Route, retry_strategy: Option<Retry>, payment_params: Option<PaymentParameters>,
1677-
entropy_source: &ES, best_block_height: u32
1687+
bolt12_invoice: Option<Bolt12Invoice>, route: &Route, retry_strategy: Option<Retry>,
1688+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
16781689
) -> (PendingOutboundPayment, Vec<[u8; 32]>)
16791690
where
16801691
ES::Target: EntropySource,
@@ -1696,6 +1707,7 @@ impl OutboundPayments {
16961707
payment_metadata: recipient_onion.payment_metadata,
16971708
keysend_preimage,
16981709
invoice_request,
1710+
bolt12_invoice,
16991711
custom_tlvs: recipient_onion.custom_tlvs,
17001712
starting_block_height: best_block_height,
17011713
total_msat: route.get_total_amount(),
@@ -2313,6 +2325,7 @@ impl OutboundPayments {
23132325
payment_metadata: None, // only used for retries, and we'll never retry on startup
23142326
keysend_preimage: None, // only used for retries, and we'll never retry on startup
23152327
invoice_request: None, // only used for retries, and we'll never retry on startup
2328+
bolt12_invoice: None, // only used for retries, and we'll never retry on startup! TODO(vincenzopalazzo): double check this
23162329
custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup
23172330
pending_amt_msat: path_amt,
23182331
pending_fee_msat: Some(path_fee),
@@ -2402,6 +2415,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
24022415
(10, starting_block_height, required),
24032416
(11, remaining_max_total_routing_fee_msat, option),
24042417
(13, invoice_request, option),
2418+
(15, bolt12_invoice, option),
24052419
(not_written, retry_strategy, (static_value, None)),
24062420
(not_written, attempts, (static_value, PaymentAttempts::new())),
24072421
},
@@ -2552,7 +2566,7 @@ mod tests {
25522566
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25532567
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25542568
Some(Retry::Attempts(1)), Some(expired_route_params.payment_params.clone()),
2555-
&&keys_manager, 0).unwrap();
2569+
&&keys_manager, 0, None).unwrap();
25562570
outbound_payments.find_route_and_send_payment(
25572571
PaymentHash([0; 32]), PaymentId([0; 32]), expired_route_params, &&router, vec![],
25582572
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
@@ -2595,7 +2609,7 @@ mod tests {
25952609
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25962610
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25972611
Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()),
2598-
&&keys_manager, 0).unwrap();
2612+
&&keys_manager, 0, None).unwrap();
25992613
outbound_payments.find_route_and_send_payment(
26002614
PaymentHash([0; 32]), PaymentId([0; 32]), route_params, &&router, vec![],
26012615
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,

0 commit comments

Comments
 (0)