@@ -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