Skip to content

Commit 5427994

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 30d7f2d commit 5427994

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
}
@@ -1255,7 +1253,7 @@ impl ClaimablePayments {
12551253
})
12561254
.or_insert_with(|| {
12571255
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
1258-
let sender_intended_value = payment.htlcs.first().map(|htlc| htlc.total_msat);
1256+
let sender_intended_value = payment.onion_fields.total_mpp_amount_msat;
12591257
// Pick an "arbitrary" channel to block RAAs on until the `PaymentSent`
12601258
// event is processed, specifically the last channel to get claimed.
12611259
let durable_preimage_channel = payment.htlcs.last().map_or(None, |htlc| {
@@ -1271,7 +1269,7 @@ impl ClaimablePayments {
12711269
payment_purpose: payment.purpose,
12721270
receiver_node_id,
12731271
htlcs,
1274-
sender_intended_value,
1272+
sender_intended_value: Some(sender_intended_value),
12751273
onion_fields: payment.onion_fields,
12761274
payment_id: Some(payment_id),
12771275
durable_preimage_channel,
@@ -7884,11 +7882,6 @@ impl<
78847882
sender_intended_value: outgoing_amt_msat,
78857883
timer_ticks: 0,
78867884
total_value_received: None,
7887-
total_msat: if let Some(data) = &payment_data {
7888-
data.total_msat
7889-
} else {
7890-
outgoing_amt_msat
7891-
},
78927885
cltv_expiry,
78937886
onion_payload,
78947887
counterparty_skimmed_fee_msat: skimmed_fee_msat,
@@ -7969,27 +7962,25 @@ impl<
79697962
if onions_compatible.is_err() {
79707963
fail_htlc!(claimable_htlc, payment_hash);
79717964
}
7972-
let mut total_value = claimable_htlc.sender_intended_value;
7965+
let mut total_intended_recvd_value =
7966+
claimable_htlc.sender_intended_value;
79737967
let mut earliest_expiry = claimable_htlc.cltv_expiry;
79747968
for htlc in claimable_payment.htlcs.iter() {
7975-
total_value += htlc.sender_intended_value;
7969+
total_intended_recvd_value += htlc.sender_intended_value;
79767970
earliest_expiry = cmp::min(earliest_expiry, htlc.cltv_expiry);
7977-
if htlc.total_msat != claimable_htlc.total_msat {
7978-
log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})",
7979-
&payment_hash, claimable_htlc.total_msat, htlc.total_msat);
7980-
total_value = msgs::MAX_VALUE_MSAT;
7981-
}
7982-
if total_value >= msgs::MAX_VALUE_MSAT { break; }
7971+
if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT { break; }
79837972
}
7973+
let total_mpp_value =
7974+
claimable_payment.onion_fields.total_mpp_amount_msat;
79847975
// The condition determining whether an MPP is complete must
79857976
// match exactly the condition used in `timer_tick_occurred`
7986-
if total_value >= msgs::MAX_VALUE_MSAT {
7977+
if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT {
79877978
fail_htlc!(claimable_htlc, payment_hash);
7988-
} else if total_value - claimable_htlc.sender_intended_value >= claimable_htlc.total_msat {
7979+
} else if total_intended_recvd_value - claimable_htlc.sender_intended_value >= total_mpp_value {
79897980
log_trace!(self.logger, "Failing HTLC with payment_hash {} as payment is already claimable",
79907981
&payment_hash);
79917982
fail_htlc!(claimable_htlc, payment_hash);
7992-
} else if total_value >= claimable_htlc.total_msat {
7983+
} else if total_intended_recvd_value >= total_mpp_value {
79937984
#[allow(unused_assignments)] {
79947985
committed_to_claimable = true;
79957986
}
@@ -8000,8 +7991,8 @@ impl<
80007991
.for_each(|htlc| htlc.total_value_received = Some(amount_msat));
80017992
let counterparty_skimmed_fee_msat = claimable_payment.htlcs.iter()
80027993
.map(|htlc| htlc.counterparty_skimmed_fee_msat.unwrap_or(0)).sum();
8003-
debug_assert!(total_value.saturating_sub(amount_msat) <=
8004-
counterparty_skimmed_fee_msat);
7994+
debug_assert!(total_intended_recvd_value.saturating_sub(amount_msat)
7995+
<= counterparty_skimmed_fee_msat);
80057996
claimable_payment.htlcs.sort();
80067997
let payment_id =
80077998
claimable_payment.inbound_payment_id(&self.inbound_payment_id_secret);
@@ -8496,9 +8487,10 @@ impl<
84968487
// In this case we're not going to handle any timeouts of the parts here.
84978488
// This condition determining whether the MPP is complete here must match
84988489
// exactly the condition used in `process_pending_htlc_forwards`.
8499-
let htlc_total_msat =
8490+
let total_intended_recvd_value =
85008491
payment.htlcs.iter().map(|h| h.sender_intended_value).sum();
8501-
if payment.htlcs[0].total_msat <= htlc_total_msat {
8492+
let total_mpp_value = payment.onion_fields.total_mpp_amount_msat;
8493+
if total_mpp_value <= total_intended_recvd_value {
85028494
return true;
85038495
} else if payment.htlcs.iter_mut().any(|htlc| {
85048496
htlc.timer_ticks += 1;
@@ -8913,20 +8905,11 @@ impl<
89138905
// amount we told the user in the last `PaymentClaimable`. We also do a sanity-check that
89148906
// the MPP parts all have the same `total_msat`.
89158907
let mut claimable_amt_msat = 0;
8916-
let mut prev_total_msat = None;
89178908
let mut expected_amt_msat = None;
89188909
let mut valid_mpp = true;
89198910
let mut errs = Vec::new();
89208911
let per_peer_state = self.per_peer_state.read().unwrap();
89218912
for htlc in sources.iter() {
8922-
if prev_total_msat.is_some() && prev_total_msat != Some(htlc.total_msat) {
8923-
log_error!(self.logger, "Somehow ended up with an MPP payment with different expected total amounts - this should not be reachable!");
8924-
debug_assert!(false);
8925-
valid_mpp = false;
8926-
break;
8927-
}
8928-
prev_total_msat = Some(htlc.total_msat);
8929-
89308913
if expected_amt_msat.is_some() && expected_amt_msat != htlc.total_value_received {
89318914
log_error!(self.logger, "Somehow ended up with an MPP payment with different received total amounts - this should not be reachable!");
89328915
debug_assert!(false);
@@ -16937,28 +16920,28 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
1693716920
(13, trampoline_shared_secret, option),
1693816921
});
1693916922

16940-
impl Writeable for ClaimableHTLC {
16941-
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
16942-
let (payment_data, keysend_preimage) = match &self.onion_payload {
16943-
OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
16944-
OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
16945-
};
16946-
write_tlv_fields!(writer, {
16947-
(0, self.prev_hop, required),
16948-
(1, self.total_msat, required),
16949-
(2, self.value, required),
16950-
(3, self.sender_intended_value, required),
16951-
(4, payment_data, option),
16952-
(5, self.total_value_received, option),
16953-
(6, self.cltv_expiry, required),
16954-
(8, keysend_preimage, option),
16955-
(10, self.counterparty_skimmed_fee_msat, option),
16956-
});
16957-
Ok(())
16958-
}
16923+
fn write_claimable_htlc<W: Writer>(
16924+
htlc: &ClaimableHTLC, total_mpp_value_msat: u64, writer: &mut W,
16925+
) -> Result<(), io::Error> {
16926+
let (payment_data, keysend_preimage) = match &htlc.onion_payload {
16927+
OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
16928+
OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
16929+
};
16930+
write_tlv_fields!(writer, {
16931+
(0, htlc.prev_hop, required),
16932+
(1, total_mpp_value_msat, required),
16933+
(2, htlc.value, required),
16934+
(3, htlc.sender_intended_value, required),
16935+
(4, payment_data, option),
16936+
(5, htlc.total_value_received, option),
16937+
(6, htlc.cltv_expiry, required),
16938+
(8, keysend_preimage, option),
16939+
(10, htlc.counterparty_skimmed_fee_msat, option),
16940+
});
16941+
Ok(())
1695916942
}
1696016943

16961-
impl Readable for ClaimableHTLC {
16944+
impl Readable for (ClaimableHTLC, u64) {
1696216945
#[rustfmt::skip]
1696316946
fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
1696416947
_init_and_read_len_prefixed_tlv_fields!(reader, {
@@ -16994,17 +16977,16 @@ impl Readable for ClaimableHTLC {
1699416977
OnionPayload::Invoice { _legacy_hop_data: payment_data }
1699516978
},
1699616979
};
16997-
Ok(Self {
16980+
Ok((ClaimableHTLC {
1699816981
prev_hop: prev_hop.0.unwrap(),
1699916982
timer_ticks: 0,
1700016983
value,
1700116984
sender_intended_value: sender_intended_value.unwrap_or(value),
1700216985
total_value_received,
17003-
total_msat: total_msat.unwrap(),
1700416986
onion_payload,
1700516987
cltv_expiry: cltv_expiry.0.unwrap(),
1700616988
counterparty_skimmed_fee_msat,
17007-
})
16989+
}, total_msat.unwrap()))
1700816990
}
1700916991
}
1701016992

@@ -17270,7 +17252,7 @@ impl<
1727017252
payment_hash.write(writer)?;
1727117253
(payment.htlcs.len() as u64).write(writer)?;
1727217254
for htlc in payment.htlcs.iter() {
17273-
htlc.write(writer)?;
17255+
write_claimable_htlc(&htlc, payment.onion_fields.total_mpp_amount_msat, writer)?;
1727417256
}
1727517257
htlc_purposes.push(&payment.purpose);
1727617258
htlc_onion_fields.push(Some(&payment.onion_fields));
@@ -17544,24 +17526,18 @@ pub(super) struct ChannelManagerData<SP: SignerProvider> {
1754417526
}
1754517527

1754617528
/// Arguments for deserializing [`ChannelManagerData`].
17547-
struct ChannelManagerDataReadArgs<
17548-
'a,
17549-
ES: EntropySource,
17550-
NS: NodeSigner,
17551-
SP: SignerProvider,
17552-
L: Logger,
17553-
> {
17529+
struct ChannelManagerDataReadArgs<'a, ES: EntropySource, SP: SignerProvider, L: Logger> {
1755417530
entropy_source: &'a ES,
1755517531
signer_provider: &'a SP,
1755617532
config: UserConfig,
1755717533
logger: &'a L,
1755817534
}
1755917535

17560-
impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
17561-
ReadableArgs<ChannelManagerDataReadArgs<'a, ES, NS, SP, L>> for ChannelManagerData<SP>
17536+
impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
17537+
ReadableArgs<ChannelManagerDataReadArgs<'a, ES, SP, L>> for ChannelManagerData<SP>
1756217538
{
1756317539
fn read<R: io::Read>(
17564-
reader: &mut R, args: ChannelManagerDataReadArgs<'a, ES, NS, SP, L>,
17540+
reader: &mut R, args: ChannelManagerDataReadArgs<'a, ES, SP, L>,
1756517541
) -> Result<Self, DecodeError> {
1756617542
let version = read_ver_prefix!(reader, SERIALIZATION_VERSION);
1756717543

@@ -17616,10 +17592,20 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1761617592
previous_hops_len as usize,
1761717593
MAX_ALLOC_SIZE / mem::size_of::<ClaimableHTLC>(),
1761817594
));
17595+
let mut total_mpp_value_msat = None;
1761917596
for _ in 0..previous_hops_len {
17620-
previous_hops.push(<ClaimableHTLC as Readable>::read(reader)?);
17597+
let (htlc, total_mpp_value_msat_read) =
17598+
<(ClaimableHTLC, u64) as Readable>::read(reader)?;
17599+
if total_mpp_value_msat.is_some()
17600+
&& total_mpp_value_msat != Some(total_mpp_value_msat_read)
17601+
{
17602+
return Err(DecodeError::InvalidValue);
17603+
}
17604+
total_mpp_value_msat = Some(total_mpp_value_msat_read);
17605+
previous_hops.push(htlc);
1762117606
}
17622-
claimable_htlcs_list.push((payment_hash, previous_hops));
17607+
let total_mpp_value_msat = total_mpp_value_msat.ok_or(DecodeError::InvalidValue)?;
17608+
claimable_htlcs_list.push((payment_hash, previous_hops, total_mpp_value_msat));
1762317609
}
1762417610

1762517611
let peer_count: u64 = Readable::read(reader)?;
@@ -17798,19 +17784,17 @@ impl<'a, ES: EntropySource, NS: NodeSigner, SP: SignerProvider, L: Logger>
1779817784
if onion_fields.len() != claimable_htlcs_list.len() {
1779917785
return Err(DecodeError::InvalidValue);
1780017786
}
17801-
for (purpose, (onion, (payment_hash, htlcs))) in purposes
17787+
for (purpose, (onion, (payment_hash, htlcs, total_mpp_value_msat))) in purposes
1780217788
.into_iter()
1780317789
.zip(onion_fields.into_iter().zip(claimable_htlcs_list.into_iter()))
1780417790
{
17805-
let htlcs_total_msat =
17806-
htlcs.first().ok_or(DecodeError::InvalidValue)?.total_msat;
1780717791
let onion_fields = if let Some(mut onion) = onion {
1780817792
if onion.0.total_mpp_amount_msat != 0
17809-
&& onion.0.total_mpp_amount_msat != htlcs_total_msat
17793+
&& onion.0.total_mpp_amount_msat != total_mpp_value_msat
1781017794
{
1781117795
return Err(DecodeError::InvalidValue);
1781217796
}
17813-
onion.0.total_mpp_amount_msat = htlcs_total_msat;
17797+
onion.0.total_mpp_amount_msat = total_mpp_value_msat;
1781417798
onion.0
1781517799
} else {
1781617800
return Err(DecodeError::InvalidValue);
@@ -19760,16 +19744,15 @@ impl<
1976019744
let payment_id =
1976119745
payment.inbound_payment_id(&inbound_payment_id_secret.unwrap());
1976219746
let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
19763-
let sender_intended_total_msat =
19764-
payment.htlcs.first().map(|htlc| htlc.total_msat);
19747+
let sender_intended_total_msat = payment.onion_fields.total_mpp_amount_msat;
1976519748
pending_events.push_back((
1976619749
events::Event::PaymentClaimed {
1976719750
receiver_node_id,
1976819751
payment_hash,
1976919752
purpose: payment.purpose,
1977019753
amount_msat: claimable_amt_msat,
1977119754
htlcs,
19772-
sender_intended_total_msat,
19755+
sender_intended_total_msat: Some(sender_intended_total_msat),
1977319756
onion_fields: Some(payment.onion_fields),
1977419757
payment_id: Some(payment_id),
1977519758
},

0 commit comments

Comments
 (0)