Skip to content

Commit 4d83694

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 18166d0 commit 4d83694

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
@@ -2299,7 +2299,7 @@ pub fn expect_payment_sent<CM: AChannelManager, H: NodeHolder<CM=CM>>(node: &H,
22992299
check_added_monitors(node, 1);
23002300
}
23012301
let expected_payment_id = match events[0] {
2302-
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat } => {
2302+
Event::PaymentSent { ref payment_id, ref payment_preimage, ref payment_hash, ref fee_paid_msat, .. } => {
23032303
assert_eq!(expected_payment_preimage, *payment_preimage);
23042304
assert_eq!(expected_payment_hash, *payment_hash);
23052305
if let Some(expected_fee_msat) = expected_fee_msat_opt {

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+.
@@ -148,6 +151,12 @@ impl_writeable_tlv_based!(RetryableInvoiceRequest, {
148151
});
149152

150153
impl PendingOutboundPayment {
154+
fn bolt12_invoice(&self) -> Option<&Bolt12Invoice> {
155+
match self {
156+
PendingOutboundPayment::Retryable { bolt12_invoice, .. } => bolt12_invoice.as_ref(),
157+
_ => None,
158+
}
159+
}
151160
fn increment_attempts(&mut self) {
152161
if let PendingOutboundPayment::Retryable { attempts, .. } = self {
153162
attempts.count += 1;
@@ -879,7 +888,7 @@ impl OutboundPayments {
879888
route_params.max_total_routing_fee_msat = Some(max_fee_msat);
880889
}
881890
self.send_payment_for_bolt12_invoice_internal(
882-
payment_id, payment_hash, None, None, route_params, retry_strategy, router, first_hops,
891+
payment_id, payment_hash, None, None, Some(invoice), route_params, retry_strategy, router, first_hops,
883892
inflight_htlcs, entropy_source, node_signer, node_id_lookup, secp_ctx, best_block_height,
884893
logger, pending_events, send_payment_along_path
885894
)
@@ -890,6 +899,7 @@ impl OutboundPayments {
890899
>(
891900
&self, payment_id: PaymentId, payment_hash: PaymentHash,
892901
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
902+
bolt12_invoice: Option<&Bolt12Invoice>,
893903
mut route_params: RouteParameters, retry_strategy: Retry, router: &R,
894904
first_hops: Vec<ChannelDetails>, inflight_htlcs: IH, entropy_source: &ES, node_signer: &NS,
895905
node_id_lookup: &NL, secp_ctx: &Secp256k1<secp256k1::All>, best_block_height: u32, logger: &L,
@@ -952,18 +962,20 @@ impl OutboundPayments {
952962
hash_map::Entry::Occupied(entry) => match entry.get() {
953963
PendingOutboundPayment::InvoiceReceived { .. } => {
954964
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
955-
payment_hash, recipient_onion.clone(), keysend_preimage, None, &route,
956-
Some(retry_strategy), payment_params, entropy_source, best_block_height
965+
payment_hash, recipient_onion.clone(), keysend_preimage, None, bolt12_invoice.cloned(), &route,
966+
Some(retry_strategy), payment_params, entropy_source, best_block_height,
957967
);
958968
*entry.into_mut() = retryable_payment;
959969
onion_session_privs
960970
},
971+
// TODO(vincenzopalazzo): What about static invoices? There is no proof of payment with async payment because we need PTLC
972+
// so we can ingore it for now
961973
PendingOutboundPayment::StaticInvoiceReceived { .. } => {
962974
let invreq = if let PendingOutboundPayment::StaticInvoiceReceived { invoice_request, .. } = entry.remove() {
963975
invoice_request
964976
} else { unreachable!() };
965977
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
966-
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), &route,
978+
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), None, &route,
967979
Some(retry_strategy), payment_params, entropy_source, best_block_height
968980
);
969981
outbounds.insert(payment_id, retryable_payment);
@@ -1113,7 +1125,7 @@ impl OutboundPayments {
11131125
};
11141126

11151127
self.send_payment_for_bolt12_invoice_internal(
1116-
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), route_params,
1128+
payment_id, payment_hash, Some(keysend_preimage), Some(&invoice_request), None, route_params,
11171129
retry_strategy, router, first_hops, inflight_htlcs, entropy_source, node_signer,
11181130
node_id_lookup, secp_ctx, best_block_height, logger, pending_events, send_payment_along_path
11191131
)
@@ -1259,7 +1271,7 @@ impl OutboundPayments {
12591271

12601272
let onion_session_privs = self.add_new_pending_payment(payment_hash,
12611273
recipient_onion.clone(), payment_id, keysend_preimage, &route, Some(retry_strategy),
1262-
Some(route_params.payment_params.clone()), entropy_source, best_block_height)
1274+
Some(route_params.payment_params.clone()), entropy_source, best_block_height, None)
12631275
.map_err(|_| {
12641276
log_error!(logger, "Payment with id {} is already pending. New payment had payment hash {}",
12651277
payment_id, payment_hash);
@@ -1573,7 +1585,7 @@ impl OutboundPayments {
15731585
let route = Route { paths: vec![path], route_params: None };
15741586
let onion_session_privs = self.add_new_pending_payment(payment_hash,
15751587
RecipientOnionFields::secret_only(payment_secret), payment_id, None, &route, None, None,
1576-
entropy_source, best_block_height
1588+
entropy_source, best_block_height, None
15771589
).map_err(|e| {
15781590
debug_assert!(matches!(e, PaymentSendFailure::DuplicatePayment));
15791591
ProbeSendFailure::DuplicateProbe
@@ -1628,20 +1640,21 @@ impl OutboundPayments {
16281640
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16291641
route: &Route, retry_strategy: Option<Retry>, entropy_source: &ES, best_block_height: u32
16301642
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
1631-
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height)
1643+
self.add_new_pending_payment(payment_hash, recipient_onion, payment_id, None, route, retry_strategy, None, entropy_source, best_block_height, None)
16321644
}
16331645

16341646
pub(super) fn add_new_pending_payment<ES: Deref>(
16351647
&self, payment_hash: PaymentHash, recipient_onion: RecipientOnionFields, payment_id: PaymentId,
16361648
keysend_preimage: Option<PaymentPreimage>, route: &Route, retry_strategy: Option<Retry>,
1637-
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
1649+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32,
1650+
bolt12_invoice: Option<Bolt12Invoice>
16381651
) -> Result<Vec<[u8; 32]>, PaymentSendFailure> where ES::Target: EntropySource {
16391652
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
16401653
match pending_outbounds.entry(payment_id) {
16411654
hash_map::Entry::Occupied(_) => Err(PaymentSendFailure::DuplicatePayment),
16421655
hash_map::Entry::Vacant(entry) => {
16431656
let (payment, onion_session_privs) = Self::create_pending_payment(
1644-
payment_hash, recipient_onion, keysend_preimage, None, route, retry_strategy,
1657+
payment_hash, recipient_onion, keysend_preimage, None, bolt12_invoice, route, retry_strategy,
16451658
payment_params, entropy_source, best_block_height
16461659
);
16471660
entry.insert(payment);
@@ -1653,8 +1666,8 @@ impl OutboundPayments {
16531666
fn create_pending_payment<ES: Deref>(
16541667
payment_hash: PaymentHash, recipient_onion: RecipientOnionFields,
16551668
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<InvoiceRequest>,
1656-
route: &Route, retry_strategy: Option<Retry>, payment_params: Option<PaymentParameters>,
1657-
entropy_source: &ES, best_block_height: u32
1669+
bolt12_invoice: Option<Bolt12Invoice>, route: &Route, retry_strategy: Option<Retry>,
1670+
payment_params: Option<PaymentParameters>, entropy_source: &ES, best_block_height: u32
16581671
) -> (PendingOutboundPayment, Vec<[u8; 32]>)
16591672
where
16601673
ES::Target: EntropySource,
@@ -1676,6 +1689,7 @@ impl OutboundPayments {
16761689
payment_metadata: recipient_onion.payment_metadata,
16771690
keysend_preimage,
16781691
invoice_request,
1692+
bolt12_invoice,
16791693
custom_tlvs: recipient_onion.custom_tlvs,
16801694
starting_block_height: best_block_height,
16811695
total_msat: route.get_total_amount(),
@@ -2291,6 +2305,7 @@ impl OutboundPayments {
22912305
payment_metadata: None, // only used for retries, and we'll never retry on startup
22922306
keysend_preimage: None, // only used for retries, and we'll never retry on startup
22932307
invoice_request: None, // only used for retries, and we'll never retry on startup
2308+
bolt12_invoice: None, // only used for retries, and we'll never retry on startup! TODO(vincenzopalazzo): double check this
22942309
custom_tlvs: Vec::new(), // only used for retries, and we'll never retry on startup
22952310
pending_amt_msat: path_amt,
22962311
pending_fee_msat: Some(path_fee),
@@ -2379,6 +2394,7 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
23792394
(10, starting_block_height, required),
23802395
(11, remaining_max_total_routing_fee_msat, option),
23812396
(13, invoice_request, option),
2397+
(15, bolt12_invoice, option),
23822398
(not_written, retry_strategy, (static_value, None)),
23832399
(not_written, attempts, (static_value, PaymentAttempts::new())),
23842400
},
@@ -2496,7 +2512,7 @@ mod tests {
24962512
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
24972513
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
24982514
Some(Retry::Attempts(1)), Some(expired_route_params.payment_params.clone()),
2499-
&&keys_manager, 0).unwrap();
2515+
&&keys_manager, 0, None).unwrap();
25002516
outbound_payments.find_route_and_send_payment(
25012517
PaymentHash([0; 32]), PaymentId([0; 32]), expired_route_params, &&router, vec![],
25022518
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
@@ -2540,7 +2556,7 @@ mod tests {
25402556
outbound_payments.add_new_pending_payment(PaymentHash([0; 32]), RecipientOnionFields::spontaneous_empty(),
25412557
PaymentId([0; 32]), None, &Route { paths: vec![], route_params: None },
25422558
Some(Retry::Attempts(1)), Some(route_params.payment_params.clone()),
2543-
&&keys_manager, 0).unwrap();
2559+
&&keys_manager, 0, None).unwrap();
25442560
outbound_payments.find_route_and_send_payment(
25452561
PaymentHash([0; 32]), PaymentId([0; 32]), route_params, &&router, vec![],
25462562
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,

0 commit comments

Comments
 (0)