Skip to content

Commit 529da61

Browse files
committed
Include pending HTLC's in ChannelDetails
1 parent 6f58072 commit 529da61

File tree

4 files changed

+277
-1
lines changed

4 files changed

+277
-1
lines changed

fuzz/src/router.rs

+3
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,9 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
241241
config: None,
242242
feerate_sat_per_1000_weight: None,
243243
channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
244+
pending_inbound_htlcs: Vec::new(),
245+
pending_outbound_htlcs: Vec::new(),
246+
holding_cell_updates: Vec::new(),
244247
});
245248
}
246249
Some(&$first_hops_vec[..])

lightning/src/ln/channel.rs

+243
Original file line numberDiff line numberDiff line change
@@ -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+
155199
struct 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+
163226
enum 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)]
196297
enum 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
231353
enum 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;

lightning/src/ln/channelmanager.rs

+25-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa
4040
// Since this struct is returned in `list_channels` methods, expose it here in case users want to
4141
// construct one themselves.
4242
use crate::ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret};
43-
use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
43+
use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel, InboundHTLCDetails, OutboundHTLCDetails, HTLCUpdateAwaitingACKDetails};
4444
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
4545
#[cfg(any(feature = "_test_utils", test))]
4646
use crate::ln::features::Bolt11InvoiceFeatures;
@@ -1505,6 +1505,18 @@ pub struct ChannelDetails {
15051505
///
15061506
/// This field is only `None` for `ChannelDetails` objects serialized prior to LDK 0.0.109.
15071507
pub config: Option<ChannelConfig>,
1508+
/// Pending inbound HTLCs.
1509+
///
1510+
/// This field is empty for objects serialized with LDK versions prior to 0.0.117.
1511+
pub pending_inbound_htlcs: Vec<InboundHTLCDetails>,
1512+
/// Pending outbound HTLCs.
1513+
///
1514+
/// This field is empty for objects serialized with LDK versions prior to 0.0.117.
1515+
pub pending_outbound_htlcs: Vec<OutboundHTLCDetails>,
1516+
/// Pending HTLC updates that are held awaiting a revoke_and_ack.
1517+
///
1518+
/// This field is empty for objects serialized with LDK versions prior to 0.0.117.
1519+
pub holding_cell_updates: Vec<HTLCUpdateAwaitingACKDetails>,
15081520
}
15091521

15101522
impl ChannelDetails {
@@ -1580,6 +1592,9 @@ impl ChannelDetails {
15801592
inbound_htlc_maximum_msat: context.get_holder_htlc_maximum_msat(),
15811593
config: Some(context.config()),
15821594
channel_shutdown_state: Some(context.shutdown_state()),
1595+
pending_inbound_htlcs: context.get_pending_inbound_htlc_details(),
1596+
pending_outbound_htlcs: context.get_pending_outbound_htlc_details(),
1597+
holding_cell_updates: context.get_holding_cell_details(),
15831598
}
15841599
}
15851600
}
@@ -7530,6 +7545,9 @@ impl Writeable for ChannelDetails {
75307545
(37, user_channel_id_high_opt, option),
75317546
(39, self.feerate_sat_per_1000_weight, option),
75327547
(41, self.channel_shutdown_state, option),
7548+
(43, self.pending_inbound_htlcs, optional_vec),
7549+
(45, self.pending_outbound_htlcs, optional_vec),
7550+
(47, self.holding_cell_updates, optional_vec),
75337551
});
75347552
Ok(())
75357553
}
@@ -7568,6 +7586,9 @@ impl Readable for ChannelDetails {
75687586
(37, user_channel_id_high_opt, option),
75697587
(39, feerate_sat_per_1000_weight, option),
75707588
(41, channel_shutdown_state, option),
7589+
(43, pending_inbound_htlcs, optional_vec),
7590+
(45, pending_outbound_htlcs, optional_vec),
7591+
(47, holding_cell_updates, optional_vec),
75717592
});
75727593

75737594
// `user_channel_id` used to be a single u64 value. In order to remain backwards compatible with
@@ -7604,6 +7625,9 @@ impl Readable for ChannelDetails {
76047625
inbound_htlc_maximum_msat,
76057626
feerate_sat_per_1000_weight,
76067627
channel_shutdown_state,
7628+
pending_inbound_htlcs: pending_inbound_htlcs.unwrap_or(Vec::new()),
7629+
pending_outbound_htlcs: pending_outbound_htlcs.unwrap_or(Vec::new()),
7630+
holding_cell_updates: holding_cell_updates.unwrap_or(Vec::new()),
76077631
})
76087632
}
76097633
}

lightning/src/routing/router.rs

+6
Original file line numberDiff line numberDiff line change
@@ -2741,6 +2741,9 @@ mod tests {
27412741
config: None,
27422742
feerate_sat_per_1000_weight: None,
27432743
channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
2744+
pending_inbound_htlcs: Vec::new(),
2745+
pending_outbound_htlcs: Vec::new(),
2746+
holding_cell_updates: Vec::new(),
27442747
}
27452748
}
27462749

@@ -6812,6 +6815,9 @@ pub(crate) mod bench_utils {
68126815
config: None,
68136816
feerate_sat_per_1000_weight: None,
68146817
channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown),
6818+
pending_inbound_htlcs: Vec::new(),
6819+
pending_outbound_htlcs: Vec::new(),
6820+
holding_cell_updates: Vec::new(),
68156821
}
68166822
}
68176823

0 commit comments

Comments
 (0)