@@ -152,6 +152,85 @@ enum InboundHTLCState {
152152 LocalRemoved(InboundHTLCRemovalReason),
153153}
154154
155+ /// Exposes the state of pending inbound HTLCs.
156+ ///
157+ /// Fail and fulfill suffixes indicate the resolution of the HTLC.
158+ #[derive(Clone, Debug, PartialEq)]
159+ pub enum InboundHTLCStateDetails {
160+ /// RemoteAnnounced states indicate that the remote sent update_add_htlc for this HTLC while the
161+ /// HTLC is not on any commitment transactions yet. It will be included in the next local
162+ /// commitment transaction when we receive commitment_signed and return revoke_and_ack.
163+ RemoteAnnouncedForward,
164+ /// See above.
165+ RemoteAnnouncedFail,
166+ /// AwaitingRemoteRevokeToAnnounce states indicate that we have received commitment_signed with
167+ /// this HTLC, returned revoke_and_ack, and this HTLC is included on the local commitment
168+ /// transaction but not the remote commitment transaction. The remote hasn't yet revoked their
169+ /// previous state and we have not yet included this HTLC in commitment_signed because we are
170+ /// waiting on the remote's revocation.
171+ AwaitingRemoteRevokeToAnnounceForward,
172+ /// See above.
173+ AwaitingRemoteRevokeToAnnounceFail,
174+ /// AwaitingAnnouncedRemoteRevoke states indicate that we have received commitment_signed with
175+ /// this HTLC, returned revoke_and_ack, and this HTLC is included on the local commitment
176+ /// transaction. We have also included this HTLC in our latest commitment_signed and are now just
177+ /// waiting on the remote's revoke_and_ack before this HTLC will be included on the remote
178+ /// commitment transaction as well and can then get forwarded and/or removed.
179+ AwaitingAnnouncedRemoteRevokeForward,
180+ /// See above.
181+ AwaitingAnnouncedRemoteRevokeFail,
182+ /// Committed indicates that this HTLC has been included in the commitment_signed and
183+ /// revoke_and_ack flow on both sides and is included in both commitment transactions.
184+ Committed,
185+ /// AwaitingRemoteRevokeToRemove states indicate that this HTLC will be removed by us sending
186+ /// update_*_htlc and commitment_signed, but the remote has not sent revoke_and_ack for the
187+ /// previous commitment_signed yet. The HTLC is still on both commitment transactions.
188+ AwaitingRemoteRevokeToRemoveFulfill,
189+ /// See above.
190+ AwaitingRemoteRevokeToRemoveFail,
191+ /// LocalRemoved states indicate that this HTLC has been removed by us and a new
192+ /// commitment_signed was sent, but the HTLC is still on both commitment transactions. When the
193+ /// remote sends the next revoke_and_ack, it will be removed from the remote's commitment
194+ /// transaction.
195+ LocalRemovedFailRelay,
196+ /// See above.
197+ LocalRemovedFailMalformed,
198+ /// See above.
199+ LocalRemovedFulfill,
200+ }
201+
202+ impl From<&InboundHTLCState> for InboundHTLCStateDetails {
203+ fn from(state: &InboundHTLCState) -> InboundHTLCStateDetails {
204+ match state {
205+ InboundHTLCState::RemoteAnnounced(PendingHTLCStatus::Forward(_)) => InboundHTLCStateDetails::RemoteAnnouncedForward,
206+ InboundHTLCState::RemoteAnnounced(PendingHTLCStatus::Fail(_)) => InboundHTLCStateDetails::RemoteAnnouncedFail,
207+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus::Forward(_)) => InboundHTLCStateDetails::AwaitingRemoteRevokeToAnnounceForward,
208+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus::Fail(_)) => InboundHTLCStateDetails::AwaitingRemoteRevokeToAnnounceFail,
209+ InboundHTLCState::AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus::Forward(_)) => InboundHTLCStateDetails::AwaitingAnnouncedRemoteRevokeForward,
210+ InboundHTLCState::AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus::Fail(_)) => InboundHTLCStateDetails::AwaitingAnnouncedRemoteRevokeFail,
211+ InboundHTLCState::Committed => InboundHTLCStateDetails::Committed,
212+ InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(_)) => InboundHTLCStateDetails::LocalRemovedFailRelay,
213+ InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed(_)) => InboundHTLCStateDetails::LocalRemovedFailMalformed,
214+ InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) => InboundHTLCStateDetails::LocalRemovedFulfill,
215+ }
216+ }
217+ }
218+
219+ impl_writeable_tlv_based_enum!(InboundHTLCStateDetails,
220+ (0, RemoteAnnouncedForward) => {},
221+ (2, RemoteAnnouncedFail) => {},
222+ (4, AwaitingRemoteRevokeToAnnounceForward) => {},
223+ (6, AwaitingRemoteRevokeToAnnounceFail) => {},
224+ (8, AwaitingAnnouncedRemoteRevokeForward) => {},
225+ (10, AwaitingAnnouncedRemoteRevokeFail) => {},
226+ (12, Committed) => {},
227+ (14, AwaitingRemoteRevokeToRemoveFulfill) => {},
228+ (16, AwaitingRemoteRevokeToRemoveFail) => {},
229+ (18, LocalRemovedFailRelay) => {},
230+ (20, LocalRemovedFailMalformed) => {},
231+ (22, LocalRemovedFulfill) => {};
232+ );
233+
155234struct InboundHTLCOutput {
156235 htlc_id: u64,
157236 amount_msat: u64,
@@ -160,6 +239,35 @@ struct InboundHTLCOutput {
160239 state: InboundHTLCState,
161240}
162241
242+ /// Exposes details around pending inbound HTLCs.
243+ #[derive(Clone, Debug, PartialEq)]
244+ pub struct InboundHTLCDetails {
245+ /// The corresponding HTLC ID.
246+ pub htlc_id: u64,
247+ /// The amount in msat.
248+ pub amount_msat: u64,
249+ /// The CLTV expiry.
250+ pub cltv_expiry: u32,
251+ /// The payment hash.
252+ pub payment_hash: PaymentHash,
253+ /// The state of the HTLC in the update_*_htlc, commitment_signed, revoke_and_ack flow.
254+ /// Informs on which commitment transactions the HTLC is included.
255+ pub state: InboundHTLCStateDetails,
256+ /// Whether the HTLC has an output below the local dust limit. If so, the output will be trimmed
257+ /// from the local commitment transaction and added to the commitment transaction fee.
258+ /// This takes into account the second-stage HTLC transactions as well.
259+ pub is_dust: bool,
260+ }
261+
262+ impl_writeable_tlv_based!(InboundHTLCDetails, {
263+ (0, htlc_id, required),
264+ (2, amount_msat, required),
265+ (4, cltv_expiry, required),
266+ (6, payment_hash, required),
267+ (8, state, required),
268+ (10, is_dust, required),
269+ });
270+
163271enum OutboundHTLCState {
164272 /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
165273 /// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -192,6 +300,82 @@ enum OutboundHTLCState {
192300 AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome),
193301}
194302
303+ /// Exposes the state of pending outbound HTLCs.
304+ ///
305+ /// Failure and success suffixes indicate the resolution of the HTLC.
306+ #[derive(Clone, Debug, PartialEq)]
307+ pub enum OutboundHTLCStateDetails {
308+ /// THe AwaitingRemoteRevokeToAnnounce state indicates that this HTLC will be added by us sending
309+ /// update_add_htlc and commitment_signed, but the remote has not sent revoke_and_ack for the
310+ /// previous commitment_signed yet. The HTLC is not on any commitment transactions yet.
311+ AwaitingRemoteRevokeToAnnounce,
312+ /// The LocalAnnounced state indicates that this HTLC has been added by us and included in a
313+ /// commitment_signed, but the HTLC is not on any commitment transactions yet. When the remote
314+ /// sends the next revoke_and_ack, it will be included in the remote's commitment transaction.
315+ LocalAnnounced,
316+ /// The Committed state indicates that this HTLC has been included in a commitment_signed sent by
317+ /// us and we have received a corresponding revoke_and_ack. The HTLC is therefore included in the
318+ /// remote's commitment transaction. Note that this includes the subsequent state where we
319+ /// receive the remote's commitment_signed with this HTLC, respond with the corresponding
320+ /// revoke_and_ack, and include it in the local commitment transaction, as:
321+ /// * they've revoked, so worst case we can announce an old state and get our (option on)
322+ /// money back (though we won't), and,
323+ /// * we'll send them a revoke when they send a commitment_signed, and since only they're
324+ /// allowed to remove it, the "can only be removed once committed on both sides" requirement
325+ /// doesn't matter to us and it's up to them to enforce it, worst-case they jump ahead but
326+ /// we'll never get out of sync).
327+ Committed,
328+ /// RemoteRemoved states indicate that this HTLC has been removed by the remote with
329+ /// update_*_htlc. The HTLC is still on both commitment transactions and we are waiting on their
330+ /// commitment_signed mesage.
331+ RemoteRemovedSuccess,
332+ /// See above.
333+ RemoteRemovedFailure,
334+ /// AwaitingRemoteRevokeToRemove states indicate that the remote removed this HTLC and sent a
335+ /// commitment_signed and we've revoke_and_ack'ed it. It is removed from the local commitment
336+ /// transaction but the remote side hasn't yet revoked their previous state and therefore we
337+ /// haven't yet removed this HTLC in our latest commitment_signed. This HTLC is still included in
338+ /// the remote's commitment transaction.
339+ AwaitingRemoteRevokeToRemoveSuccess,
340+ /// See above.
341+ AwaitingRemoteRevokeToRemoveFailure,
342+ /// AwaitingRemovedRemoteRevoke states indicate that the remote removed this and sent a
343+ /// commitment_signed and we've revoke_and_ack'ed it. It is therefore removed from the local
344+ /// commitment transaction. This HTLC has also been removed in our latest commitment_signed and
345+ /// will be removed from the remote's commitment transaction when we receive their
346+ /// revoke_and_ack, after which we can do any backwards failing.
347+ AwaitingRemovedRemoteRevokeSuccess,
348+ /// See above.
349+ AwaitingRemovedRemoteRevokeFailure,
350+ }
351+
352+ impl From<&OutboundHTLCState> for OutboundHTLCStateDetails {
353+ fn from(state: &OutboundHTLCState) -> OutboundHTLCStateDetails {
354+ match state {
355+ OutboundHTLCState::LocalAnnounced(_) => OutboundHTLCStateDetails::LocalAnnounced,
356+ OutboundHTLCState::Committed => OutboundHTLCStateDetails::Committed,
357+ OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_)) => OutboundHTLCStateDetails::RemoteRemovedSuccess,
358+ OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Failure(_)) => OutboundHTLCStateDetails::RemoteRemovedFailure,
359+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) => OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveSuccess,
360+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Failure(_)) => OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFailure,
361+ OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) => OutboundHTLCStateDetails::AwaitingRemovedRemoteRevokeSuccess,
362+ OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Failure(_)) => OutboundHTLCStateDetails::AwaitingRemovedRemoteRevokeFailure,
363+ }
364+ }
365+ }
366+
367+ impl_writeable_tlv_based_enum!(OutboundHTLCStateDetails,
368+ (0, AwaitingRemoteRevokeToAnnounce) => {},
369+ (2, LocalAnnounced) => {},
370+ (4, Committed) => {},
371+ (6, RemoteRemovedSuccess) => {},
372+ (8, RemoteRemovedFailure) => {},
373+ (10, AwaitingRemoteRevokeToRemoveSuccess) => {},
374+ (12, AwaitingRemoteRevokeToRemoveFailure) => {},
375+ (14, AwaitingRemovedRemoteRevokeSuccess) => {},
376+ (16, AwaitingRemovedRemoteRevokeFailure) => {};
377+ );
378+
195379#[derive(Clone)]
196380enum OutboundHTLCOutcome {
197381 /// LDK version 0.0.105+ will always fill in the preimage here.
@@ -227,6 +411,39 @@ struct OutboundHTLCOutput {
227411 skimmed_fee_msat: Option<u64>,
228412}
229413
414+ /// Exposes details around pending outbound HTLCs.
415+ #[derive(Clone, Debug, PartialEq)]
416+ pub struct OutboundHTLCDetails {
417+ /// The corresponding HTLC ID.
418+ /// Not present when we are awaiting a remote revocation and the HTLC is not added yet.
419+ pub htlc_id: Option<u64>,
420+ /// The amount in msat.
421+ pub amount_msat: u64,
422+ /// The CLTV expiry.
423+ pub cltv_expiry: u32,
424+ /// The payment hash.
425+ pub payment_hash: PaymentHash,
426+ /// The state of the HTLC in the update_*_htlc, commitment_signed, revoke_and_ack flow.
427+ /// Informs on which commitment transactions the HTLC is included.
428+ pub state: OutboundHTLCStateDetails,
429+ /// The extra fee being skimmed off the top of this HTLC.
430+ pub skimmed_fee_msat: Option<u64>,
431+ /// Whether the HTLC has an output below the local dust limit. If so, the output will be trimmed
432+ /// from the local commitment transaction and added to the commitment transaction fee.
433+ /// This takes into account the second-stage HTLC transactions as well.
434+ pub is_dust: bool,
435+ }
436+
437+ impl_writeable_tlv_based!(OutboundHTLCDetails, {
438+ (0, htlc_id, required),
439+ (2, amount_msat, required),
440+ (4, cltv_expiry, required),
441+ (6, payment_hash, required),
442+ (8, state, required),
443+ (10, skimmed_fee_msat, required),
444+ (12, is_dust, required),
445+ });
446+
230447/// See AwaitingRemoteRevoke ChannelState for more info
231448enum HTLCUpdateAwaitingACK {
232449 AddHTLC { // TODO: Time out if we're getting close to cltv_expiry
@@ -1549,6 +1766,90 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
15491766 stats
15501767 }
15511768
1769+ /// Returns information on all pending inbound HTLCs.
1770+ pub fn get_pending_inbound_htlc_details(&self) -> Vec<InboundHTLCDetails> {
1771+ let mut holding_cell_states = HashMap::new();
1772+ for holding_cell_update in self.holding_cell_htlc_updates.iter() {
1773+ match holding_cell_update {
1774+ HTLCUpdateAwaitingACK::ClaimHTLC { htlc_id, .. } => {
1775+ holding_cell_states.insert(
1776+ htlc_id,
1777+ InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFulfill,
1778+ );
1779+ },
1780+ HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
1781+ holding_cell_states.insert(
1782+ htlc_id,
1783+ InboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFail,
1784+ );
1785+ },
1786+ _ => {},
1787+ }
1788+ }
1789+ let mut inbound_details = Vec::new();
1790+ let htlc_success_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
1791+ 0
1792+ } else {
1793+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
1794+ dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
1795+ };
1796+ let holder_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
1797+ for htlc in self.pending_inbound_htlcs.iter() {
1798+ inbound_details.push(InboundHTLCDetails{
1799+ htlc_id: htlc.htlc_id,
1800+ amount_msat: htlc.amount_msat,
1801+ cltv_expiry: htlc.cltv_expiry,
1802+ payment_hash: htlc.payment_hash,
1803+ state: holding_cell_states.remove(&htlc.htlc_id).unwrap_or((&htlc.state).into()),
1804+ is_dust: htlc.amount_msat / 1000 < holder_dust_limit_success_sat,
1805+ });
1806+ }
1807+ inbound_details
1808+ }
1809+
1810+ /// Returns information on all pending outbound HTLCs.
1811+ pub fn get_pending_outbound_htlc_details(&self) -> Vec<OutboundHTLCDetails> {
1812+ let mut outbound_details = Vec::new();
1813+ let htlc_timeout_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
1814+ 0
1815+ } else {
1816+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
1817+ dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
1818+ };
1819+ let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
1820+ for htlc in self.pending_outbound_htlcs.iter() {
1821+ outbound_details.push(OutboundHTLCDetails{
1822+ htlc_id: Some(htlc.htlc_id),
1823+ amount_msat: htlc.amount_msat,
1824+ cltv_expiry: htlc.cltv_expiry,
1825+ payment_hash: htlc.payment_hash,
1826+ skimmed_fee_msat: htlc.skimmed_fee_msat,
1827+ state: (&htlc.state).into(),
1828+ is_dust: htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat,
1829+ });
1830+ }
1831+ for holding_cell_update in self.holding_cell_htlc_updates.iter() {
1832+ if let HTLCUpdateAwaitingACK::AddHTLC {
1833+ amount_msat,
1834+ cltv_expiry,
1835+ payment_hash,
1836+ skimmed_fee_msat,
1837+ ..
1838+ } = *holding_cell_update {
1839+ outbound_details.push(OutboundHTLCDetails{
1840+ htlc_id: None,
1841+ amount_msat: amount_msat,
1842+ cltv_expiry: cltv_expiry,
1843+ payment_hash: payment_hash,
1844+ skimmed_fee_msat: skimmed_fee_msat,
1845+ state: OutboundHTLCStateDetails::AwaitingRemoteRevokeToAnnounce,
1846+ is_dust: amount_msat / 1000 < holder_dust_limit_timeout_sat,
1847+ });
1848+ }
1849+ }
1850+ outbound_details
1851+ }
1852+
15521853 /// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
15531854 fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
15541855 let context = self;
0 commit comments