@@ -211,7 +211,14 @@ enum InboundHTLCState {
211211 /// channel (before it can then get forwarded and/or removed).
212212 /// Implies AwaitingRemoteRevoke.
213213 AwaitingAnnouncedRemoteRevoke(InboundHTLCResolution),
214- Committed,
214+ /// An HTLC irrevocably committed in the latest commitment transaction, ready to be forwarded or
215+ /// removed.
216+ Committed {
217+ /// Used to rebuild `ChannelManager` HTLC state on restart. Previously the manager would track
218+ /// and persist all HTLC forwards and receives itself, but newer LDK versions avoid relying on
219+ /// its persistence and instead reconstruct state based on `Channel` and `ChannelMonitor` data.
220+ update_add_htlc_opt: Option<msgs::UpdateAddHTLC>,
221+ },
215222 /// Removed by us and a new commitment_signed was sent (if we were AwaitingRemoteRevoke when we
216223 /// created it we would have put it in the holding cell instead). When they next revoke_and_ack
217224 /// we'll drop it.
@@ -235,7 +242,7 @@ impl From<&InboundHTLCState> for Option<InboundHTLCStateDetails> {
235242 InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => {
236243 Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToAdd)
237244 },
238- InboundHTLCState::Committed => Some(InboundHTLCStateDetails::Committed),
245+ InboundHTLCState::Committed { .. } => Some(InboundHTLCStateDetails::Committed),
239246 InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(_)) => {
240247 Some(InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFail)
241248 },
@@ -256,7 +263,7 @@ impl fmt::Display for InboundHTLCState {
256263 InboundHTLCState::RemoteAnnounced(_) => write!(f, "RemoteAnnounced"),
257264 InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => write!(f, "AwaitingRemoteRevokeToAnnounce"),
258265 InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => write!(f, "AwaitingAnnouncedRemoteRevoke"),
259- InboundHTLCState::Committed => write!(f, "Committed"),
266+ InboundHTLCState::Committed { .. } => write!(f, "Committed"),
260267 InboundHTLCState::LocalRemoved(_) => write!(f, "LocalRemoved"),
261268 }
262269 }
@@ -268,7 +275,7 @@ impl InboundHTLCState {
268275 InboundHTLCState::RemoteAnnounced(_) => !generated_by_local,
269276 InboundHTLCState::AwaitingRemoteRevokeToAnnounce(_) => !generated_by_local,
270277 InboundHTLCState::AwaitingAnnouncedRemoteRevoke(_) => true,
271- InboundHTLCState::Committed => true,
278+ InboundHTLCState::Committed { .. } => true,
272279 InboundHTLCState::LocalRemoved(_) => !generated_by_local,
273280 }
274281 }
@@ -296,7 +303,7 @@ impl InboundHTLCState {
296303 },
297304 InboundHTLCResolution::Resolved { .. } => false,
298305 },
299- InboundHTLCState::Committed | InboundHTLCState::LocalRemoved(_) => false,
306+ InboundHTLCState::Committed { .. } | InboundHTLCState::LocalRemoved(_) => false,
300307 }
301308 }
302309}
@@ -4102,7 +4109,7 @@ where
41024109
41034110 if self.pending_inbound_htlcs.iter()
41044111 .any(|htlc| match htlc.state {
4105- InboundHTLCState::Committed => false,
4112+ InboundHTLCState::Committed { .. } => false,
41064113 // An HTLC removal from the local node is pending on the remote commitment.
41074114 InboundHTLCState::LocalRemoved(_) => true,
41084115 // An HTLC add from the remote node is pending on the local commitment.
@@ -4531,7 +4538,7 @@ where
45314538 (InboundHTLCState::RemoteAnnounced(..), _) => true,
45324539 (InboundHTLCState::AwaitingRemoteRevokeToAnnounce(..), _) => true,
45334540 (InboundHTLCState::AwaitingAnnouncedRemoteRevoke(..), _) => true,
4534- (InboundHTLCState::Committed, _) => true,
4541+ (InboundHTLCState::Committed { .. } , _) => true,
45354542 (InboundHTLCState::LocalRemoved(..), true) => true,
45364543 (InboundHTLCState::LocalRemoved(..), false) => false,
45374544 })
@@ -7320,7 +7327,7 @@ where
73207327 payment_preimage_arg
73217328 );
73227329 match htlc.state {
7323- InboundHTLCState::Committed => {},
7330+ InboundHTLCState::Committed { .. } => {},
73247331 InboundHTLCState::LocalRemoved(ref reason) => {
73257332 if let &InboundHTLCRemovalReason::Fulfill { .. } = reason {
73267333 } else {
@@ -7413,7 +7420,7 @@ where
74137420
74147421 {
74157422 let htlc = &mut self.context.pending_inbound_htlcs[pending_idx];
7416- if let InboundHTLCState::Committed = htlc.state {
7423+ if let InboundHTLCState::Committed { .. } = htlc.state {
74177424 } else {
74187425 debug_assert!(
74197426 false,
@@ -7548,7 +7555,7 @@ where
75487555 for (idx, htlc) in self.context.pending_inbound_htlcs.iter().enumerate() {
75497556 if htlc.htlc_id == htlc_id_arg {
75507557 match htlc.state {
7551- InboundHTLCState::Committed => {},
7558+ InboundHTLCState::Committed { .. } => {},
75527559 InboundHTLCState::LocalRemoved(_) => {
75537560 return Err(ChannelError::Ignore(format!("HTLC {} was already resolved", htlc.htlc_id)));
75547561 },
@@ -8716,7 +8723,7 @@ where
87168723 false
87178724 };
87188725 if swap {
8719- let mut state = InboundHTLCState::Committed;
8726+ let mut state = InboundHTLCState::Committed { update_add_htlc_opt: None } ;
87208727 mem::swap(&mut state, &mut htlc.state);
87218728
87228729 if let InboundHTLCState::AwaitingRemoteRevokeToAnnounce(resolution) = state {
@@ -8755,14 +8762,23 @@ where
87558762 PendingHTLCStatus::Forward(forward_info) => {
87568763 log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed, attempting to forward", &htlc.payment_hash);
87578764 to_forward_infos.push((forward_info, htlc.htlc_id));
8758- htlc.state = InboundHTLCState::Committed;
8765+ htlc.state = InboundHTLCState::Committed {
8766+ // HTLCs will only be in state `InboundHTLCResolution::Resolved` if they were
8767+ // received on an old pre-0.1 version of LDK. In this case, we can't set
8768+ // `update_add_htlc_opt` here, but the HTLC will be present in the legacy
8769+ // `ChannelManager` maps so we'll process it from there if it's still around
8770+ // on the next restart.
8771+ update_add_htlc_opt: None,
8772+ };
87598773 },
87608774 }
87618775 },
87628776 InboundHTLCResolution::Pending { update_add_htlc } => {
87638777 log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", &htlc.payment_hash);
8764- pending_update_adds.push(update_add_htlc);
8765- htlc.state = InboundHTLCState::Committed;
8778+ pending_update_adds.push(update_add_htlc.clone());
8779+ htlc.state = InboundHTLCState::Committed {
8780+ update_add_htlc_opt: Some(update_add_htlc),
8781+ };
87668782 },
87678783 }
87688784 }
@@ -9297,7 +9313,7 @@ where
92979313 // in response to it yet, so don't touch it.
92989314 true
92999315 },
9300- InboundHTLCState::Committed => true,
9316+ InboundHTLCState::Committed { .. } => true,
93019317 InboundHTLCState::LocalRemoved(_) => {
93029318 // We (hopefully) sent a commitment_signed updating this HTLC (which we can
93039319 // re-transmit if needed) and they may have even sent a revoke_and_ack back
@@ -14518,6 +14534,7 @@ where
1451814534 }
1451914535 }
1452014536 let mut removed_htlc_attribution_data: Vec<&Option<AttributionData>> = Vec::new();
14537+ let mut inbound_committed_update_adds: Vec<Option<msgs::UpdateAddHTLC>> = Vec::new();
1452114538 (self.context.pending_inbound_htlcs.len() as u64 - dropped_inbound_htlcs).write(writer)?;
1452214539 for htlc in self.context.pending_inbound_htlcs.iter() {
1452314540 if let &InboundHTLCState::RemoteAnnounced(_) = &htlc.state {
@@ -14537,8 +14554,9 @@ where
1453714554 2u8.write(writer)?;
1453814555 htlc_resolution.write(writer)?;
1453914556 },
14540- &InboundHTLCState::Committed => {
14557+ &InboundHTLCState::Committed { ref update_add_htlc_opt } => {
1454114558 3u8.write(writer)?;
14559+ inbound_committed_update_adds.push(update_add_htlc_opt.clone());
1454214560 },
1454314561 &InboundHTLCState::LocalRemoved(ref removal_reason) => {
1454414562 4u8.write(writer)?;
@@ -14914,6 +14932,7 @@ where
1491414932 (69, holding_cell_held_htlc_flags, optional_vec), // Added in 0.2
1491514933 (71, holder_commitment_point_previous_revoked, option), // Added in 0.3
1491614934 (73, holder_commitment_point_last_revoked, option), // Added in 0.3
14935+ (75, inbound_committed_update_adds, optional_vec),
1491714936 });
1491814937
1491914938 Ok(())
@@ -14997,7 +15016,7 @@ where
1499715016 };
1499815017 InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution)
1499915018 },
15000- 3 => InboundHTLCState::Committed,
15019+ 3 => InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1500115020 4 => {
1500215021 let reason = match <u8 as Readable>::read(reader)? {
1500315022 0 => InboundHTLCRemovalReason::FailRelay(msgs::OnionErrorPacket {
@@ -15301,6 +15320,7 @@ where
1530115320
1530215321 let mut pending_outbound_held_htlc_flags_opt: Option<Vec<Option<()>>> = None;
1530315322 let mut holding_cell_held_htlc_flags_opt: Option<Vec<Option<()>>> = None;
15323+ let mut inbound_committed_update_adds_opt: Option<Vec<Option<msgs::UpdateAddHTLC>>> = None;
1530415324
1530515325 read_tlv_fields!(reader, {
1530615326 (0, announcement_sigs, option),
@@ -15350,6 +15370,7 @@ where
1535015370 (69, holding_cell_held_htlc_flags_opt, optional_vec), // Added in 0.2
1535115371 (71, holder_commitment_point_previous_revoked_opt, option), // Added in 0.3
1535215372 (73, holder_commitment_point_last_revoked_opt, option), // Added in 0.3
15373+ (75, inbound_committed_update_adds_opt, optional_vec),
1535315374 });
1535415375
1535515376 let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
@@ -15473,6 +15494,17 @@ where
1547315494 return Err(DecodeError::InvalidValue);
1547415495 }
1547515496 }
15497+ if let Some(update_adds) = inbound_committed_update_adds_opt {
15498+ let mut iter = update_adds.into_iter();
15499+ for htlc in pending_inbound_htlcs.iter_mut() {
15500+ if let InboundHTLCState::Committed { ref mut update_add_htlc_opt } = htlc.state {
15501+ *update_add_htlc_opt = iter.next().ok_or(DecodeError::InvalidValue)?;
15502+ }
15503+ }
15504+ if iter.next().is_some() {
15505+ return Err(DecodeError::InvalidValue);
15506+ }
15507+ }
1547615508
1547715509 if let Some(attribution_data_list) = removed_htlc_attribution_data {
1547815510 let mut removed_htlcs = pending_inbound_htlcs.iter_mut().filter_map(|status| {
@@ -16057,7 +16089,7 @@ mod tests {
1605716089 amount_msat: htlc_amount_msat,
1605816090 payment_hash: PaymentHash(Sha256::hash(&[42; 32]).to_byte_array()),
1605916091 cltv_expiry: 300000000,
16060- state: InboundHTLCState::Committed,
16092+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1606116093 });
1606216094
1606316095 node_a_chan.context.pending_outbound_htlcs.push(OutboundHTLCOutput {
@@ -16903,7 +16935,7 @@ mod tests {
1690316935 amount_msat: 1000000,
1690416936 cltv_expiry: 500,
1690516937 payment_hash: PaymentHash::from(payment_preimage_0),
16906- state: InboundHTLCState::Committed,
16938+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1690716939 });
1690816940
1690916941 let payment_preimage_1 =
@@ -16913,7 +16945,7 @@ mod tests {
1691316945 amount_msat: 2000000,
1691416946 cltv_expiry: 501,
1691516947 payment_hash: PaymentHash::from(payment_preimage_1),
16916- state: InboundHTLCState::Committed,
16948+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1691716949 });
1691816950
1691916951 let payment_preimage_2 =
@@ -16953,7 +16985,7 @@ mod tests {
1695316985 amount_msat: 4000000,
1695416986 cltv_expiry: 504,
1695516987 payment_hash: PaymentHash::from(payment_preimage_4),
16956- state: InboundHTLCState::Committed,
16988+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1695716989 });
1695816990
1695916991 // commitment tx with all five HTLCs untrimmed (minimum feerate)
@@ -17342,7 +17374,7 @@ mod tests {
1734217374 amount_msat: 2000000,
1734317375 cltv_expiry: 501,
1734417376 payment_hash: PaymentHash::from(payment_preimage_1),
17345- state: InboundHTLCState::Committed,
17377+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1734617378 });
1734717379
1734817380 chan.context.pending_outbound_htlcs.clear();
@@ -17593,7 +17625,7 @@ mod tests {
1759317625 amount_msat: 5000000,
1759417626 cltv_expiry: 920150,
1759517627 payment_hash: PaymentHash::from(htlc_in_preimage),
17596- state: InboundHTLCState::Committed,
17628+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1759717629 }));
1759817630
1759917631 chan.context.pending_outbound_htlcs.extend(
@@ -17656,7 +17688,7 @@ mod tests {
1765617688 amount_msat,
1765717689 cltv_expiry: 920150,
1765817690 payment_hash: PaymentHash::from(htlc_in_preimage),
17659- state: InboundHTLCState::Committed,
17691+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1766017692 },
1766117693 ));
1766217694
@@ -17722,7 +17754,7 @@ mod tests {
1772217754 amount_msat: 100000,
1772317755 cltv_expiry: 920125,
1772417756 payment_hash: htlc_0_in_hash,
17725- state: InboundHTLCState::Committed,
17757+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1772617758 });
1772717759
1772817760 let htlc_1_in_preimage =
@@ -17740,7 +17772,7 @@ mod tests {
1774017772 amount_msat: 49900000,
1774117773 cltv_expiry: 920125,
1774217774 payment_hash: htlc_1_in_hash,
17743- state: InboundHTLCState::Committed,
17775+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1774417776 });
1774517777
1774617778 chan.context.pending_outbound_htlcs.extend(
@@ -17792,7 +17824,7 @@ mod tests {
1779217824 amount_msat: 30000,
1779317825 payment_hash,
1779417826 cltv_expiry: 920125,
17795- state: InboundHTLCState::Committed,
17827+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1779617828 },
1779717829 ));
1779817830
@@ -17833,7 +17865,7 @@ mod tests {
1783317865 amount_msat: 29525,
1783417866 payment_hash,
1783517867 cltv_expiry: 920125,
17836- state: InboundHTLCState::Committed,
17868+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1783717869 },
1783817870 ));
1783917871
@@ -17870,7 +17902,7 @@ mod tests {
1787017902 amount_msat: 29525,
1787117903 payment_hash,
1787217904 cltv_expiry: 920125,
17873- state: InboundHTLCState::Committed,
17905+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1787417906 },
1787517907 ));
1787617908
@@ -17907,7 +17939,7 @@ mod tests {
1790717939 amount_msat: 29753,
1790817940 payment_hash,
1790917941 cltv_expiry: 920125,
17910- state: InboundHTLCState::Committed,
17942+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1791117943 },
1791217944 ));
1791317945
@@ -17959,7 +17991,7 @@ mod tests {
1795917991 amount_msat,
1796017992 cltv_expiry,
1796117993 payment_hash,
17962- state: InboundHTLCState::Committed,
17994+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1796317995 }),
1796417996 );
1796517997
0 commit comments