Skip to content

Commit aaf4450

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 ca2f31d commit aaf4450

File tree

1 file changed

+60
-77
lines changed

1 file changed

+60
-77
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 60 additions & 77 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
}
@@ -1240,7 +1238,7 @@ impl ClaimablePayments {
12401238
})
12411239
.or_insert_with(|| {
12421240
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
1243-
let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
1241+
let sender_intended_value = payment.onion_fields.total_mpp_amount_msat;
12441242
// Pick an "arbitrary" channel to block RAAs on until the `PaymentSent`
12451243
// event is processed, specifically the last channel to get claimed.
12461244
let durable_preimage_channel = payment.htlcs.last().map_or(None, |htlc| {
@@ -1256,7 +1254,7 @@ impl ClaimablePayments {
12561254
payment_purpose: payment.purpose,
12571255
receiver_node_id,
12581256
htlcs,
1259-
sender_intended_value,
1257+
sender_intended_value: Some(sender_intended_value),
12601258
onion_fields: payment.onion_fields,
12611259
payment_id: Some(payment_id),
12621260
durable_preimage_channel,
@@ -7896,11 +7894,6 @@ impl<
78967894
sender_intended_value: outgoing_amt_msat,
78977895
timer_ticks: 0,
78987896
total_value_received: None,
7899-
total_msat: if let Some(data) = &payment_data {
7900-
data.total_msat
7901-
} else {
7902-
outgoing_amt_msat
7903-
},
79047897
cltv_expiry,
79057898
onion_payload,
79067899
counterparty_skimmed_fee_msat: skimmed_fee_msat,
@@ -7981,27 +7974,25 @@ impl<
79817974
if onions_compatible.is_err() {
79827975
fail_htlc!(claimable_htlc, payment_hash);
79837976
}
7984-
let mut total_value = claimable_htlc.sender_intended_value;
7977+
let mut total_intended_recvd_value =
7978+
claimable_htlc.sender_intended_value;
79857979
let mut earliest_expiry = claimable_htlc.cltv_expiry;
79867980
for htlc in claimable_payment.htlcs.iter() {
7987-
total_value += htlc.sender_intended_value;
7981+
total_intended_recvd_value += htlc.sender_intended_value;
79887982
earliest_expiry = cmp::min(earliest_expiry, htlc.cltv_expiry);
7989-
if htlc.total_msat != claimable_htlc.total_msat {
7990-
log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})",
7991-
&payment_hash, claimable_htlc.total_msat, htlc.total_msat);
7992-
total_value = msgs::MAX_VALUE_MSAT;
7993-
}
7994-
if total_value >= msgs::MAX_VALUE_MSAT { break; }
7983+
if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT { break; }
79957984
}
7985+
let total_mpp_value =
7986+
claimable_payment.onion_fields.total_mpp_amount_msat;
79967987
// The condition determining whether an MPP is complete must
79977988
// match exactly the condition used in `timer_tick_occurred`
7998-
if total_value >= msgs::MAX_VALUE_MSAT {
7989+
if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT {
79997990
fail_htlc!(claimable_htlc, payment_hash);
8000-
} else if total_value - claimable_htlc.sender_intended_value >= claimable_htlc.total_msat {
7991+
} else if total_intended_recvd_value - claimable_htlc.sender_intended_value >= total_mpp_value {
80017992
log_trace!(self.logger, "Failing HTLC with payment_hash {} as payment is already claimable",
80027993
&payment_hash);
80037994
fail_htlc!(claimable_htlc, payment_hash);
8004-
} else if total_value >= claimable_htlc.total_msat {
7995+
} else if total_intended_recvd_value >= total_mpp_value {
80057996
#[allow(unused_assignments)] {
80067997
committed_to_claimable = true;
80077998
}
@@ -8012,8 +8003,8 @@ impl<
80128003
.for_each(|htlc| htlc.total_value_received = Some(amount_msat));
80138004
let counterparty_skimmed_fee_msat = claimable_payment.htlcs.iter()
80148005
.map(|htlc| htlc.counterparty_skimmed_fee_msat.unwrap_or(0)).sum();
8015-
debug_assert!(total_value.saturating_sub(amount_msat) <=
8016-
counterparty_skimmed_fee_msat);
8006+
debug_assert!(total_intended_recvd_value.saturating_sub(amount_msat)
8007+
<= counterparty_skimmed_fee_msat);
80178008
claimable_payment.htlcs.sort();
80188009
let payment_id =
80198010
claimable_payment.inbound_payment_id(&self.inbound_payment_id_secret);
@@ -8508,9 +8499,10 @@ impl<
85088499
// In this case we're not going to handle any timeouts of the parts here.
85098500
// This condition determining whether the MPP is complete here must match
85108501
// exactly the condition used in `process_pending_htlc_forwards`.
8511-
let htlc_total_msat =
8502+
let total_intended_recvd_value =
85128503
payment.htlcs.iter().map(|h| h.sender_intended_value).sum();
8513-
if payment.htlcs[0].total_msat <= htlc_total_msat {
8504+
let total_mpp_value = payment.onion_fields.total_mpp_amount_msat;
8505+
if total_mpp_value <= total_intended_recvd_value {
85148506
return true;
85158507
} else if payment.htlcs.iter_mut().any(|htlc| {
85168508
htlc.timer_ticks += 1;
@@ -8925,20 +8917,11 @@ impl<
89258917
// amount we told the user in the last `PaymentClaimable`. We also do a sanity-check that
89268918
// the MPP parts all have the same `total_msat`.
89278919
let mut claimable_amt_msat = 0;
8928-
let mut prev_total_msat = None;
89298920
let mut expected_amt_msat = None;
89308921
let mut valid_mpp = true;
89318922
let mut errs = Vec::new();
89328923
let per_peer_state = self.per_peer_state.read().unwrap();
89338924
for htlc in sources.iter() {
8934-
if prev_total_msat.is_some() && prev_total_msat != Some(htlc.total_msat) {
8935-
log_error!(self.logger, "Somehow ended up with an MPP payment with different expected total amounts - this should not be reachable!");
8936-
debug_assert!(false);
8937-
valid_mpp = false;
8938-
break;
8939-
}
8940-
prev_total_msat = Some(htlc.total_msat);
8941-
89428925
if expected_amt_msat.is_some() && expected_amt_msat != htlc.total_value_received {
89438926
log_error!(self.logger, "Somehow ended up with an MPP payment with different received total amounts - this should not be reachable!");
89448927
debug_assert!(false);
@@ -16780,28 +16763,28 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
1678016763
(13, trampoline_shared_secret, option),
1678116764
});
1678216765

16783-
impl Writeable for ClaimableHTLC {
16784-
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
16785-
let (payment_data, keysend_preimage) = match &self.onion_payload {
16786-
OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
16787-
OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
16788-
};
16789-
write_tlv_fields!(writer, {
16790-
(0, self.prev_hop, required),
16791-
(1, self.total_msat, required),
16792-
(2, self.value, required),
16793-
(3, self.sender_intended_value, required),
16794-
(4, payment_data, option),
16795-
(5, self.total_value_received, option),
16796-
(6, self.cltv_expiry, required),
16797-
(8, keysend_preimage, option),
16798-
(10, self.counterparty_skimmed_fee_msat, option),
16799-
});
16800-
Ok(())
16801-
}
16766+
fn write_claimable_htlc<W: Writer>(
16767+
htlc: &ClaimableHTLC, total_mpp_value_msat: u64, writer: &mut W,
16768+
) -> Result<(), io::Error> {
16769+
let (payment_data, keysend_preimage) = match &htlc.onion_payload {
16770+
OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
16771+
OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
16772+
};
16773+
write_tlv_fields!(writer, {
16774+
(0, htlc.prev_hop, required),
16775+
(1, total_mpp_value_msat, required),
16776+
(2, htlc.value, required),
16777+
(3, htlc.sender_intended_value, required),
16778+
(4, payment_data, option),
16779+
(5, htlc.total_value_received, option),
16780+
(6, htlc.cltv_expiry, required),
16781+
(8, keysend_preimage, option),
16782+
(10, htlc.counterparty_skimmed_fee_msat, option),
16783+
});
16784+
Ok(())
1680216785
}
1680316786

16804-
impl Readable for ClaimableHTLC {
16787+
impl Readable for (ClaimableHTLC, u64) {
1680516788
#[rustfmt::skip]
1680616789
fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
1680716790
_init_and_read_len_prefixed_tlv_fields!(reader, {
@@ -16837,17 +16820,16 @@ impl Readable for ClaimableHTLC {
1683716820
OnionPayload::Invoice { _legacy_hop_data: payment_data }
1683816821
},
1683916822
};
16840-
Ok(Self {
16823+
Ok((ClaimableHTLC {
1684116824
prev_hop: prev_hop.0.unwrap(),
1684216825
timer_ticks: 0,
1684316826
value,
1684416827
sender_intended_value: sender_intended_value.unwrap_or(value),
1684516828
total_value_received,
16846-
total_msat: total_msat.unwrap(),
1684716829
onion_payload,
1684816830
cltv_expiry: cltv_expiry.0.unwrap(),
1684916831
counterparty_skimmed_fee_msat,
16850-
})
16832+
}, total_msat.unwrap()))
1685116833
}
1685216834
}
1685316835

@@ -17113,7 +17095,7 @@ impl<
1711317095
payment_hash.write(writer)?;
1711417096
(payment.htlcs.len() as u64).write(writer)?;
1711517097
for htlc in payment.htlcs.iter() {
17116-
htlc.write(writer)?;
17098+
write_claimable_htlc(&htlc, payment.onion_fields.total_mpp_amount_msat, writer)?;
1711717099
}
1711817100
htlc_purposes.push(&payment.purpose);
1711917101
htlc_onion_fields.push(Some(&payment.onion_fields));
@@ -17387,24 +17369,18 @@ pub(super) struct ChannelManagerData<SP: SignerProvider> {
1738717369
}
1738817370

1738917371
/// Arguments for deserializing [`ChannelManagerData`].
17390-
struct ChannelManagerDataReadArgs<
17391-
'a,
17392-
ES: EntropySource,
17393-
NS: NodeSigner,
17394-
SP: SignerProvider,
17395-
L: Logger,
17396-
> {
17372+
struct ChannelManagerDataReadArgs<'a, ES: EntropySource, SP: SignerProvider, L: Logger> {
1739717373
entropy_source: &'a ES,
1739817374
signer_provider: &'a SP,
1739917375
config: UserConfig,
1740017376
logger: &'a L,
1740117377
}
1740217378

17403-
impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
17404-
ReadableArgs<ChannelManagerDataReadArgs<'a, ES, NS, SP, L>> for ChannelManagerData<SP>
17379+
impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
17380+
ReadableArgs<ChannelManagerDataReadArgs<'a, ES, SP, L>> for ChannelManagerData<SP>
1740517381
{
1740617382
fn read<R: io::Read>(
17407-
reader: &mut R, args: ChannelManagerDataReadArgs<'a, ES, NS, SP, L>,
17383+
reader: &mut R, args: ChannelManagerDataReadArgs<'a, ES, SP, L>,
1740817384
) -> Result<Self, DecodeError> {
1740917385
let version = read_ver_prefix!(reader, SERIALIZATION_VERSION);
1741017386

@@ -17459,10 +17435,20 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1745917435
previous_hops_len as usize,
1746017436
MAX_ALLOC_SIZE / mem::size_of::<ClaimableHTLC>(),
1746117437
));
17438+
let mut total_mpp_value_msat = None;
1746217439
for _ in 0..previous_hops_len {
17463-
previous_hops.push(<ClaimableHTLC as Readable>::read(reader)?);
17440+
let (htlc, total_mpp_value_msat_read) =
17441+
<(ClaimableHTLC, u64) as Readable>::read(reader)?;
17442+
if total_mpp_value_msat.is_some()
17443+
&& total_mpp_value_msat != Some(total_mpp_value_msat_read)
17444+
{
17445+
return Err(DecodeError::InvalidValue);
17446+
}
17447+
total_mpp_value_msat = Some(total_mpp_value_msat_read);
17448+
previous_hops.push(htlc);
1746417449
}
17465-
claimable_htlcs_list.push((payment_hash, previous_hops));
17450+
let total_mpp_value_msat = total_mpp_value_msat.ok_or(DecodeError::InvalidValue)?;
17451+
claimable_htlcs_list.push((payment_hash, previous_hops, total_mpp_value_msat));
1746617452
}
1746717453

1746817454
let peer_count: u64 = Readable::read(reader)?;
@@ -17641,19 +17627,17 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1764117627
if onion_fields.len() != claimable_htlcs_list.len() {
1764217628
return Err(DecodeError::InvalidValue);
1764317629
}
17644-
for (purpose, (onion, (payment_hash, htlcs))) in purposes
17630+
for (purpose, (onion, (payment_hash, htlcs, total_mpp_value_msat))) in purposes
1764517631
.into_iter()
1764617632
.zip(onion_fields.into_iter().zip(claimable_htlcs_list.into_iter()))
1764717633
{
17648-
let htlcs_total_msat =
17649-
htlcs.first().ok_or(DecodeError::InvalidValue)?.total_msat;
1765017634
let onion_fields = if let Some(mut onion) = onion {
1765117635
if onion.0.total_mpp_amount_msat != 0
17652-
&& onion.0.total_mpp_amount_msat != htlcs_total_msat
17636+
&& onion.0.total_mpp_amount_msat != total_mpp_value_msat
1765317637
{
1765417638
return Err(DecodeError::InvalidValue);
1765517639
}
17656-
onion.0.total_mpp_amount_msat = htlcs_total_msat;
17640+
onion.0.total_mpp_amount_msat = total_mpp_value_msat;
1765717641
onion.0
1765817642
} else {
1765917643
return Err(DecodeError::InvalidValue);
@@ -19607,16 +19591,15 @@ impl<
1960719591
let payment_id =
1960819592
payment.inbound_payment_id(&inbound_payment_id_secret.unwrap());
1960919593
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
19610-
let sender_intended_total_msat =
19611-
payment.htlcs.first().map(|htlc| htlc.total_msat);
19594+
let sender_intended_total_msat = payment.onion_fields.total_mpp_amount_msat;
1961219595
pending_events.push_back((
1961319596
events::Event::PaymentClaimed {
1961419597
receiver_node_id,
1961519598
payment_hash,
1961619599
purpose: payment.purpose,
1961719600
amount_msat: claimable_amt_msat,
1961819601
htlcs,
19619-
sender_intended_total_msat,
19602+
sender_intended_total_msat: Some(sender_intended_total_msat),
1962019603
onion_fields: Some(payment.onion_fields),
1962119604
payment_id: Some(payment_id),
1962219605
},

0 commit comments

Comments
 (0)