@@ -152,6 +152,85 @@ enum InboundHTLCState {
152
152
LocalRemoved(InboundHTLCRemovalReason),
153
153
}
154
154
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
+
155
234
struct InboundHTLCOutput {
156
235
htlc_id: u64,
157
236
amount_msat: u64,
@@ -160,6 +239,35 @@ struct InboundHTLCOutput {
160
239
state: InboundHTLCState,
161
240
}
162
241
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
+
163
271
enum OutboundHTLCState {
164
272
/// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
165
273
/// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -192,6 +300,82 @@ enum OutboundHTLCState {
192
300
AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome),
193
301
}
194
302
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
+
195
379
#[derive(Clone)]
196
380
enum OutboundHTLCOutcome {
197
381
/// LDK version 0.0.105+ will always fill in the preimage here.
@@ -227,6 +411,39 @@ struct OutboundHTLCOutput {
227
411
skimmed_fee_msat: Option<u64>,
228
412
}
229
413
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
+
230
447
/// See AwaitingRemoteRevoke ChannelState for more info
231
448
enum HTLCUpdateAwaitingACK {
232
449
AddHTLC { // TODO: Time out if we're getting close to cltv_expiry
@@ -1549,6 +1766,90 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
1549
1766
stats
1550
1767
}
1551
1768
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
+
1552
1853
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
1553
1854
fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
1554
1855
let context = self;
0 commit comments