Skip to content

Commit 637983d

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: #3714 Signed-off-by: Vincenzo Palazzo <[email protected]>
1 parent c6921fa commit 637983d

File tree

5 files changed

+45
-23
lines changed

5 files changed

+45
-23
lines changed

fuzz/src/process_onion_failure.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
115115
let path = Path { hops, blinded_tail };
116116

117117
let htlc_source =
118-
HTLCSource::OutboundRoute { path, session_priv, first_hop_htlc_msat: 0, payment_id };
118+
HTLCSource::OutboundRoute { path, session_priv, first_hop_htlc_msat: 0, payment_id, bolt12_invoice: None };
119119

120120
let failure_len = get_u16!();
121121
let failure_data = get_slice!(failure_len);

lightning/src/ln/channel.rs

+2
Original file line numberDiff line numberDiff line change
@@ -11836,6 +11836,7 @@ mod tests {
1183611836
session_priv: SecretKey::from_slice(&<Vec<u8>>::from_hex("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
1183711837
first_hop_htlc_msat: 548,
1183811838
payment_id: PaymentId([42; 32]),
11839+
bolt12_invoice: None,
1183911840
},
1184011841
skimmed_fee_msat: None,
1184111842
blinding_point: None,
@@ -12214,6 +12215,7 @@ mod tests {
1221412215
session_priv: test_utils::privkey(42),
1221512216
first_hop_htlc_msat: 0,
1221612217
payment_id: PaymentId([42; 32]),
12218+
bolt12_invoice: None,
1221712219
};
1221812220
let dummy_outbound_output = OutboundHTLCOutput {
1221912221
htlc_id: 0,

lightning/src/ln/channelmanager.rs

+18-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};
@@ -668,6 +668,8 @@ mod fuzzy_channelmanager {
668668
/// doing a double-pass on route when we get a failure back
669669
first_hop_htlc_msat: u64,
670670
payment_id: PaymentId,
671+
// TODO(vincenzopalazzo): add the documentation for this field
672+
bolt12_invoice: Option<PaidBolt12Invoice>,
671673
},
672674
}
673675

@@ -705,7 +707,8 @@ impl core::hash::Hash for HTLCSource {
705707
0u8.hash(hasher);
706708
prev_hop_data.hash(hasher);
707709
},
708-
HTLCSource::OutboundRoute { path, session_priv, payment_id, first_hop_htlc_msat } => {
710+
// FIXME(vincenzopalazzo): we can ignore the bolt12_invoice here?
711+
HTLCSource::OutboundRoute { path, session_priv, payment_id, first_hop_htlc_msat, .. } => {
709712
1u8.hash(hasher);
710713
path.hash(hasher);
711714
session_priv[..].hash(hasher);
@@ -723,6 +726,7 @@ impl HTLCSource {
723726
session_priv: SecretKey::from_slice(&[1; 32]).unwrap(),
724727
first_hop_htlc_msat: 0,
725728
payment_id: PaymentId([2; 32]),
729+
bolt12_invoice: None,
726730
}
727731
}
728732

@@ -4629,14 +4633,14 @@ where
46294633
let _lck = self.total_consistency_lock.read().unwrap();
46304634
self.send_payment_along_path(SendAlongPathArgs {
46314635
path, payment_hash, recipient_onion: &recipient_onion, total_value,
4632-
cur_height, payment_id, keysend_preimage, invoice_request: None, session_priv_bytes
4636+
cur_height, payment_id, keysend_preimage, invoice_request: None, bolt12_invoice: None, session_priv_bytes
46334637
})
46344638
}
46354639

46364640
fn send_payment_along_path(&self, args: SendAlongPathArgs) -> Result<(), APIError> {
46374641
let SendAlongPathArgs {
46384642
path, payment_hash, recipient_onion, total_value, cur_height, payment_id, keysend_preimage,
4639-
invoice_request, session_priv_bytes
4643+
invoice_request, bolt12_invoice, session_priv_bytes
46404644
} = args;
46414645
// The top-level caller should hold the total_consistency_lock read lock.
46424646
debug_assert!(self.total_consistency_lock.try_write().is_err());
@@ -4686,6 +4690,7 @@ where
46864690
session_priv: session_priv.clone(),
46874691
first_hop_htlc_msat: htlc_msat,
46884692
payment_id,
4693+
bolt12_invoice: bolt12_invoice.cloned(),
46894694
}, onion_packet, None, &self.fee_estimator, &&logger);
46904695
match break_channel_entry!(self, peer_state, send_res, chan_entry) {
46914696
Some(monitor_update) => {
@@ -7447,15 +7452,15 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
74477452
next_channel_outpoint: OutPoint, next_channel_id: ChannelId, next_user_channel_id: Option<u128>,
74487453
) {
74497454
match source {
7450-
HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
7455+
HTLCSource::OutboundRoute { session_priv, payment_id, path, bolt12_invoice, .. } => {
74517456
debug_assert!(self.background_events_processed_since_startup.load(Ordering::Acquire),
74527457
"We don't support claim_htlc claims during startup - monitors may not be available yet");
74537458
debug_assert_eq!(next_channel_counterparty_node_id, path.hops[0].pubkey);
74547459
let ev_completion_action = EventCompletionAction::ReleaseRAAChannelMonitorUpdate {
74557460
channel_funding_outpoint: next_channel_outpoint, channel_id: next_channel_id,
74567461
counterparty_node_id: path.hops[0].pubkey,
74577462
};
7458-
self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage,
7463+
self.pending_outbound_payments.claim_htlc(payment_id, payment_preimage, bolt12_invoice,
74597464
session_priv, path, from_onchain, ev_completion_action, &self.pending_events,
74607465
&self.logger);
74617466
},
@@ -13131,13 +13136,15 @@ impl Readable for HTLCSource {
1313113136
let mut payment_id = None;
1313213137
let mut payment_params: Option<PaymentParameters> = None;
1313313138
let mut blinded_tail: Option<BlindedTail> = None;
13139+
let mut bolt12_invoice: Option<PaidBolt12Invoice> = None;
1313413140
read_tlv_fields!(reader, {
1313513141
(0, session_priv, required),
1313613142
(1, payment_id, option),
1313713143
(2, first_hop_htlc_msat, required),
1313813144
(4, path_hops, required_vec),
1313913145
(5, payment_params, (option: ReadableArgs, 0)),
1314013146
(6, blinded_tail, option),
13147+
(7, bolt12_invoice, option),
1314113148
});
1314213149
if payment_id.is_none() {
1314313150
// For backwards compat, if there was no payment_id written, use the session_priv bytes
@@ -13160,6 +13167,7 @@ impl Readable for HTLCSource {
1316013167
first_hop_htlc_msat,
1316113168
path,
1316213169
payment_id: payment_id.unwrap(),
13170+
bolt12_invoice,
1316313171
})
1316413172
}
1316513173
1 => Ok(HTLCSource::PreviousHopData(Readable::read(reader)?)),
@@ -13171,7 +13179,7 @@ impl Readable for HTLCSource {
1317113179
impl Writeable for HTLCSource {
1317213180
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), crate::io::Error> {
1317313181
match self {
13174-
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id } => {
13182+
HTLCSource::OutboundRoute { ref session_priv, ref first_hop_htlc_msat, ref path, payment_id, bolt12_invoice } => {
1317513183
0u8.write(writer)?;
1317613184
let payment_id_opt = Some(payment_id);
1317713185
write_tlv_fields!(writer, {
@@ -13182,6 +13190,7 @@ impl Writeable for HTLCSource {
1318213190
(4, path.hops, required_vec),
1318313191
(5, None::<PaymentParameters>, option), // payment_params in LDK versions prior to 0.0.115
1318413192
(6, path.blinded_tail, option),
13193+
(7, bolt12_invoice, option),
1318513194
});
1318613195
}
1318713196
HTLCSource::PreviousHopData(ref field) => {
@@ -14368,7 +14377,7 @@ where
1436814377
} else { true }
1436914378
});
1437014379
},
14371-
HTLCSource::OutboundRoute { payment_id, session_priv, path, .. } => {
14380+
HTLCSource::OutboundRoute { payment_id, session_priv, path, bolt12_invoice, .. } => {
1437214381
if let Some(preimage) = preimage_opt {
1437314382
let pending_events = Mutex::new(pending_events_read);
1437414383
// Note that we set `from_onchain` to "false" here,
@@ -14385,7 +14394,7 @@ where
1438514394
channel_id: monitor.channel_id(),
1438614395
counterparty_node_id: path.hops[0].pubkey,
1438714396
};
14388-
pending_outbounds.claim_htlc(payment_id, preimage, session_priv,
14397+
pending_outbounds.claim_htlc(payment_id, preimage, bolt12_invoice, session_priv,
1438914398
path, false, compl_action, &pending_events, &&logger);
1439014399
pending_events_read = pending_events.into_inner().unwrap();
1439114400
}

lightning/src/ln/onion_utils.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3233,6 +3233,7 @@ mod tests {
32333233
session_priv: get_test_session_key(),
32343234
first_hop_htlc_msat: 0,
32353235
payment_id: PaymentId([1; 32]),
3236+
bolt12_invoice: None,
32363237
};
32373238

32383239
process_onion_failure(&ctx_full, &logger, &htlc_source, onion_error)
@@ -3360,6 +3361,7 @@ mod tests {
33603361
session_priv,
33613362
first_hop_htlc_msat: dummy_amt_msat,
33623363
payment_id: PaymentId([1; 32]),
3364+
bolt12_invoice: None,
33633365
};
33643366

33653367
{
@@ -3547,6 +3549,7 @@ mod tests {
35473549
session_priv: session_key,
35483550
first_hop_htlc_msat: 0,
35493551
payment_id: PaymentId([1; 32]),
3552+
bolt12_invoice: None,
35503553
};
35513554

35523555
// Iterate over all possible failure positions and check that the cases that can be attributed are.
@@ -3655,6 +3658,7 @@ mod tests {
36553658
session_priv: get_test_session_key(),
36563659
first_hop_htlc_msat: 0,
36573660
payment_id: PaymentId([1; 32]),
3661+
bolt12_invoice: None,
36583662
};
36593663

36603664
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)