Skip to content

Commit a28e7e6

Browse files
committed
Drop total_msat from individual ClaimableHTLCs
Now that we have `total_mpp_amount_msat` in the now-required `RecipientOnionFields` in `ClaimablePayment`s, the `total_msat` field in `ClaimableHTLC` is redundant. Given it was already awkward that we stored it in *each` `ClaimableHTLC` despite it being required to match in all of them, its good to drop it.
1 parent ed10776 commit a28e7e6

File tree

1 file changed

+58
-80
lines changed

1 file changed

+58
-80
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 58 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -539,8 +539,6 @@ struct ClaimableHTLC {
539539
/// The total value received for a payment (sum of all MPP parts if the payment is a MPP).
540540
/// Gets set to the amount reported when pushing [`Event::PaymentClaimable`].
541541
total_value_received: Option<u64>,
542-
/// The sender intended sum total of all MPP parts specified in the onion
543-
total_msat: u64,
544542
/// The extra fee our counterparty skimmed off the top of this HTLC.
545543
counterparty_skimmed_fee_msat: Option<u64>,
546544
}
@@ -1272,7 +1270,7 @@ impl ClaimablePayments {
12721270
})
12731271
.or_insert_with(|| {
12741272
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
1275-
let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
1273+
let sender_intended_value = payment.onion_fields.total_mpp_amount_msat;
12761274
// Pick an "arbitrary" channel to block RAAs on until the `PaymentSent`
12771275
// event is processed, specifically the last channel to get claimed.
12781276
let durable_preimage_channel = payment.htlcs.last().map_or(None, |htlc| {
@@ -1288,7 +1286,7 @@ impl ClaimablePayments {
12881286
payment_purpose: payment.purpose,
12891287
receiver_node_id,
12901288
htlcs,
1291-
sender_intended_value,
1289+
sender_intended_value: Some(sender_intended_value),
12921290
onion_fields: payment.onion_fields,
12931291
payment_id: Some(payment_id),
12941292
durable_preimage_channel,
@@ -8013,11 +8011,6 @@ impl<
80138011
sender_intended_value: outgoing_amt_msat,
80148012
timer_ticks: 0,
80158013
total_value_received: None,
8016-
total_msat: if let Some(data) = &payment_data {
8017-
data.total_msat
8018-
} else {
8019-
outgoing_amt_msat
8020-
},
80218014
cltv_expiry,
80228015
onion_payload,
80238016
counterparty_skimmed_fee_msat: skimmed_fee_msat,
@@ -8098,27 +8091,25 @@ impl<
80988091
if onions_compatible.is_err() {
80998092
fail_htlc!(claimable_htlc, payment_hash);
81008093
}
8101-
let mut total_value = claimable_htlc.sender_intended_value;
8094+
let mut total_intended_recvd_value =
8095+
claimable_htlc.sender_intended_value;
81028096
let mut earliest_expiry = claimable_htlc.cltv_expiry;
81038097
for htlc in claimable_payment.htlcs.iter() {
8104-
total_value += htlc.sender_intended_value;
8098+
total_intended_recvd_value += htlc.sender_intended_value;
81058099
earliest_expiry = cmp::min(earliest_expiry, htlc.cltv_expiry);
8106-
if htlc.total_msat != claimable_htlc.total_msat {
8107-
log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})",
8108-
&payment_hash, claimable_htlc.total_msat, htlc.total_msat);
8109-
total_value = msgs::MAX_VALUE_MSAT;
8110-
}
8111-
if total_value >= msgs::MAX_VALUE_MSAT { break; }
8100+
if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT { break; }
81128101
}
8102+
let total_mpp_value =
8103+
claimable_payment.onion_fields.total_mpp_amount_msat;
81138104
// The condition determining whether an MPP is complete must
81148105
// match exactly the condition used in `timer_tick_occurred`
8115-
if total_value >= msgs::MAX_VALUE_MSAT {
8106+
if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT {
81168107
fail_htlc!(claimable_htlc, payment_hash);
8117-
} else if total_value - claimable_htlc.sender_intended_value >= claimable_htlc.total_msat {
8108+
} else if total_intended_recvd_value - claimable_htlc.sender_intended_value >= total_mpp_value {
81188109
log_trace!(self.logger, "Failing HTLC with payment_hash {} as payment is already claimable",
81198110
&payment_hash);
81208111
fail_htlc!(claimable_htlc, payment_hash);
8121-
} else if total_value >= claimable_htlc.total_msat {
8112+
} else if total_intended_recvd_value >= total_mpp_value {
81228113
#[allow(unused_assignments)] {
81238114
committed_to_claimable = true;
81248115
}
@@ -8129,8 +8120,8 @@ impl<
81298120
.for_each(|htlc| htlc.total_value_received = Some(amount_msat));
81308121
let counterparty_skimmed_fee_msat = claimable_payment.htlcs.iter()
81318122
.map(|htlc| htlc.counterparty_skimmed_fee_msat.unwrap_or(0)).sum();
8132-
debug_assert!(total_value.saturating_sub(amount_msat) <=
8133-
counterparty_skimmed_fee_msat);
8123+
debug_assert!(total_intended_recvd_value.saturating_sub(amount_msat)
8124+
<= counterparty_skimmed_fee_msat);
81348125
claimable_payment.htlcs.sort();
81358126
let payment_id =
81368127
claimable_payment.inbound_payment_id(&self.inbound_payment_id_secret);
@@ -8592,9 +8583,10 @@ impl<
85928583
// In this case we're not going to handle any timeouts of the parts here.
85938584
// This condition determining whether the MPP is complete here must match
85948585
// exactly the condition used in `process_pending_htlc_forwards`.
8595-
let htlc_total_msat =
8586+
let total_intended_recvd_value =
85968587
payment.htlcs.iter().map(|h| h.sender_intended_value).sum();
8597-
if payment.htlcs[0].total_msat <= htlc_total_msat {
8588+
let total_mpp_value = payment.onion_fields.total_mpp_amount_msat;
8589+
if total_mpp_value <= total_intended_recvd_value {
85988590
return true;
85998591
} else if payment.htlcs.iter_mut().any(|htlc| {
86008592
htlc.timer_ticks += 1;
@@ -9009,20 +9001,11 @@ impl<
90099001
// amount we told the user in the last `PaymentClaimable`. We also do a sanity-check that
90109002
// the MPP parts all have the same `total_msat`.
90119003
let mut claimable_amt_msat = 0;
9012-
let mut prev_total_msat = None;
90139004
let mut expected_amt_msat = None;
90149005
let mut valid_mpp = true;
90159006
let mut errs = Vec::new();
90169007
let per_peer_state = self.per_peer_state.read().unwrap();
90179008
for htlc in sources.iter() {
9018-
if prev_total_msat.is_some() && prev_total_msat != Some(htlc.total_msat) {
9019-
log_error!(self.logger, "Somehow ended up with an MPP payment with different expected total amounts - this should not be reachable!");
9020-
debug_assert!(false);
9021-
valid_mpp = false;
9022-
break;
9023-
}
9024-
prev_total_msat = Some(htlc.total_msat);
9025-
90269009
if expected_amt_msat.is_some() && expected_amt_msat != htlc.total_value_received {
90279010
log_error!(self.logger, "Somehow ended up with an MPP payment with different received total amounts - this should not be reachable!");
90289011
debug_assert!(false);
@@ -17014,33 +16997,33 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
1701416997
(13, trampoline_shared_secret, option),
1701516998
});
1701616999

17017-
impl Writeable for ClaimableHTLC {
17018-
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
17019-
let (payment_data, keysend_preimage) = match &self.onion_payload {
17020-
OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
17021-
OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
17022-
};
17023-
write_tlv_fields!(writer, {
17024-
(0, self.prev_hop, required),
17025-
(1, self.total_msat, required),
17026-
(2, self.value, required),
17027-
(3, self.sender_intended_value, required),
17028-
(4, payment_data, option),
17029-
(5, self.total_value_received, option),
17030-
(6, self.cltv_expiry, required),
17031-
(8, keysend_preimage, option),
17032-
(10, self.counterparty_skimmed_fee_msat, option),
17033-
});
17034-
Ok(())
17035-
}
17000+
fn write_claimable_htlc<W: Writer>(
17001+
htlc: &ClaimableHTLC, total_mpp_value_msat: u64, writer: &mut W,
17002+
) -> Result<(), io::Error> {
17003+
let (payment_data, keysend_preimage) = match &htlc.onion_payload {
17004+
OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
17005+
OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
17006+
};
17007+
write_tlv_fields!(writer, {
17008+
(0, htlc.prev_hop, required),
17009+
(1, total_mpp_value_msat, required),
17010+
(2, htlc.value, required),
17011+
(3, htlc.sender_intended_value, required),
17012+
(4, payment_data, option),
17013+
(5, htlc.total_value_received, option),
17014+
(6, htlc.cltv_expiry, required),
17015+
(8, keysend_preimage, option),
17016+
(10, htlc.counterparty_skimmed_fee_msat, option),
17017+
});
17018+
Ok(())
1703617019
}
1703717020

17038-
impl Readable for ClaimableHTLC {
17021+
impl Readable for (ClaimableHTLC, u64) {
1703917022
#[rustfmt::skip]
1704017023
fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
1704117024
_init_and_read_len_prefixed_tlv_fields!(reader, {
1704217025
(0, prev_hop, required),
17043-
(1, total_msat, option),
17026+
(1, total_msat, required), // Added and always written in 0.0.107
1704417027
(2, value_ser, required),
1704517028
(3, sender_intended_value, option),
1704617029
(4, payment_data_opt, option),
@@ -17056,32 +17039,20 @@ impl Readable for ClaimableHTLC {
1705617039
if payment_data.is_some() {
1705717040
return Err(DecodeError::InvalidValue)
1705817041
}
17059-
if total_msat.is_none() {
17060-
total_msat = Some(value);
17061-
}
1706217042
OnionPayload::Spontaneous(p)
1706317043
},
17064-
None => {
17065-
if total_msat.is_none() {
17066-
if payment_data.is_none() {
17067-
return Err(DecodeError::InvalidValue)
17068-
}
17069-
total_msat = Some(payment_data.as_ref().unwrap().total_msat);
17070-
}
17071-
OnionPayload::Invoice { _legacy_hop_data: payment_data }
17072-
},
17044+
None => OnionPayload::Invoice { _legacy_hop_data: payment_data },
1707317045
};
17074-
Ok(Self {
17046+
Ok((ClaimableHTLC {
1707517047
prev_hop: prev_hop.0.unwrap(),
1707617048
timer_ticks: 0,
1707717049
value,
1707817050
sender_intended_value: sender_intended_value.unwrap_or(value),
1707917051
total_value_received,
17080-
total_msat: total_msat.unwrap(),
1708117052
onion_payload,
1708217053
cltv_expiry: cltv_expiry.0.unwrap(),
1708317054
counterparty_skimmed_fee_msat,
17084-
})
17055+
}, total_msat.0.expect("required field")))
1708517056
}
1708617057
}
1708717058

@@ -17347,7 +17318,7 @@ impl<
1734717318
payment_hash.write(writer)?;
1734817319
(payment.htlcs.len() as u64).write(writer)?;
1734917320
for htlc in payment.htlcs.iter() {
17350-
htlc.write(writer)?;
17321+
write_claimable_htlc(&htlc, payment.onion_fields.total_mpp_amount_msat, writer)?;
1735117322
}
1735217323
htlc_purposes.push(&payment.purpose);
1735317324
htlc_onion_fields.push(Some(&payment.onion_fields));
@@ -17687,10 +17658,20 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1768717658
previous_hops_len as usize,
1768817659
MAX_ALLOC_SIZE / mem::size_of::<ClaimableHTLC>(),
1768917660
));
17661+
let mut total_mpp_value_msat = None;
1769017662
for _ in 0..previous_hops_len {
17691-
previous_hops.push(<ClaimableHTLC as Readable>::read(reader)?);
17663+
let (htlc, total_mpp_value_msat_read) =
17664+
<(ClaimableHTLC, u64) as Readable>::read(reader)?;
17665+
if total_mpp_value_msat.is_some()
17666+
&& total_mpp_value_msat != Some(total_mpp_value_msat_read)
17667+
{
17668+
return Err(DecodeError::InvalidValue);
17669+
}
17670+
total_mpp_value_msat = Some(total_mpp_value_msat_read);
17671+
previous_hops.push(htlc);
1769217672
}
17693-
claimable_htlcs_list.push((payment_hash, previous_hops));
17673+
let total_mpp_value_msat = total_mpp_value_msat.ok_or(DecodeError::InvalidValue)?;
17674+
claimable_htlcs_list.push((payment_hash, previous_hops, total_mpp_value_msat));
1769417675
}
1769517676

1769617677
let peer_count: u64 = Readable::read(reader)?;
@@ -17869,19 +17850,17 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1786917850
if onion_fields.len() != claimable_htlcs_list.len() {
1787017851
return Err(DecodeError::InvalidValue);
1787117852
}
17872-
for (purpose, (onion, (payment_hash, htlcs))) in purposes
17853+
for (purpose, (onion, (payment_hash, htlcs, total_mpp_value_msat))) in purposes
1787317854
.into_iter()
1787417855
.zip(onion_fields.into_iter().zip(claimable_htlcs_list.into_iter()))
1787517856
{
17876-
let htlcs_total_msat =
17877-
htlcs.first().ok_or(DecodeError::InvalidValue)?.total_msat;
1787817857
let onion_fields = if let Some(mut onion) = onion {
1787917858
if onion.0.total_mpp_amount_msat != 0
17880-
&& onion.0.total_mpp_amount_msat != htlcs_total_msat
17859+
&& onion.0.total_mpp_amount_msat != total_mpp_value_msat
1788117860
{
1788217861
return Err(DecodeError::InvalidValue);
1788317862
}
17884-
onion.0.total_mpp_amount_msat = htlcs_total_msat;
17863+
onion.0.total_mpp_amount_msat = total_mpp_value_msat;
1788517864
onion.0
1788617865
} else {
1788717866
return Err(DecodeError::InvalidValue);
@@ -19831,16 +19810,15 @@ impl<
1983119810
let payment_id =
1983219811
payment.inbound_payment_id(&inbound_payment_id_secret.unwrap());
1983319812
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
19834-
let sender_intended_total_msat =
19835-
payment.htlcs.first().map(|htlc| htlc.total_msat);
19813+
let sender_intended_total_msat = payment.onion_fields.total_mpp_amount_msat;
1983619814
pending_events.push_back((
1983719815
events::Event::PaymentClaimed {
1983819816
receiver_node_id,
1983919817
payment_hash,
1984019818
purpose: payment.purpose,
1984119819
amount_msat: claimable_amt_msat,
1984219820
htlcs,
19843-
sender_intended_total_msat,
19821+
sender_intended_total_msat: Some(sender_intended_total_msat),
1984419822
onion_fields: Some(payment.onion_fields),
1984519823
payment_id: Some(payment_id),
1984619824
},

0 commit comments

Comments
 (0)