@@ -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,21 @@ 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.0.123 version of LDK. In this case, the HTLC is
8768+ // required to be resolved prior to upgrading to 0.1+ per CHANGELOG.md.
8769+ update_add_htlc_opt: None,
8770+ };
87598771 },
87608772 }
87618773 },
87628774 InboundHTLCResolution::Pending { update_add_htlc } => {
87638775 log_trace!(logger, " ...promoting inbound AwaitingAnnouncedRemoteRevoke {} to Committed", &htlc.payment_hash);
8764- pending_update_adds.push(update_add_htlc);
8765- htlc.state = InboundHTLCState::Committed;
8776+ pending_update_adds.push(update_add_htlc.clone());
8777+ htlc.state = InboundHTLCState::Committed {
8778+ update_add_htlc_opt: Some(update_add_htlc),
8779+ };
87668780 },
87678781 }
87688782 }
@@ -9297,7 +9311,7 @@ where
92979311 // in response to it yet, so don't touch it.
92989312 true
92999313 },
9300- InboundHTLCState::Committed => true,
9314+ InboundHTLCState::Committed { .. } => true,
93019315 InboundHTLCState::LocalRemoved(_) => {
93029316 // We (hopefully) sent a commitment_signed updating this HTLC (which we can
93039317 // re-transmit if needed) and they may have even sent a revoke_and_ack back
@@ -14518,6 +14532,7 @@ where
1451814532 }
1451914533 }
1452014534 let mut removed_htlc_attribution_data: Vec<&Option<AttributionData>> = Vec::new();
14535+ let mut inbound_committed_update_adds: Vec<Option<msgs::UpdateAddHTLC>> = Vec::new();
1452114536 (self.context.pending_inbound_htlcs.len() as u64 - dropped_inbound_htlcs).write(writer)?;
1452214537 for htlc in self.context.pending_inbound_htlcs.iter() {
1452314538 if let &InboundHTLCState::RemoteAnnounced(_) = &htlc.state {
@@ -14537,8 +14552,9 @@ where
1453714552 2u8.write(writer)?;
1453814553 htlc_resolution.write(writer)?;
1453914554 },
14540- &InboundHTLCState::Committed => {
14555+ &InboundHTLCState::Committed { ref update_add_htlc_opt } => {
1454114556 3u8.write(writer)?;
14557+ inbound_committed_update_adds.push(update_add_htlc_opt.clone());
1454214558 },
1454314559 &InboundHTLCState::LocalRemoved(ref removal_reason) => {
1454414560 4u8.write(writer)?;
@@ -14914,6 +14930,7 @@ where
1491414930 (69, holding_cell_held_htlc_flags, optional_vec), // Added in 0.2
1491514931 (71, holder_commitment_point_previous_revoked, option), // Added in 0.3
1491614932 (73, holder_commitment_point_last_revoked, option), // Added in 0.3
14933+ (75, inbound_committed_update_adds, optional_vec),
1491714934 });
1491814935
1491914936 Ok(())
@@ -14997,7 +15014,7 @@ where
1499715014 };
1499815015 InboundHTLCState::AwaitingAnnouncedRemoteRevoke(resolution)
1499915016 },
15000- 3 => InboundHTLCState::Committed,
15017+ 3 => InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1500115018 4 => {
1500215019 let reason = match <u8 as Readable>::read(reader)? {
1500315020 0 => InboundHTLCRemovalReason::FailRelay(msgs::OnionErrorPacket {
@@ -15301,6 +15318,7 @@ where
1530115318
1530215319 let mut pending_outbound_held_htlc_flags_opt: Option<Vec<Option<()>>> = None;
1530315320 let mut holding_cell_held_htlc_flags_opt: Option<Vec<Option<()>>> = None;
15321+ let mut inbound_committed_update_adds_opt: Option<Vec<Option<msgs::UpdateAddHTLC>>> = None;
1530415322
1530515323 read_tlv_fields!(reader, {
1530615324 (0, announcement_sigs, option),
@@ -15350,6 +15368,7 @@ where
1535015368 (69, holding_cell_held_htlc_flags_opt, optional_vec), // Added in 0.2
1535115369 (71, holder_commitment_point_previous_revoked_opt, option), // Added in 0.3
1535215370 (73, holder_commitment_point_last_revoked_opt, option), // Added in 0.3
15371+ (75, inbound_committed_update_adds_opt, optional_vec),
1535315372 });
1535415373
1535515374 let holder_signer = signer_provider.derive_channel_signer(channel_keys_id);
@@ -15473,6 +15492,17 @@ where
1547315492 return Err(DecodeError::InvalidValue);
1547415493 }
1547515494 }
15495+ if let Some(update_adds) = inbound_committed_update_adds_opt {
15496+ let mut iter = update_adds.into_iter();
15497+ for htlc in pending_inbound_htlcs.iter_mut() {
15498+ if let InboundHTLCState::Committed { ref mut update_add_htlc_opt } = htlc.state {
15499+ *update_add_htlc_opt = iter.next().ok_or(DecodeError::InvalidValue)?;
15500+ }
15501+ }
15502+ if iter.next().is_some() {
15503+ return Err(DecodeError::InvalidValue);
15504+ }
15505+ }
1547615506
1547715507 if let Some(attribution_data_list) = removed_htlc_attribution_data {
1547815508 let mut removed_htlcs = pending_inbound_htlcs.iter_mut().filter_map(|status| {
@@ -16057,7 +16087,7 @@ mod tests {
1605716087 amount_msat: htlc_amount_msat,
1605816088 payment_hash: PaymentHash(Sha256::hash(&[42; 32]).to_byte_array()),
1605916089 cltv_expiry: 300000000,
16060- state: InboundHTLCState::Committed,
16090+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1606116091 });
1606216092
1606316093 node_a_chan.context.pending_outbound_htlcs.push(OutboundHTLCOutput {
@@ -16903,7 +16933,7 @@ mod tests {
1690316933 amount_msat: 1000000,
1690416934 cltv_expiry: 500,
1690516935 payment_hash: PaymentHash::from(payment_preimage_0),
16906- state: InboundHTLCState::Committed,
16936+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1690716937 });
1690816938
1690916939 let payment_preimage_1 =
@@ -16913,7 +16943,7 @@ mod tests {
1691316943 amount_msat: 2000000,
1691416944 cltv_expiry: 501,
1691516945 payment_hash: PaymentHash::from(payment_preimage_1),
16916- state: InboundHTLCState::Committed,
16946+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1691716947 });
1691816948
1691916949 let payment_preimage_2 =
@@ -16953,7 +16983,7 @@ mod tests {
1695316983 amount_msat: 4000000,
1695416984 cltv_expiry: 504,
1695516985 payment_hash: PaymentHash::from(payment_preimage_4),
16956- state: InboundHTLCState::Committed,
16986+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1695716987 });
1695816988
1695916989 // commitment tx with all five HTLCs untrimmed (minimum feerate)
@@ -17342,7 +17372,7 @@ mod tests {
1734217372 amount_msat: 2000000,
1734317373 cltv_expiry: 501,
1734417374 payment_hash: PaymentHash::from(payment_preimage_1),
17345- state: InboundHTLCState::Committed,
17375+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1734617376 });
1734717377
1734817378 chan.context.pending_outbound_htlcs.clear();
@@ -17593,7 +17623,7 @@ mod tests {
1759317623 amount_msat: 5000000,
1759417624 cltv_expiry: 920150,
1759517625 payment_hash: PaymentHash::from(htlc_in_preimage),
17596- state: InboundHTLCState::Committed,
17626+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1759717627 }));
1759817628
1759917629 chan.context.pending_outbound_htlcs.extend(
@@ -17656,7 +17686,7 @@ mod tests {
1765617686 amount_msat,
1765717687 cltv_expiry: 920150,
1765817688 payment_hash: PaymentHash::from(htlc_in_preimage),
17659- state: InboundHTLCState::Committed,
17689+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1766017690 },
1766117691 ));
1766217692
@@ -17722,7 +17752,7 @@ mod tests {
1772217752 amount_msat: 100000,
1772317753 cltv_expiry: 920125,
1772417754 payment_hash: htlc_0_in_hash,
17725- state: InboundHTLCState::Committed,
17755+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1772617756 });
1772717757
1772817758 let htlc_1_in_preimage =
@@ -17740,7 +17770,7 @@ mod tests {
1774017770 amount_msat: 49900000,
1774117771 cltv_expiry: 920125,
1774217772 payment_hash: htlc_1_in_hash,
17743- state: InboundHTLCState::Committed,
17773+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1774417774 });
1774517775
1774617776 chan.context.pending_outbound_htlcs.extend(
@@ -17792,7 +17822,7 @@ mod tests {
1779217822 amount_msat: 30000,
1779317823 payment_hash,
1779417824 cltv_expiry: 920125,
17795- state: InboundHTLCState::Committed,
17825+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1779617826 },
1779717827 ));
1779817828
@@ -17833,7 +17863,7 @@ mod tests {
1783317863 amount_msat: 29525,
1783417864 payment_hash,
1783517865 cltv_expiry: 920125,
17836- state: InboundHTLCState::Committed,
17866+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1783717867 },
1783817868 ));
1783917869
@@ -17870,7 +17900,7 @@ mod tests {
1787017900 amount_msat: 29525,
1787117901 payment_hash,
1787217902 cltv_expiry: 920125,
17873- state: InboundHTLCState::Committed,
17903+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1787417904 },
1787517905 ));
1787617906
@@ -17907,7 +17937,7 @@ mod tests {
1790717937 amount_msat: 29753,
1790817938 payment_hash,
1790917939 cltv_expiry: 920125,
17910- state: InboundHTLCState::Committed,
17940+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1791117941 },
1791217942 ));
1791317943
@@ -17959,7 +17989,7 @@ mod tests {
1795917989 amount_msat,
1796017990 cltv_expiry,
1796117991 payment_hash,
17962- state: InboundHTLCState::Committed,
17992+ state: InboundHTLCState::Committed { update_add_htlc_opt: None } ,
1796317993 }),
1796417994 );
1796517995
0 commit comments