@@ -152,6 +152,50 @@ enum InboundHTLCState {
152152 LocalRemoved(InboundHTLCRemovalReason),
153153}
154154
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+
155199struct InboundHTLCOutput {
156200 htlc_id: u64,
157201 amount_msat: u64,
@@ -160,6 +204,25 @@ struct InboundHTLCOutput {
160204 state: InboundHTLCState,
161205}
162206
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+
163226enum OutboundHTLCState {
164227 /// Added by us and included in a commitment_signed (if we were AwaitingRemoteRevoke when we
165228 /// created it we would have put it in the holding cell instead). When they next revoke_and_ack
@@ -192,6 +255,44 @@ enum OutboundHTLCState {
192255 AwaitingRemovedRemoteRevoke(OutboundHTLCOutcome),
193256}
194257
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+
195296#[derive(Clone)]
196297enum OutboundHTLCOutcome {
197298 /// LDK version 0.0.105+ will always fill in the preimage here.
@@ -227,6 +328,27 @@ struct OutboundHTLCOutput {
227328 skimmed_fee_msat: Option<u64>,
228329}
229330
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+
230352/// See AwaitingRemoteRevoke ChannelState for more info
231353enum HTLCUpdateAwaitingACK {
232354 AddHTLC { // TODO: Time out if we're getting close to cltv_expiry
@@ -249,6 +371,39 @@ enum HTLCUpdateAwaitingACK {
249371 },
250372}
251373
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+
252407/// There are a few "states" and then a number of flags which can be applied:
253408/// We first move through init with `OurInitSent` -> `TheirInitSent` -> `FundingCreated` -> `FundingSent`.
254409/// `TheirChannelReady` and `OurChannelReady` then get set on `FundingSent`, and when both are set we
@@ -1549,6 +1704,94 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
15491704 stats
15501705 }
15511706
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+
15521795 /// Returns a HTLCStats about pending outbound htlcs, *including* pending adds in our holding cell.
15531796 fn get_outbound_pending_htlc_stats(&self, outbound_feerate_update: Option<u32>) -> HTLCStats {
15541797 let context = self;
0 commit comments