Skip to content

Commit fe5ea5e

Browse files
move the bolt12 invoice inside HTLCSource::OutboundRoute
Matt noted during the last round of review the following: >Oof. Sorry I missed this until now. This is not, in fact, "only used for retries", we use it on claims only, in fact. If a user is relying on the event field for PoP, what this can mean is that we can initiate a send, restart with a stale ChannelManager, notice the payment is pending, then when it claims fail to provide the invoice (only the preimage) to the payer. >In practice, to fix this, we'll need to include the PaidBolt12Invoice in the HTLCSource::OutboundRoute, I believe. This commit is trying to store the PaidBolt12Invoice inside the HTLCSource::OutboundRoute, but this is not enough because we have to store the invoice also inside the PendingOutboundPayment. Link: lightningdevkit#3714 Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent 7b45811 commit fe5ea5e

File tree

4 files changed

+45
-22
lines changed

4 files changed

+45
-22
lines changed

lightning/src/ln/channel.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11701,6 +11701,7 @@ mod tests {
1170111701
session_priv: SecretKey::from_slice(&<Vec<u8>>::from_hex("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
1170211702
first_hop_htlc_msat: 548,
1170311703
payment_id: PaymentId([42; 32]),
11704+
bolt12_invoice: None,
1170411705
},
1170511706
skimmed_fee_msat: None,
1170611707
blinding_point: None,
@@ -12079,6 +12080,7 @@ mod tests {
1207912080
session_priv: test_utils::privkey(42),
1208012081
first_hop_htlc_msat: 0,
1208112082
payment_id: PaymentId([42; 32]),
12083+
bolt12_invoice: None,
1208212084
};
1208312085
let dummy_outbound_output = OutboundHTLCOutput {
1208412086
htlc_id: 0,

lightning/src/ln/channelmanager.rs

+19-9
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ use bitcoin::{secp256k1, Sequence};
3434
#[cfg(splicing)]
3535
use bitcoin::{TxIn, Weight};
3636

37-
use crate::events::FundingInfo;
37+
use crate::events::{FundingInfo, PaidBolt12Invoice};
3838
use crate::blinded_path::message::{AsyncPaymentsContext, MessageContext, OffersContext};
3939
use crate::blinded_path::NodeIdLookUp;
4040
use crate::blinded_path::message::{BlindedMessagePath, MessageForwardNode};
@@ -666,6 +666,8 @@ mod fuzzy_channelmanager {
666666
/// doing a double-pass on route when we get a failure back
667667
first_hop_htlc_msat: u64,
668668
payment_id: PaymentId,
669+
// TODO(vincenzopalazzo): add the documentation for this field
670+
bolt12_invoice: Option<PaidBolt12Invoice>,
669671
},
670672
}
671673

@@ -703,7 +705,8 @@ impl core::hash::Hash for HTLCSource {
703705
0u8.hash(hasher);
704706
prev_hop_data.hash(hasher);
705707
},
706-
HTLCSource::OutboundRoute { path, session_priv, payment_id, first_hop_htlc_msat } => {
708+
// FIXME(vincenzopalazzo): we can ignore the bolt12_invoice here?
709+
HTLCSource::OutboundRoute { path, session_priv, payment_id, first_hop_htlc_msat, .. } => {
707710
1u8.hash(hasher);
708711
path.hash(hasher);
709712
session_priv[..].hash(hasher);
@@ -721,6 +724,7 @@ impl HTLCSource {
721724
session_priv: SecretKey::from_slice(&[1; 32]).unwrap(),
722725
first_hop_htlc_msat: 0,
723726
payment_id: PaymentId([2; 32]),
727+
bolt12_invoice: None,
724728
}
725729
}
726730

@@ -4634,14 +4638,14 @@ where
46344638
let _lck = self.total_consistency_lock.read().unwrap();
46354639
self.send_payment_along_path(SendAlongPathArgs {
46364640
path, payment_hash, recipient_onion: &recipient_onion, total_value,
4637-
cur_height, payment_id, keysend_preimage, invoice_request: None, session_priv_bytes
4641+
cur_height, payment_id, keysend_preimage, invoice_request: None, bolt12_invoice: None, session_priv_bytes
46384642
})
46394643
}
46404644

46414645
fn send_payment_along_path(&self, args: SendAlongPathArgs) -> Result<(), APIError> {
46424646
let SendAlongPathArgs {
46434647
path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage,
4644-
invoice_request, session_priv_bytes
4648+
invoice_request, bolt12_invoice, session_priv_bytes
46454649
} = args;
46464650
// The top-level caller should hold the total_consistency_lock read lock.
46474651
debug_assert!(self.total_consistency_lock.try_write().is_err());
@@ -4691,6 +4695,7 @@ where
46914695
session_priv: session_priv.clone(),
46924696
first_hop_htlc_msat: htlc_msat,
46934697
payment_id,
4698+
bolt12_invoice: bolt12_invoice.cloned(),
46944699
}, onion_packet, None, &self.fee_estimator, &&logger);
46954700
match break_channel_entry!(self, peer_state, send_res, chan_entry) {
46964701
Some(monitor_update) => {
@@ -7459,15 +7464,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
74597464
next_channel_outpoint: OutPoint, next_channel_id: ChannelId, next_user_channel_id: Option<u128>,
74607465
) {
74617466
match source {
7462-
HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
7467+
HTLCSource::OutboundRoute { session_priv, payment_id, path, bolt12_invoice, .. } => {
74637468
debug_assert!(self.background_events_processed_since_startup.load(Ordering::Acquire),
74647469
"We don't support claim_htlc claims during startup - monitors may not be available yet");
74657470
debug_assert_eq!(next_channel_counterparty_node_id, path.hops[0].pubkey);
74667471
let ev_completion_action = EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
74677472
channel_funding_outpoint: next_channel_outpoint, channel_id: next_channel_id,
74687473
counterparty_node_id: path.hops[0].pubkey,
74697474
};
7470-
self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage,
7475+
self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage, bolt12_invoice,
74717476
session_priv, path, from_onchain, ev_completion_action, &self.pending_events,
74727477
&self.logger);
74737478
},
@@ -8918,6 +8923,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
89188923
hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.channel_id))
89198924
}
89208925
};
8926+
// TODO(vincenzopalazzo): pass down the paid bolt12invoice
89218927
self.claim_funds_internal(htlc_source, msg.payment_preimage.clone(),
89228928
Some(forwarded_htlc_value), skimmed_fee_msat, false, false, *counterparty_node_id,
89238929
funding_txo, msg.channel_id, Some(next_user_channel_id),
@@ -13144,13 +13150,15 @@ impl Readable for HTLCSource {
1314413150
let mut payment_id = None;
1314513151
let mut payment_params: Option<PaymentParameters> = None;
1314613152
let mut blinded_tail: Option<BlindedTail> = None;
13153+
let mut bolt12_invoice: Option<PaidBolt12Invoice> = None;
1314713154
read_tlv_fields!(reader, {
1314813155
(0, session_priv, required),
1314913156
(1, payment_id, option),
1315013157
(2, first_hop_htlc_msat, required),
1315113158
(4, path_hops, required_vec),
1315213159
(5, payment_params, (option: ReadableArgs, 0)),
1315313160
(6, blinded_tail, option),
13161+
(8, bolt12_invoice, option),
1315413162
});
1315513163
if payment_id.is_none() {
1315613164
// For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -13173,6 +13181,7 @@ impl Readable for HTLCSource {
1317313181
first_hop_htlc_msat,
1317413182
path,
1317513183
payment_id: payment_id.unwrap(),
13184+
bolt12_invoice,
1317613185
})
1317713186
}
1317813187
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
@@ -13184,7 +13193,7 @@ impl Readable for HTLCSource {
1318413193
impl Writeable for HTLCSource {
1318513194
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), crate::io::Error> {
1318613195
match self {
13187-
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id } => {
13196+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, bolt12_invoice } => {
1318813197
0u8.write(writer)?;
1318913198
let payment_id_opt = Some(payment_id);
1319013199
write_tlv_fields!(writer, {
@@ -13195,6 +13204,7 @@ impl Writeable for HTLCSource {
1319513204
(4, path.hops, required_vec),
1319613205
(5, None::<PaymentParameters>, option), // payment_params in LDK versions prior to 0.0.115
1319713206
(6, path.blinded_tail, option),
13207+
(8, bolt12_invoice, option),
1319813208
});
1319913209
}
1320013210
HTLCSource::PreviousHopData(ref field) => {
@@ -14381,7 +14391,7 @@ where
1438114391
} else { true }
1438214392
});
1438314393
},
14384-
HTLCSource::OutboundRoute { payment_id, session_priv, path, .. } => {
14394+
HTLCSource::OutboundRoute { payment_id, session_priv, path, bolt12_invoice, .. } => {
1438514395
if let Some(preimage) = preimage_opt {
1438614396
let pending_events = Mutex::new(pending_events_read);
1438714397
// Note that we set `from_onchain` to "false" here,
@@ -14398,7 +14408,7 @@ where
1439814408
channel_id: monitor.channel_id(),
1439914409
counterparty_node_id: path.hops[0].pubkey,
1440014410
};
14401-
pending_outbounds.claim_htlc(payment_id, preimage, session_priv,
14411+
pending_outbounds.claim_htlc(payment_id, preimage, bolt12_invoice, session_priv,
1440214412
path, false, compl_action, &pending_events, &&logger);
1440314413
pending_events_read = pending_events.into_inner().unwrap();
1440414414
}

lightning/src/ln/onion_utils.rs

+4
Original file line numberDiff line numberDiff line change
@@ -2904,6 +2904,7 @@ mod tests {
29042904
session_priv: get_test_session_key(),
29052905
first_hop_htlc_msat: 0,
29062906
payment_id: PaymentId([1; 32]),
2907+
bolt12_invoice: None,
29072908
};
29082909

29092910
process_onion_failure(&ctx_full, &logger, &htlc_source, onion_error)
@@ -3029,6 +3030,7 @@ mod tests {
30293030
session_priv,
30303031
first_hop_htlc_msat: dummy_amt_msat,
30313032
payment_id: PaymentId([1; 32]),
3033+
bolt12_invoice: None,
30323034
};
30333035

30343036
{
@@ -3221,6 +3223,7 @@ mod tests {
32213223
session_priv: session_key,
32223224
first_hop_htlc_msat: 0,
32233225
payment_id: PaymentId([1; 32]),
3226+
bolt12_invoice: None,
32243227
};
32253228

32263229
// Iterate over all possible failure positions and check that the cases that can be attributed are.
@@ -3329,6 +3332,7 @@ mod tests {
33293332
session_priv: get_test_session_key(),
33303333
first_hop_htlc_msat: 0,
33313334
payment_id: PaymentId([1; 32]),
3335+
bolt12_invoice: None,
33323336
};
33333337

33343338
let decrypted_failure = process_onion_failure(&ctx_full, &logger, &htlc_source, packet);

lightning/src/ln/outbound_payment.rs

+20-13
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ impl PendingOutboundPayment {
163163
_ => None,
164164
}
165165
}
166+
166167
fn increment_attempts(&mut self) {
167168
if let PendingOutboundPayment::Retryable { attempts, .. } = self {
168169
attempts.count += 1;
@@ -797,6 +798,7 @@ pub(super) struct SendAlongPathArgs<'a> {
797798
pub payment_id: PaymentId,
798799
pub keysend_preimage: &'a Option<PaymentPreimage>,
799800
pub invoice_request: Option<&'a InvoiceRequest>,
801+
pub bolt12_invoice: Option<&'a PaidBolt12Invoice>,
800802
pub session_priv_bytes: [u8; 32],
801803
}
802804

@@ -1042,7 +1044,8 @@ impl OutboundPayments {
10421044
hash_map::Entry::Occupied(entry) => match entry.get() {
10431045
PendingOutboundPayment::InvoiceReceived { .. } => {
10441046
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
1045-
payment_hash, recipient_onion.clone(), keysend_preimage, None, Some(bolt12_invoice), &route,
1047+
// FIXME: remove the bolt12_invoice here! we need to clean up this part!
1048+
payment_hash, recipient_onion.clone(), keysend_preimage, None, Some(bolt12_invoice.clone()), &route,
10461049
Some(retry_strategy), payment_params, entropy_source, best_block_height,
10471050
);
10481051
*entry.into_mut() = retryable_payment;
@@ -1053,7 +1056,8 @@ impl OutboundPayments {
10531056
invoice_request
10541057
} else { unreachable!() };
10551058
let (retryable_payment, onion_session_privs) = Self::create_pending_payment(
1056-
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), Some(bolt12_invoice), &route,
1059+
// FIXME: We do not need anymore the bolt12_invoice here! we need to clean up this part!
1060+
payment_hash, recipient_onion.clone(), keysend_preimage, Some(invreq), Some(bolt12_invoice.clone()), &route,
10571061
Some(retry_strategy), payment_params, entropy_source, best_block_height
10581062
);
10591063
outbounds.insert(payment_id, retryable_payment);
@@ -1066,7 +1070,7 @@ impl OutboundPayments {
10661070
core::mem::drop(outbounds);
10671071

10681072
let result = self.pay_route_internal(
1069-
&route, payment_hash, &recipient_onion, keysend_preimage, invoice_request, payment_id,
1073+
&route, payment_hash, &recipient_onion, keysend_preimage, invoice_request, Some(bolt12_invoice), payment_id,
10701074
Some(route_params.final_value_msat), &onion_session_privs, node_signer, best_block_height,
10711075
&send_payment_along_path
10721076
);
@@ -1359,7 +1363,7 @@ impl OutboundPayments {
13591363
})?;
13601364

13611365
let res = self.pay_route_internal(&route, payment_hash, &recipient_onion,
1362-
keysend_preimage, None, payment_id, None, &onion_session_privs, node_signer,
1366+
keysend_preimage, None, None, payment_id, None, &onion_session_privs, node_signer,
13631367
best_block_height, &send_payment_along_path);
13641368
log_info!(logger, "Sending payment with id {} and hash {} returned {:?}",
13651369
payment_id, payment_hash, res);
@@ -1437,7 +1441,7 @@ impl OutboundPayments {
14371441
}
14381442
}
14391443
}
1440-
let (total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request) = {
1444+
let (total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request, bolt12_invoice) = {
14411445
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
14421446
match outbounds.entry(payment_id) {
14431447
hash_map::Entry::Occupied(mut payment) => {
@@ -1479,8 +1483,9 @@ impl OutboundPayments {
14791483
}
14801484

14811485
payment.get_mut().increment_attempts();
1486+
let bolt12_invoice = payment.get().bolt12_invoice();
14821487

1483-
(total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request)
1488+
(total_msat, recipient_onion, keysend_preimage, onion_session_privs, invoice_request, bolt12_invoice.cloned())
14841489
},
14851490
PendingOutboundPayment::Legacy { .. } => {
14861491
log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102");
@@ -1520,7 +1525,7 @@ impl OutboundPayments {
15201525
}
15211526
};
15221527
let res = self.pay_route_internal(&route, payment_hash, &recipient_onion, keysend_preimage,
1523-
invoice_request.as_ref(), payment_id, Some(total_msat), &onion_session_privs, node_signer,
1528+
invoice_request.as_ref(), bolt12_invoice, payment_id, Some(total_msat), &onion_session_privs, node_signer,
15241529
best_block_height, &send_payment_along_path);
15251530
log_info!(logger, "Result retrying payment id {}: {:?}", &payment_id, res);
15261531
if let Err(e) = res {
@@ -1673,7 +1678,7 @@ impl OutboundPayments {
16731678

16741679
let recipient_onion_fields = RecipientOnionFields::spontaneous_empty();
16751680
match self.pay_route_internal(&route, payment_hash, &recipient_onion_fields,
1676-
None, None, payment_id, None, &onion_session_privs, node_signer, best_block_height,
1681+
None, None, None, payment_id, None, &onion_session_privs, node_signer, best_block_height,
16771682
&send_payment_along_path
16781683
) {
16791684
Ok(()) => Ok((payment_hash, payment_id)),
@@ -1865,7 +1870,7 @@ impl OutboundPayments {
18651870

18661871
fn pay_route_internal<NS: Deref, F>(
18671872
&self, route: &Route, payment_hash: PaymentHash, recipient_onion: &RecipientOnionFields,
1868-
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
1873+
keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>, bolt12_invoice: Option<PaidBolt12Invoice>,
18691874
payment_id: PaymentId, recv_value_msat: Option<u64>, onion_session_privs: &Vec<[u8; 32]>,
18701875
node_signer: &NS, best_block_height: u32, send_payment_along_path: &F
18711876
) -> Result<(), PaymentSendFailure>
@@ -1921,6 +1926,7 @@ impl OutboundPayments {
19211926
let path_res = send_payment_along_path(SendAlongPathArgs {
19221927
path: &path, payment_hash: &payment_hash, recipient_onion, total_value,
19231928
cur_height, payment_id, keysend_preimage: &keysend_preimage, invoice_request,
1929+
bolt12_invoice: bolt12_invoice.as_ref(),
19241930
session_priv_bytes: *session_priv_bytes
19251931
});
19261932
results.push(path_res);
@@ -1987,7 +1993,7 @@ impl OutboundPayments {
19871993
F: Fn(SendAlongPathArgs) -> Result<(), APIError>,
19881994
{
19891995
self.pay_route_internal(route, payment_hash, &recipient_onion,
1990-
keysend_preimage, None, payment_id, recv_value_msat, &onion_session_privs,
1996+
keysend_preimage, None, None, payment_id, recv_value_msat, &onion_session_privs,
19911997
node_signer, best_block_height, &send_payment_along_path)
19921998
.map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
19931999
}
@@ -2008,8 +2014,8 @@ impl OutboundPayments {
20082014
}
20092015

20102016
pub(super) fn claim_htlc<L: Deref>(
2011-
&self, payment_id: PaymentId, payment_preimage: PaymentPreimage, session_priv: SecretKey,
2012-
path: Path, from_onchain: bool, ev_completion_action: EventCompletionAction,
2017+
&self, payment_id: PaymentId, payment_preimage: PaymentPreimage, bolt12_invoice: Option<PaidBolt12Invoice>,
2018+
session_priv: SecretKey, path: Path, from_onchain: bool, ev_completion_action: EventCompletionAction,
20132019
pending_events: &Mutex<VecDeque<(events::Event, Option<EventCompletionAction>)>>,
20142020
logger: &L,
20152021
) where L::Target: Logger {
@@ -2029,7 +2035,7 @@ impl OutboundPayments {
20292035
payment_hash,
20302036
amount_msat,
20312037
fee_paid_msat,
2032-
bolt12_invoice: payment.get().bolt12_invoice().cloned(),
2038+
bolt12_invoice: bolt12_invoice.clone(),
20332039
}, Some(ev_completion_action.clone())));
20342040
payment.get_mut().mark_fulfilled();
20352041
}
@@ -2061,6 +2067,7 @@ impl OutboundPayments {
20612067
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
20622068
let mut pending_events = pending_events.lock().unwrap();
20632069
for source in sources {
2070+
// TODO(vincenzopalazzo): This should contain the paid bolt12 invoice.
20642071
if let HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } = source {
20652072
let mut session_priv_bytes = [0; 32];
20662073
session_priv_bytes.copy_from_slice(&session_priv[..]);

0 commit comments

Comments
 (0)