Skip to content

Commit 30d7f2d

Browse files
committed
Require RecipientOnionFields in the claimable HTLC pipeline
We added `RecipientOnionFields` in the `ClaimablePayment`/`ClaimingPayment` structs in 0.0.115/0.0.124, always writing them for new HTLCs. As of 0.1, we do not support upgrading from 0.0.123 or earlier with pending HTLCs to forward or claim. Thus, we already don't support upgrading in cases where no `RecipientOnionFields` is set and we can thus go ahead and mark it as non-`Option`al. Further, there's some super ancient upgrade logic in `ChannelManager` deserialization we can remove at the same time.
1 parent abafdeb commit 30d7f2d

1 file changed

Lines changed: 29 additions & 73 deletions

File tree

lightning/src/ln/channelmanager.rs

Lines changed: 29 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,7 +1089,7 @@ struct ClaimingPayment {
10891089
receiver_node_id: PublicKey,
10901090
htlcs: Vec<events::ClaimedHTLC>,
10911091
sender_intended_value: Option<u64>,
1092-
onion_fields: Option<RecipientOnionFields>,
1092+
onion_fields: RecipientOnionFields,
10931093
payment_id: Option<PaymentId>,
10941094
/// When we claim and generate a [`Event::PaymentClaimed`], we want to block any
10951095
/// payment-preimage-removing RAA [`ChannelMonitorUpdate`]s until the [`Event::PaymentClaimed`]
@@ -1108,13 +1108,14 @@ impl_writeable_tlv_based!(ClaimingPayment, {
11081108
(4, receiver_node_id, required),
11091109
(5, htlcs, optional_vec),
11101110
(7, sender_intended_value, option),
1111-
(9, onion_fields, (option: ReadableArgs, amount_msat.0.unwrap())),
1111+
// onion_fields was added (and always set for new payments) in 0.0.124
1112+
(9, onion_fields, (required: ReadableArgs, amount_msat.0.unwrap())),
11121113
(11, payment_id, option),
11131114
});
11141115

11151116
struct ClaimablePayment {
11161117
purpose: events::PaymentPurpose,
1117-
onion_fields: Option<RecipientOnionFields>,
1118+
onion_fields: RecipientOnionFields,
11181119
htlcs: Vec<ClaimableHTLC>,
11191120
}
11201121

@@ -1237,12 +1238,11 @@ impl ClaimablePayments {
12371238
}
12381239
}
12391240

1240-
if let Some(RecipientOnionFields { custom_tlvs, .. }) = &payment.onion_fields {
1241-
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
1242-
log_info!(logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
1243-
&payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
1244-
return Err(payment.htlcs);
1245-
}
1241+
let custom_tlvs = &payment.onion_fields.custom_tlvs;
1242+
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
1243+
log_info!(logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
1244+
&payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
1245+
return Err(payment.htlcs);
12461246
}
12471247

12481248
let payment_id = payment.inbound_payment_id(inbound_payment_id_secret);
@@ -7954,20 +7954,20 @@ impl<
79547954
.or_insert_with(|| {
79557955
committed_to_claimable = true;
79567956
ClaimablePayment {
7957-
purpose: $purpose.clone(), htlcs: Vec::new(), onion_fields: None,
7957+
purpose: $purpose.clone(),
7958+
htlcs: Vec::new(),
7959+
onion_fields: onion_fields.clone(),
79587960
}
79597961
});
79607962
if $purpose != claimable_payment.purpose {
79617963
let log_keysend = |keysend| if keysend { "keysend" } else { "non-keysend" };
79627964
log_trace!(self.logger, "Failing new {} HTLC with payment_hash {} as we already had an existing {} HTLC with the same payment hash", log_keysend(is_keysend), &payment_hash, log_keysend(!is_keysend));
79637965
fail_htlc!(claimable_htlc, payment_hash);
79647966
}
7965-
if let Some(earlier_fields) = &mut claimable_payment.onion_fields {
7966-
if earlier_fields.check_merge(&mut onion_fields).is_err() {
7967-
fail_htlc!(claimable_htlc, payment_hash);
7968-
}
7969-
} else {
7970-
claimable_payment.onion_fields = Some(onion_fields);
7967+
let onions_compatible =
7968+
claimable_payment.onion_fields.check_merge(&mut onion_fields);
7969+
if onions_compatible.is_err() {
7970+
fail_htlc!(claimable_htlc, payment_hash);
79717971
}
79727972
let mut total_value = claimable_htlc.sender_intended_value;
79737973
let mut earliest_expiry = claimable_htlc.cltv_expiry;
@@ -8013,7 +8013,7 @@ impl<
80138013
counterparty_skimmed_fee_msat,
80148014
receiving_channel_ids: claimable_payment.receiving_channel_ids(),
80158015
claim_deadline: Some(earliest_expiry - HTLC_FAIL_BACK_BUFFER),
8016-
onion_fields: claimable_payment.onion_fields.clone(),
8016+
onion_fields: Some(claimable_payment.onion_fields.clone()),
80178017
payment_id: Some(payment_id),
80188018
}, None));
80198019
payment_claimable_generated = true;
@@ -9773,7 +9773,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
97739773
receiver_node_id: Some(receiver_node_id),
97749774
htlcs,
97759775
sender_intended_total_msat,
9776-
onion_fields,
9776+
onion_fields: Some(onion_fields),
97779777
payment_id,
97789778
};
97799779
let action = if let Some((outpoint, counterparty_node_id, channel_id)) =
@@ -17264,7 +17264,7 @@ impl<
1726417264
let pending_outbound_payments = self.pending_outbound_payments.pending_outbound_payments.lock().unwrap();
1726517265

1726617266
let mut htlc_purposes: Vec<&events::PaymentPurpose> = Vec::new();
17267-
let mut htlc_onion_fields: Vec<&_> = Vec::new();
17267+
let mut htlc_onion_fields: Vec<Option<&_>> = Vec::new();
1726817268
(claimable_payments.claimable_payments.len() as u64).write(writer)?;
1726917269
for (payment_hash, payment) in claimable_payments.claimable_payments.iter() {
1727017270
payment_hash.write(writer)?;
@@ -17273,7 +17273,7 @@ impl<
1727317273
htlc.write(writer)?;
1727417274
}
1727517275
htlc_purposes.push(&payment.purpose);
17276-
htlc_onion_fields.push(&payment.onion_fields);
17276+
htlc_onion_fields.push(Some(&payment.onion_fields));
1727717277
}
1727817278

1727917279
let mut monitor_update_blocked_actions_per_peer = None;
@@ -17552,7 +17552,6 @@ struct ChannelManagerDataReadArgs<
1755217552
L: Logger,
1755317553
> {
1755417554
entropy_source: &'a ES,
17555-
node_signer: &'a NS,
1755617555
signer_provider: &'a SP,
1755717556
config: UserConfig,
1755817557
logger: &'a L,
@@ -17789,10 +17788,7 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1778917788
// Resolve events_override: if present, it replaces pending_events.
1779017789
let pending_events_read = events_override.unwrap_or(pending_events_read);
1779117790

17792-
// Combine claimable_htlcs_list with their purposes and onion fields. For very old data
17793-
// (pre-0.0.107) that lacks purposes, reconstruct them from legacy hop data.
17794-
let expanded_inbound_key = args.node_signer.get_expanded_key();
17795-
17791+
// Combine claimable_htlcs_list with their purposes and onion fields.
1779617792
let mut claimable_payments = hash_map_with_capacity(claimable_htlcs_list.len());
1779717793
if let Some(purposes) = claimable_htlc_purposes {
1779817794
if purposes.len() != claimable_htlcs_list.len() {
@@ -17815,64 +17811,25 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1781517811
return Err(DecodeError::InvalidValue);
1781617812
}
1781717813
onion.0.total_mpp_amount_msat = htlcs_total_msat;
17818-
Some(onion.0)
17814+
onion.0
1781917815
} else {
17820-
None
17816+
return Err(DecodeError::InvalidValue);
1782117817
};
1782217818
let claimable = ClaimablePayment { purpose, htlcs, onion_fields };
1782317819
let existing_payment = claimable_payments.insert(payment_hash, claimable);
1782417820
if existing_payment.is_some() {
1782517821
return Err(DecodeError::InvalidValue);
1782617822
}
1782717823
}
17828-
} else {
17829-
for (purpose, (payment_hash, htlcs)) in
17830-
purposes.into_iter().zip(claimable_htlcs_list.into_iter())
17831-
{
17832-
let claimable = ClaimablePayment { purpose, htlcs, onion_fields: None };
17833-
let existing_payment = claimable_payments.insert(payment_hash, claimable);
17834-
if existing_payment.is_some() {
17835-
return Err(DecodeError::InvalidValue);
17836-
}
17837-
}
17824+
} else if !purposes.is_empty() || !claimable_htlcs_list.is_empty() {
17825+
// `amountless_claimable_htlc_onion_fields` was first written in LDK 0.0.115. We no
17826+
// haven't supported upgrade from 0.0.115 with pending HTLCs since 0.1.
17827+
return Err(DecodeError::InvalidValue);
1783817828
}
1783917829
} else {
1784017830
// LDK versions prior to 0.0.107 did not write a `pending_htlc_purposes`, but do
1784117831
// include a `_legacy_hop_data` in the `OnionPayload`.
17842-
for (payment_hash, htlcs) in claimable_htlcs_list.into_iter() {
17843-
if htlcs.is_empty() {
17844-
return Err(DecodeError::InvalidValue);
17845-
}
17846-
let purpose = match &htlcs[0].onion_payload {
17847-
OnionPayload::Invoice { _legacy_hop_data } => {
17848-
if let Some(hop_data) = _legacy_hop_data {
17849-
events::PaymentPurpose::Bolt11InvoicePayment {
17850-
payment_preimage: match inbound_payment::verify(
17851-
payment_hash,
17852-
&hop_data,
17853-
0,
17854-
&expanded_inbound_key,
17855-
&args.logger,
17856-
) {
17857-
Ok((payment_preimage, _)) => payment_preimage,
17858-
Err(()) => {
17859-
log_error!(args.logger, "Failed to read claimable payment data for HTLC with payment hash {} - was not a pending inbound payment and didn't match our payment key", &payment_hash);
17860-
return Err(DecodeError::InvalidValue);
17861-
},
17862-
},
17863-
payment_secret: hop_data.payment_secret,
17864-
}
17865-
} else {
17866-
return Err(DecodeError::InvalidValue);
17867-
}
17868-
},
17869-
OnionPayload::Spontaneous(payment_preimage) => {
17870-
events::PaymentPurpose::SpontaneousPayment(*payment_preimage)
17871-
},
17872-
};
17873-
claimable_payments
17874-
.insert(payment_hash, ClaimablePayment { purpose, htlcs, onion_fields: None });
17875-
}
17832+
return Err(DecodeError::InvalidValue);
1787617833
}
1787717834

1787817835
Ok(ChannelManagerData {
@@ -18145,7 +18102,6 @@ impl<
1814518102
reader,
1814618103
ChannelManagerDataReadArgs {
1814718104
entropy_source: &args.entropy_source,
18148-
node_signer: &args.node_signer,
1814918105
signer_provider: &args.signer_provider,
1815018106
config: args.config.clone(),
1815118107
logger: &args.logger,
@@ -19814,7 +19770,7 @@ impl<
1981419770
amount_msat: claimable_amt_msat,
1981519771
htlcs,
1981619772
sender_intended_total_msat,
19817-
onion_fields: payment.onion_fields,
19773+
onion_fields: Some(payment.onion_fields),
1981819774
payment_id: Some(payment_id),
1981919775
},
1982019776
// Note that we don't bother adding a EventCompletionAction here to

0 commit comments

Comments
 (0)