@@ -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,
@@ -7885,11 +7883,6 @@ impl<
78857883 sender_intended_value: outgoing_amt_msat,
78867884 timer_ticks: 0,
78877885 total_value_received: None,
7888- total_msat: if let Some(data) = &payment_data {
7889- data.total_msat
7890- } else {
7891- outgoing_amt_msat
7892- },
78937886 cltv_expiry,
78947887 onion_payload,
78957888 counterparty_skimmed_fee_msat: skimmed_fee_msat,
@@ -7970,27 +7963,25 @@ impl<
79707963 if onions_compatible.is_err() {
79717964 fail_htlc!(claimable_htlc, payment_hash);
79727965 }
7973- let mut total_value = claimable_htlc.sender_intended_value;
7966+ let mut total_intended_recvd_value =
7967+ claimable_htlc.sender_intended_value;
79747968 let mut earliest_expiry = claimable_htlc.cltv_expiry;
79757969 for htlc in claimable_payment.htlcs.iter() {
7976- total_value += htlc.sender_intended_value;
7970+ total_intended_recvd_value += htlc.sender_intended_value;
79777971 earliest_expiry = cmp::min(earliest_expiry, htlc.cltv_expiry);
7978- if htlc.total_msat != claimable_htlc.total_msat {
7979- log_trace!(self.logger, "Failing HTLCs with payment_hash {} as the HTLCs had inconsistent total values (eg {} and {})",
7980- &payment_hash, claimable_htlc.total_msat, htlc.total_msat);
7981- total_value = msgs::MAX_VALUE_MSAT;
7982- }
7983- if total_value >= msgs::MAX_VALUE_MSAT { break; }
7972+ if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT { break; }
79847973 }
7974+ let total_mpp_value =
7975+ claimable_payment.onion_fields.total_mpp_amount_msat;
79857976 // The condition determining whether an MPP is complete must
79867977 // match exactly the condition used in `timer_tick_occurred`
7987- if total_value >= msgs::MAX_VALUE_MSAT {
7978+ if total_intended_recvd_value >= msgs::MAX_VALUE_MSAT {
79887979 fail_htlc!(claimable_htlc, payment_hash);
7989- } else if total_value - claimable_htlc.sender_intended_value >= claimable_htlc.total_msat {
7980+ } else if total_intended_recvd_value - claimable_htlc.sender_intended_value >= total_mpp_value {
79907981 log_trace!(self.logger, "Failing HTLC with payment_hash {} as payment is already claimable",
79917982 &payment_hash);
79927983 fail_htlc!(claimable_htlc, payment_hash);
7993- } else if total_value >= claimable_htlc.total_msat {
7984+ } else if total_intended_recvd_value >= total_mpp_value {
79947985 #[allow(unused_assignments)] {
79957986 committed_to_claimable = true;
79967987 }
@@ -8001,8 +7992,8 @@ impl<
80017992 .for_each(|htlc| htlc.total_value_received = Some(amount_msat));
80027993 let counterparty_skimmed_fee_msat = claimable_payment.htlcs.iter()
80037994 .map(|htlc| htlc.counterparty_skimmed_fee_msat.unwrap_or(0)).sum();
8004- debug_assert!(total_value .saturating_sub(amount_msat) <=
8005- counterparty_skimmed_fee_msat);
7995+ debug_assert!(total_intended_recvd_value .saturating_sub(amount_msat)
7996+ <= counterparty_skimmed_fee_msat);
80067997 claimable_payment.htlcs.sort();
80077998 let payment_id =
80087999 claimable_payment.inbound_payment_id(&self.inbound_payment_id_secret);
@@ -8497,9 +8488,10 @@ impl<
84978488 // In this case we're not going to handle any timeouts of the parts here.
84988489 // This condition determining whether the MPP is complete here must match
84998490 // exactly the condition used in `process_pending_htlc_forwards`.
8500- let htlc_total_msat =
8491+ let total_intended_recvd_value =
85018492 payment.htlcs.iter().map(|h| h.sender_intended_value).sum();
8502- if payment.htlcs[0].total_msat <= htlc_total_msat {
8493+ let total_mpp_value = payment.onion_fields.total_mpp_amount_msat;
8494+ if total_mpp_value <= total_intended_recvd_value {
85038495 return true;
85048496 } else if payment.htlcs.iter_mut().any(|htlc| {
85058497 htlc.timer_ticks += 1;
@@ -8914,20 +8906,11 @@ impl<
89148906 // amount we told the user in the last `PaymentClaimable`. We also do a sanity-check that
89158907 // the MPP parts all have the same `total_msat`.
89168908 let mut claimable_amt_msat = 0;
8917- let mut prev_total_msat = None;
89188909 let mut expected_amt_msat = None;
89198910 let mut valid_mpp = true;
89208911 let mut errs = Vec::new();
89218912 let per_peer_state = self.per_peer_state.read().unwrap();
89228913 for htlc in sources.iter() {
8923- if prev_total_msat.is_some() && prev_total_msat != Some(htlc.total_msat) {
8924- log_error!(self.logger, "Somehow ended up with an MPP payment with different expected total amounts - this should not be reachable!");
8925- debug_assert!(false);
8926- valid_mpp = false;
8927- break;
8928- }
8929- prev_total_msat = Some(htlc.total_msat);
8930-
89318914 if expected_amt_msat.is_some() && expected_amt_msat != htlc.total_value_received {
89328915 log_error!(self.logger, "Somehow ended up with an MPP payment with different received total amounts - this should not be reachable!");
89338916 debug_assert!(false);
@@ -16938,28 +16921,28 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
1693816921 (13, trampoline_shared_secret, option),
1693916922});
1694016923
16941- impl Writeable for ClaimableHTLC {
16942- fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
16943- let (payment_data, keysend_preimage) = match &self.onion_payload {
16944- OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None),
16945- OnionPayload::Spontaneous(preimage) => (None, Some(preimage) ),
16946- };
16947- write_tlv_fields!(writer, {
16948- (0, self.prev_hop, required),
16949- (1, self.total_msat , required),
16950- (2, self.value , required),
16951- (3, self.sender_intended_value , required),
16952- (4, payment_data, option ),
16953- (5, self.total_value_received , option),
16954- (6, self.cltv_expiry, required ),
16955- (8, keysend_preimage, option ),
16956- (10, self.counterparty_skimmed_fee_msat , option),
16957- });
16958- Ok(())
16959- }
16924+ fn write_claimable_htlc<W: Writer>(
16925+ htlc: &ClaimableHTLC, total_mpp_value_msat: u64, writer: &mut W,
16926+ ) -> Result<(), io::Error> {
16927+ let (payment_data, keysend_preimage) = match &htlc.onion_payload {
16928+ OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None ),
16929+ OnionPayload::Spontaneous(preimage) => (None, Some(preimage)),
16930+ };
16931+ write_tlv_fields!(writer, {
16932+ (0, htlc.prev_hop , required),
16933+ (1, total_mpp_value_msat , required),
16934+ (2, htlc.value , required),
16935+ (3, htlc.sender_intended_value, required ),
16936+ (4, payment_data , option),
16937+ (5, htlc.total_value_received, option ),
16938+ (6, htlc.cltv_expiry, required ),
16939+ (8, keysend_preimage , option),
16940+ (10, htlc.counterparty_skimmed_fee_msat, option),
16941+ });
16942+ Ok(())
1696016943}
1696116944
16962- impl Readable for ClaimableHTLC {
16945+ impl Readable for ( ClaimableHTLC, u64) {
1696316946 #[rustfmt::skip]
1696416947 fn read<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
1696516948 _init_and_read_len_prefixed_tlv_fields!(reader, {
@@ -16995,17 +16978,16 @@ impl Readable for ClaimableHTLC {
1699516978 OnionPayload::Invoice { _legacy_hop_data: payment_data }
1699616979 },
1699716980 };
16998- Ok(Self {
16981+ Ok((ClaimableHTLC {
1699916982 prev_hop: prev_hop.0.unwrap(),
1700016983 timer_ticks: 0,
1700116984 value,
1700216985 sender_intended_value: sender_intended_value.unwrap_or(value),
1700316986 total_value_received,
17004- total_msat: total_msat.unwrap(),
1700516987 onion_payload,
1700616988 cltv_expiry: cltv_expiry.0.unwrap(),
1700716989 counterparty_skimmed_fee_msat,
17008- })
16990+ }, total_msat.unwrap()) )
1700916991 }
1701016992}
1701116993
@@ -17271,7 +17253,7 @@ impl<
1727117253 payment_hash.write(writer)?;
1727217254 (payment.htlcs.len() as u64).write(writer)?;
1727317255 for htlc in payment.htlcs.iter() {
17274- htlc.write( writer)?;
17256+ write_claimable_htlc(& htlc, payment.onion_fields.total_mpp_amount_msat, writer)?;
1727517257 }
1727617258 htlc_purposes.push(&payment.purpose);
1727717259 htlc_onion_fields.push(Some(&payment.onion_fields));
@@ -17611,10 +17593,20 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1761117593 previous_hops_len as usize,
1761217594 MAX_ALLOC_SIZE / mem::size_of::<ClaimableHTLC>(),
1761317595 ));
17596+ let mut total_mpp_value_msat = None;
1761417597 for _ in 0..previous_hops_len {
17615- previous_hops.push(<ClaimableHTLC as Readable>::read(reader)?);
17598+ let (htlc, total_mpp_value_msat_read) =
17599+ <(ClaimableHTLC, u64) as Readable>::read(reader)?;
17600+ if total_mpp_value_msat.is_some()
17601+ && total_mpp_value_msat != Some(total_mpp_value_msat_read)
17602+ {
17603+ return Err(DecodeError::InvalidValue);
17604+ }
17605+ total_mpp_value_msat = Some(total_mpp_value_msat_read);
17606+ previous_hops.push(htlc);
1761617607 }
17617- claimable_htlcs_list.push((payment_hash, previous_hops));
17608+ let total_mpp_value_msat = total_mpp_value_msat.ok_or(DecodeError::InvalidValue)?;
17609+ claimable_htlcs_list.push((payment_hash, previous_hops, total_mpp_value_msat));
1761817610 }
1761917611
1762017612 let peer_count: u64 = Readable::read(reader)?;
@@ -17793,19 +17785,17 @@ impl<'a, ES: EntropySource, SP: SignerProvider, L: Logger>
1779317785 if onion_fields.len() != claimable_htlcs_list.len() {
1779417786 return Err(DecodeError::InvalidValue);
1779517787 }
17796- for (purpose, (onion, (payment_hash, htlcs))) in purposes
17788+ for (purpose, (onion, (payment_hash, htlcs, total_mpp_value_msat ))) in purposes
1779717789 .into_iter()
1779817790 .zip(onion_fields.into_iter().zip(claimable_htlcs_list.into_iter()))
1779917791 {
17800- let htlcs_total_msat =
17801- htlcs.first().ok_or(DecodeError::InvalidValue)?.total_msat;
1780217792 let onion_fields = if let Some(mut onion) = onion {
1780317793 if onion.0.total_mpp_amount_msat != 0
17804- && onion.0.total_mpp_amount_msat != htlcs_total_msat
17794+ && onion.0.total_mpp_amount_msat != total_mpp_value_msat
1780517795 {
1780617796 return Err(DecodeError::InvalidValue);
1780717797 }
17808- onion.0.total_mpp_amount_msat = htlcs_total_msat ;
17798+ onion.0.total_mpp_amount_msat = total_mpp_value_msat ;
1780917799 onion.0
1781017800 } else {
1781117801 return Err(DecodeError::InvalidValue);
@@ -19755,16 +19745,15 @@ impl<
1975519745 let payment_id =
1975619746 payment.inbound_payment_id(&inbound_payment_id_secret.unwrap());
1975719747 let htlcs = payment.htlcs.iter().map(events::ClaimedHTLC::from).collect();
19758- let sender_intended_total_msat =
19759- payment.htlcs.first().map(|htlc| htlc.total_msat);
19748+ let sender_intended_total_msat = payment.onion_fields.total_mpp_amount_msat;
1976019749 pending_events.push_back((
1976119750 events::Event::PaymentClaimed {
1976219751 receiver_node_id,
1976319752 payment_hash,
1976419753 purpose: payment.purpose,
1976519754 amount_msat: claimable_amt_msat,
1976619755 htlcs,
19767- sender_intended_total_msat,
19756+ sender_intended_total_msat: Some(sender_intended_total_msat) ,
1976819757 onion_fields: Some(payment.onion_fields),
1976919758 payment_id: Some(payment_id),
1977019759 },
0 commit comments