@@ -152,6 +152,50 @@ enum InboundHTLCState {
152
152
LocalRemoved(InboundHTLCRemovalReason),
153
153
}
154
154
155
+ #[derive(Clone, Debug, PartialEq)]
156
+ pub enum InboundHTLCStateDetails {
157
+ RemoteAnnouncedForward,
158
+ RemoteAnnouncedFail,
159
+ AwaitingRemoteRevokeToAnnounceForward,
160
+ AwaitingRemoteRevokeToAnnounceFail,
161
+ AwaitingAnnouncedRemoteRevokeForward,
162
+ AwaitingAnnouncedRemoteRevokeFail,
163
+ Committed,
164
+ LocalRemovedFailRelay,
165
+ LocalRemovedFailMalformed,
166
+ LocalRemovedFulfill,
167
+ }
168
+
169
+ impl From<&InboundHTLCState> for InboundHTLCStateDetails {
170
+ fn from(state: &InboundHTLCState) -> InboundHTLCStateDetails {
171
+ match state {
172
+ InboundHTLCState::RemoteAnnounced(PendingHTLCStatus::Forward(_)) => InboundHTLCStateDetails::RemoteAnnouncedForward,
173
+ InboundHTLCState::RemoteAnnounced(PendingHTLCStatus::Fail(_)) => InboundHTLCStateDetails::RemoteAnnouncedFail,
174
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus::Forward(_)) => InboundHTLCStateDetails::AwaitingRemoteRevokeToAnnounceForward,
175
+ InboundHTLCState::AwaitingRemoteRevokeToAnnounce(PendingHTLCStatus::Fail(_)) => InboundHTLCStateDetails::AwaitingRemoteRevokeToAnnounceFail,
176
+ InboundHTLCState::AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus::Forward(_)) => InboundHTLCStateDetails::AwaitingAnnouncedRemoteRevokeForward,
177
+ InboundHTLCState::AwaitingAnnouncedRemoteRevoke(PendingHTLCStatus::Fail(_)) => InboundHTLCStateDetails::AwaitingAnnouncedRemoteRevokeFail,
178
+ InboundHTLCState::Committed => InboundHTLCStateDetails::Committed,
179
+ InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(_)) => InboundHTLCStateDetails::LocalRemovedFailRelay,
180
+ InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailMalformed(_)) => InboundHTLCStateDetails::LocalRemovedFailMalformed,
181
+ InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(_)) => InboundHTLCStateDetails::LocalRemovedFulfill,
182
+ }
183
+ }
184
+ }
185
+
186
+ impl_writeable_tlv_based_enum!(InboundHTLCStateDetails,
187
+ (0, RemoteAnnouncedForward) => {},
188
+ (1, RemoteAnnouncedFail) => {},
189
+ (2, AwaitingRemoteRevokeToAnnounceForward) => {},
190
+ (3, AwaitingRemoteRevokeToAnnounceFail) => {},
191
+ (4, AwaitingAnnouncedRemoteRevokeForward) => {},
192
+ (5, AwaitingAnnouncedRemoteRevokeFail) => {},
193
+ (6, Committed) => {},
194
+ (7, LocalRemovedFailRelay) => {},
195
+ (8, LocalRemovedFailMalformed) => {},
196
+ (9, LocalRemovedFulfill) => {};
197
+ );
198
+
155
199
struct InboundHTLCOutput {
156
200
htlc_id: u64,
157
201
amount_msat: u64,
@@ -160,6 +204,25 @@ struct InboundHTLCOutput {
160
204
state: InboundHTLCState,
161
205
}
162
206
207
+ #[derive(Clone, Debug, PartialEq)]
208
+ pub struct InboundHTLCDetails {
209
+ pub htlc_id: u64,
210
+ pub amount_msat: u64,
211
+ pub cltv_expiry: u32,
212
+ pub payment_hash: PaymentHash,
213
+ pub state: InboundHTLCStateDetails,
214
+ pub is_dust: bool,
215
+ }
216
+
217
+ impl_writeable_tlv_based!(InboundHTLCDetails, {
218
+ (0, htlc_id, required),
219
+ (2, amount_msat, required),
220
+ (4, cltv_expiry, required),
221
+ (6, payment_hash, required),
222
+ (8, state, required),
223
+ (10, is_dust, required),
224
+ });
225
+
163
226
enum OutboundHTLCState {
164
227
/// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
165
228
/// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -192,6 +255,44 @@ enum OutboundHTLCState {
192
255
AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome),
193
256
}
194
257
258
+ #[derive(Clone, Debug, PartialEq)]
259
+ pub enum OutboundHTLCStateDetails {
260
+ LocalAnnounced,
261
+ Committed,
262
+ RemoteRemovedSuccess,
263
+ RemoteRemovedFailure,
264
+ AwaitingRemoteRevokeToRemoveSuccess,
265
+ AwaitingRemoteRevokeToRemoveFailure,
266
+ AwaitingRemovedRemoteRevokeSuccess,
267
+ AwaitingRemovedRemoteRevokeFailure,
268
+ }
269
+
270
+ impl From<&OutboundHTLCState> for OutboundHTLCStateDetails {
271
+ fn from(state: &OutboundHTLCState) -> OutboundHTLCStateDetails {
272
+ match state {
273
+ OutboundHTLCState::LocalAnnounced(_) => OutboundHTLCStateDetails::LocalAnnounced,
274
+ OutboundHTLCState::Committed => OutboundHTLCStateDetails::Committed,
275
+ OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Success(_)) => OutboundHTLCStateDetails::RemoteRemovedSuccess,
276
+ OutboundHTLCState::RemoteRemoved(OutboundHTLCOutcome::Failure(_)) => OutboundHTLCStateDetails::RemoteRemovedFailure,
277
+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Success(_)) => OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveSuccess,
278
+ OutboundHTLCState::AwaitingRemoteRevokeToRemove(OutboundHTLCOutcome::Failure(_)) => OutboundHTLCStateDetails::AwaitingRemoteRevokeToRemoveFailure,
279
+ OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Success(_)) => OutboundHTLCStateDetails::AwaitingRemovedRemoteRevokeSuccess,
280
+ OutboundHTLCState::AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome::Failure(_)) => OutboundHTLCStateDetails::AwaitingRemovedRemoteRevokeFailure,
281
+ }
282
+ }
283
+ }
284
+
285
+ impl_writeable_tlv_based_enum!(OutboundHTLCStateDetails,
286
+ (0, LocalAnnounced) => {},
287
+ (1, Committed) => {},
288
+ (2, RemoteRemovedSuccess) => {},
289
+ (3, RemoteRemovedFailure) => {},
290
+ (4, AwaitingRemoteRevokeToRemoveSuccess) => {},
291
+ (5, AwaitingRemoteRevokeToRemoveFailure) => {},
292
+ (6, AwaitingRemovedRemoteRevokeSuccess) => {},
293
+ (7, AwaitingRemovedRemoteRevokeFailure) => {};
294
+ );
295
+
195
296
#[derive(Clone)]
196
297
enum OutboundHTLCOutcome {
197
298
/// LDK version 0.0.105+ will always fill in the preimage here.
@@ -227,6 +328,27 @@ struct OutboundHTLCOutput {
227
328
skimmed_fee_msat: Option<u64>,
228
329
}
229
330
331
+ #[derive(Clone, Debug, PartialEq)]
332
+ pub struct OutboundHTLCDetails {
333
+ pub htlc_id: u64,
334
+ pub amount_msat: u64,
335
+ pub cltv_expiry: u32,
336
+ pub payment_hash: PaymentHash,
337
+ pub state: OutboundHTLCStateDetails,
338
+ pub skimmed_fee_msat: Option<u64>,
339
+ pub is_dust: bool,
340
+ }
341
+
342
+ impl_writeable_tlv_based!(OutboundHTLCDetails, {
343
+ (0, htlc_id, required),
344
+ (2, amount_msat, required),
345
+ (4, cltv_expiry, required),
346
+ (6, payment_hash, required),
347
+ (8, state, required),
348
+ (10, skimmed_fee_msat, required),
349
+ (12, is_dust, required),
350
+ });
351
+
230
352
/// See AwaitingRemoteRevoke ChannelState for more info
231
353
enum HTLCUpdateAwaitingACK {
232
354
AddHTLC { // TODO: Time out if we're getting close to cltv_expiry
@@ -249,6 +371,39 @@ enum HTLCUpdateAwaitingACK {
249
371
},
250
372
}
251
373
374
+ #[derive(Clone, Debug, PartialEq)]
375
+ pub enum HTLCUpdateAwaitingACKDetails {
376
+ AddHTLC {
377
+ amount_msat: u64,
378
+ cltv_expiry: u32,
379
+ payment_hash: PaymentHash,
380
+ skimmed_fee_msat: Option<u64>,
381
+ is_dust: bool,
382
+ },
383
+ ClaimHTLC {
384
+ htlc_id: u64,
385
+ },
386
+ FailHTLC {
387
+ htlc_id: u64,
388
+ },
389
+ }
390
+
391
+ impl_writeable_tlv_based_enum!(HTLCUpdateAwaitingACKDetails,
392
+ (0, AddHTLC) => {
393
+ (0, amount_msat, required),
394
+ (2, cltv_expiry, required),
395
+ (4, payment_hash, required),
396
+ (6, skimmed_fee_msat, required),
397
+ (8, is_dust, required),
398
+ },
399
+ (1, ClaimHTLC) => {
400
+ (0, htlc_id, required),
401
+ },
402
+ (2, FailHTLC) => {
403
+ (0, htlc_id, required),
404
+ };
405
+ );
406
+
252
407
/// There are a few "states" and then a number of flags which can be applied:
253
408
/// We first move through init with `OurInitSent` -> `TheirInitSent` -> `FundingCreated` -> `FundingSent`.
254
409
/// `TheirChannelReady` and `OurChannelReady` then get set on `FundingSent`, and when both are set we
@@ -1549,6 +1704,94 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
1549
1704
stats
1550
1705
}
1551
1706
1707
+ /// Returns information on all pending inbound HTLCs.
1708
+ pub fn get_pending_inbound_htlc_details(&self) -> Vec<InboundHTLCDetails> {
1709
+ let mut inbound_details = Vec::new();
1710
+ let htlc_success_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
1711
+ 0
1712
+ } else {
1713
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
1714
+ dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
1715
+ };
1716
+ let holder_dust_limit_success_sat = htlc_success_dust_limit + self.holder_dust_limit_satoshis;
1717
+ for ref htlc in self.pending_inbound_htlcs.iter() {
1718
+ inbound_details.push(InboundHTLCDetails{
1719
+ htlc_id: htlc.htlc_id,
1720
+ amount_msat: htlc.amount_msat,
1721
+ cltv_expiry: htlc.cltv_expiry,
1722
+ payment_hash: htlc.payment_hash,
1723
+ state: (&htlc.state).into(),
1724
+ is_dust: htlc.amount_msat / 1000 < holder_dust_limit_success_sat,
1725
+ });
1726
+ }
1727
+ inbound_details
1728
+ }
1729
+
1730
+ /// Returns information on all pending outbound HTLCs.
1731
+ pub fn get_pending_outbound_htlc_details(&self) -> Vec<OutboundHTLCDetails> {
1732
+ let mut outbound_details = Vec::new();
1733
+ let htlc_timeout_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
1734
+ 0
1735
+ } else {
1736
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
1737
+ dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
1738
+ };
1739
+ let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
1740
+ for ref htlc in self.pending_outbound_htlcs.iter() {
1741
+ outbound_details.push(OutboundHTLCDetails{
1742
+ htlc_id: htlc.htlc_id,
1743
+ amount_msat: htlc.amount_msat,
1744
+ cltv_expiry: htlc.cltv_expiry,
1745
+ payment_hash: htlc.payment_hash,
1746
+ skimmed_fee_msat: htlc.skimmed_fee_msat,
1747
+ state: (&htlc.state).into(),
1748
+ is_dust: htlc.amount_msat / 1000 < holder_dust_limit_timeout_sat,
1749
+ });
1750
+ }
1751
+ outbound_details
1752
+ }
1753
+
1754
+ pub fn get_holding_cell_details(&self) -> Vec<HTLCUpdateAwaitingACKDetails> {
1755
+ let mut holding_cell_details = Vec::new();
1756
+ let htlc_timeout_dust_limit = if self.get_channel_type().supports_anchors_zero_fee_htlc_tx() {
1757
+ 0
1758
+ } else {
1759
+ let dust_buffer_feerate = self.get_dust_buffer_feerate(None) as u64;
1760
+ dust_buffer_feerate * htlc_success_tx_weight(self.get_channel_type()) / 1000
1761
+ };
1762
+ let holder_dust_limit_timeout_sat = htlc_timeout_dust_limit + self.holder_dust_limit_satoshis;
1763
+ for ref htlc_update in self.holding_cell_htlc_updates.iter() {
1764
+ holding_cell_details.push(match htlc_update {
1765
+ HTLCUpdateAwaitingACK::AddHTLC {
1766
+ amount_msat,
1767
+ cltv_expiry,
1768
+ payment_hash,
1769
+ skimmed_fee_msat,
1770
+ ..
1771
+ } => HTLCUpdateAwaitingACKDetails::AddHTLC {
1772
+ amount_msat: *amount_msat,
1773
+ cltv_expiry: *cltv_expiry,
1774
+ payment_hash: *payment_hash,
1775
+ skimmed_fee_msat: *skimmed_fee_msat,
1776
+ is_dust: amount_msat / 1000 < holder_dust_limit_timeout_sat,
1777
+ },
1778
+ HTLCUpdateAwaitingACK::ClaimHTLC {
1779
+ htlc_id,
1780
+ ..
1781
+ } => HTLCUpdateAwaitingACKDetails::ClaimHTLC {
1782
+ htlc_id: *htlc_id,
1783
+ },
1784
+ HTLCUpdateAwaitingACK::FailHTLC {
1785
+ htlc_id,
1786
+ ..
1787
+ } => HTLCUpdateAwaitingACKDetails::FailHTLC {
1788
+ htlc_id: *htlc_id,
1789
+ },
1790
+ });
1791
+ }
1792
+ holding_cell_details
1793
+ }
1794
+
1552
1795
/// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
1553
1796
fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
1554
1797
let context = self;
0 commit comments