Skip to content

Commit ca2f31d

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 6f811f3 commit ca2f31d

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
@@ -1074,7 +1074,7 @@ struct ClaimingPayment {
10741074
receiver_node_id: PublicKey,
10751075
htlcs: Vec<events::ClaimedHTLC>,
10761076
sender_intended_value: Option<u64>,
1077-
onion_fields: Option<RecipientOnionFields>,
1077+
onion_fields: RecipientOnionFields,
10781078
payment_id: Option<PaymentId>,
10791079
/// When we claim and generate a [`Event::PaymentClaimed`], we want to block any
10801080
/// payment-preimage-removing RAA [`ChannelMonitorUpdate`]s until the [`Event::PaymentClaimed`]
@@ -1093,13 +1093,14 @@ impl_writeable_tlv_based!(ClaimingPayment, {
10931093
(4, receiver_node_id, required),
10941094
(5, htlcs, optional_vec),
10951095
(7, sender_intended_value, option),
1096-
(9, onion_fields, (option: ReadableArgs, amount_msat.0.unwrap())),
1096+
// onion_fields was added (and always set for new payments) in 0.0.124
1097+
(9, onion_fields, (required: ReadableArgs, amount_msat.0.unwrap())),
10971098
(11, payment_id, option),
10981099
});
10991100

11001101
struct ClaimablePayment {
11011102
purpose: events::PaymentPurpose,
1102-
onion_fields: Option<RecipientOnionFields>,
1103+
onion_fields: RecipientOnionFields,
11031104
htlcs: Vec<ClaimableHTLC>,
11041105
}
11051106

@@ -1222,12 +1223,11 @@ impl ClaimablePayments {
12221223
}
12231224
}
12241225

1225-
if let Some(RecipientOnionFields { custom_tlvs, .. }) = &payment.onion_fields {
1226-
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
1227-
log_info!(logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
1228-
&payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
1229-
return Err(payment.htlcs);
1230-
}
1226+
let custom_tlvs = &payment.onion_fields.custom_tlvs;
1227+
if !custom_tlvs_known && custom_tlvs.iter().any(|(typ, _)| typ % 2 == 0) {
1228+
log_info!(logger, "Rejecting payment with payment hash {} as we cannot accept payment with unknown even TLVs: {}",
1229+
&payment_hash, log_iter!(custom_tlvs.iter().map(|(typ, _)| typ).filter(|typ| *typ % 2 == 0)));
1230+
return Err(payment.htlcs);
12311231
}
12321232

12331233
let payment_id = payment.inbound_payment_id(inbound_payment_id_secret);
@@ -7966,20 +7966,20 @@ impl<
79667966
.or_insert_with(|| {
79677967
committed_to_claimable = true;
79687968
ClaimablePayment {
7969-
purpose: $purpose.clone(), htlcs: Vec::new(), onion_fields: None,
7969+
purpose: $purpose.clone(),
7970+
htlcs: Vec::new(),
7971+
onion_fields: onion_fields.clone(),
79707972
}
79717973
});
79727974
if $purpose != claimable_payment.purpose {
79737975
let log_keysend = |keysend| if keysend { "keysend" } else { "non-keysend" };
79747976
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));
79757977
fail_htlc!(claimable_htlc, payment_hash);
79767978
}
7977-
if let Some(earlier_fields) = &mut claimable_payment.onion_fields {
7978-
if earlier_fields.check_merge(&mut onion_fields).is_err() {
7979-
fail_htlc!(claimable_htlc, payment_hash);
7980-
}
7981-
} else {
7982-
claimable_payment.onion_fields = Some(onion_fields);
7979+
let onions_compatible =
7980+
claimable_payment.onion_fields.check_merge(&mut onion_fields);
7981+
if onions_compatible.is_err() {
7982+
fail_htlc!(claimable_htlc, payment_hash);
79837983
}
79847984
let mut total_value = claimable_htlc.sender_intended_value;
79857985
let mut earliest_expiry = claimable_htlc.cltv_expiry;
@@ -8025,7 +8025,7 @@ impl<
80258025
counterparty_skimmed_fee_msat,
80268026
receiving_channel_ids: claimable_payment.receiving_channel_ids(),
80278027
claim_deadline: Some(earliest_expiry - HTLC_FAIL_BACK_BUFFER),
8028-
onion_fields: claimable_payment.onion_fields.clone(),
8028+
onion_fields: Some(claimable_payment.onion_fields.clone()),
80298029
payment_id: Some(payment_id),
80308030
}, None));
80318031
payment_claimable_generated = true;
@@ -9779,7 +9779,7 @@ This indicates a bug inside LDK. Please report this error at https://github.com/
97799779
receiver_node_id: Some(receiver_node_id),
97809780
htlcs,
97819781
sender_intended_total_msat,
9782-
onion_fields,
9782+
onion_fields: Some(onion_fields),
97839783
payment_id,
97849784
};
97859785
let action = if let Some((outpoint, counterparty_node_id, channel_id)) =
@@ -17107,7 +17107,7 @@ impl<
1710717107
let pending_outbound_payments = self.pending_outbound_payments.pending_outbound_payments.lock().unwrap();
1710817108

1710917109
let mut htlc_purposes: Vec<&events::PaymentPurpose> = Vec::new();
17110-
let mut htlc_onion_fields: Vec<&_> = Vec::new();
17110+
let mut htlc_onion_fields: Vec<Option<&_>> = Vec::new();
1711117111
(claimable_payments.claimable_payments.len() as u64).write(writer)?;
1711217112
for (payment_hash, payment) in claimable_payments.claimable_payments.iter() {
1711317113
payment_hash.write(writer)?;
@@ -17116,7 +17116,7 @@ impl<
1711617116
htlc.write(writer)?;
1711717117
}
1711817118
htlc_purposes.push(&payment.purpose);
17119-
htlc_onion_fields.push(&payment.onion_fields);
17119+
htlc_onion_fields.push(Some(&payment.onion_fields));
1712017120
}
1712117121

1712217122
let mut monitor_update_blocked_actions_per_peer = None;
@@ -17395,7 +17395,6 @@ struct ChannelManagerDataReadArgs<
1739517395
L: Logger,
1739617396
> {
1739717397
entropy_source: &'a ES,
17398-
node_signer: &'a NS,
1739917398
signer_provider: &'a SP,
1740017399
config: UserConfig,
1740117400
logger: &'a L,
@@ -17632,10 +17631,7 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1763217631
// Resolve events_override: if present, it replaces pending_events.
1763317632
let pending_events_read = events_override.unwrap_or(pending_events_read);
1763417633

17635-
// Combine claimable_htlcs_list with their purposes and onion fields. For very old data
17636-
// (pre-0.0.107) that lacks purposes, reconstruct them from legacy hop data.
17637-
let expanded_inbound_key = args.node_signer.get_expanded_key();
17638-
17634+
// Combine claimable_htlcs_list with their purposes and onion fields.
1763917635
let mut claimable_payments = hash_map_with_capacity(claimable_htlcs_list.len());
1764017636
if let Some(purposes) = claimable_htlc_purposes {
1764117637
if purposes.len() != claimable_htlcs_list.len() {
@@ -17658,64 +17654,25 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1765817654
return Err(DecodeError::InvalidValue);
1765917655
}
1766017656
onion.0.total_mpp_amount_msat = htlcs_total_msat;
17661-
Some(onion.0)
17657+
onion.0
1766217658
} else {
17663-
None
17659+
return Err(DecodeError::InvalidValue);
1766417660
};
1766517661
let claimable = ClaimablePayment { purpose, htlcs, onion_fields };
1766617662
let existing_payment = claimable_payments.insert(payment_hash, claimable);
1766717663
if existing_payment.is_some() {
1766817664
return Err(DecodeError::InvalidValue);
1766917665
}
1767017666
}
17671-
} else {
17672-
for (purpose, (payment_hash, htlcs)) in
17673-
purposes.into_iter().zip(claimable_htlcs_list.into_iter())
17674-
{
17675-
let claimable = ClaimablePayment { purpose, htlcs, onion_fields: None };
17676-
let existing_payment = claimable_payments.insert(payment_hash, claimable);
17677-
if existing_payment.is_some() {
17678-
return Err(DecodeError::InvalidValue);
17679-
}
17680-
}
17667+
} else if !purposes.is_empty() || !claimable_htlcs_list.is_empty() {
17668+
// `amountless_claimable_htlc_onion_fields` was first written in LDK 0.0.115. We no
17669+
// haven't supported upgrade from 0.0.115 with pending HTLCs since 0.1.
17670+
return Err(DecodeError::InvalidValue);
1768117671
}
1768217672
} else {
1768317673
// LDK versions prior to 0.0.107 did not write a `pending_htlc_purposes`, but do
1768417674
// include a `_legacy_hop_data` in the `OnionPayload`.
17685-
for (payment_hash, htlcs) in claimable_htlcs_list.into_iter() {
17686-
if htlcs.is_empty() {
17687-
return Err(DecodeError::InvalidValue);
17688-
}
17689-
let purpose = match &htlcs[0].onion_payload {
17690-
OnionPayload::Invoice { _legacy_hop_data } => {
17691-
if let Some(hop_data) = _legacy_hop_data {
17692-
events::PaymentPurpose::Bolt11InvoicePayment {
17693-
payment_preimage: match inbound_payment::verify(
17694-
payment_hash,
17695-
&hop_data,
17696-
0,
17697-
&expanded_inbound_key,
17698-
&args.logger,
17699-
) {
17700-
Ok((payment_preimage, _)) => payment_preimage,
17701-
Err(()) => {
17702-
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);
17703-
return Err(DecodeError::InvalidValue);
17704-
},
17705-
},
17706-
payment_secret: hop_data.payment_secret,
17707-
}
17708-
} else {
17709-
return Err(DecodeError::InvalidValue);
17710-
}
17711-
},
17712-
OnionPayload::Spontaneous(payment_preimage) => {
17713-
events::PaymentPurpose::SpontaneousPayment(*payment_preimage)
17714-
},
17715-
};
17716-
claimable_payments
17717-
.insert(payment_hash, ClaimablePayment { purpose, htlcs, onion_fields: None });
17718-
}
17675+
return Err(DecodeError::InvalidValue);
1771917676
}
1772017677

1772117678
Ok(ChannelManagerData {
@@ -17988,7 +17945,6 @@ impl<
1798817945
reader,
1798917946
ChannelManagerDataReadArgs {
1799017947
entropy_source: &args.entropy_source,
17991-
node_signer: &args.node_signer,
1799217948
signer_provider: &args.signer_provider,
1799317949
config: args.config.clone(),
1799417950
logger: &args.logger,
@@ -19661,7 +19617,7 @@ impl<
1966119617
amount_msat: claimable_amt_msat,
1966219618
htlcs,
1966319619
sender_intended_total_msat,
19664-
onion_fields: payment.onion_fields,
19620+
onion_fields: Some(payment.onion_fields),
1966519621
payment_id: Some(payment_id),
1966619622
},
1966719623
// Note that we don't bother adding a EventCompletionAction here to

0 commit comments

Comments
 (0)