Skip to content

Commit e142f67

Browse files
committed
Expose the full set of outbound HTLCs from a ChannelMonitor
This expands the outbound-HTLC-listing support in `ChannelMonitor` to include not only the set of outbound HTLCs which have not yet been resolved but to also include the full set of HTLCs which the `ChannelMonitor` is currently able to to or has already finalized. This will be used in the next commit to fail-back HTLCs which were removed from a channel in the ChannelMonitor but not in a Channel. Using the existing `get_pending_outbound_htlcs` for this purpose is subtly broken - if the channel is already closed, an HTLC fail may have completed on chain and is no longer "pending" to the monitor, but the fail event is still in the monitor waiting to be handed back to the `ChannelMonitor` when polled.
1 parent a4c4301 commit e142f67

File tree

1 file changed

+62
-46
lines changed

1 file changed

+62
-46
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 62 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,12 +1828,60 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
18281828
res
18291829
}
18301830

1831+
/// Gets the set of outbound HTLCs which can be (or have been) resolved by this
1832+
/// `ChannelMonitor`. This is used to determine if an HTLC was removed from the channel prior
1833+
/// to the `ChannelManager` having been persisted.
1834+
///
1835+
/// This is similar to [`Self::get_pending_outbound_htlcs`] except it includes HTLCs which were
1836+
/// resolved by this `ChannelMonitor`.
1837+
pub(crate) fn get_all_current_outbound_htlcs(&self) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
1838+
let mut res = HashMap::new();
1839+
// Just examine the available counterparty commitment transactions. See docs on
1840+
// `fail_unbroadcast_htlcs`, below, for justification.
1841+
let us = self.inner.lock().unwrap();
1842+
macro_rules! walk_counterparty_commitment {
1843+
($txid: expr) => {
1844+
if let Some(ref latest_outpoints) = us.counterparty_claimable_outpoints.get($txid) {
1845+
for &(ref htlc, ref source_option) in latest_outpoints.iter() {
1846+
if let &Some(ref source) = source_option {
1847+
res.insert((**source).clone(), htlc.clone());
1848+
}
1849+
}
1850+
}
1851+
}
1852+
}
1853+
if let Some(ref txid) = us.current_counterparty_commitment_txid {
1854+
walk_counterparty_commitment!(txid);
1855+
}
1856+
if let Some(ref txid) = us.prev_counterparty_commitment_txid {
1857+
walk_counterparty_commitment!(txid);
1858+
}
1859+
res
1860+
}
1861+
18311862
/// Gets the set of outbound HTLCs which are pending resolution in this channel.
18321863
/// This is used to reconstruct pending outbound payments on restart in the ChannelManager.
18331864
pub(crate) fn get_pending_outbound_htlcs(&self) -> HashMap<HTLCSource, HTLCOutputInCommitment> {
1834-
let mut res = HashMap::new();
18351865
let us = self.inner.lock().unwrap();
1866+
// We're only concerned with the confirmation count of HTLC transactions, and don't
1867+
// actually care how many confirmations a commitment transaction may or may not have. Thus,
1868+
// we look for either a FundingSpendConfirmation event or a funding_spend_confirmed.
1869+
let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
1870+
us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
1871+
if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
1872+
Some(event.txid)
1873+
} else { None }
1874+
})
1875+
});
1876+
1877+
if confirmed_txid.is_none() {
1878+
// If we have not seen a commitment transaction on-chain (ie the channel is not yet
1879+
// closed), just get the full set.
1880+
mem::drop(us);
1881+
return self.get_all_current_outbound_htlcs();
1882+
}
18361883

1884+
let mut res = HashMap::new();
18371885
macro_rules! walk_htlcs {
18381886
($holder_commitment: expr, $htlc_iter: expr) => {
18391887
for (htlc, source) in $htlc_iter {
@@ -1869,54 +1917,22 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
18691917
}
18701918
}
18711919

1872-
// We're only concerned with the confirmation count of HTLC transactions, and don't
1873-
// actually care how many confirmations a commitment transaction may or may not have. Thus,
1874-
// we look for either a FundingSpendConfirmation event or a funding_spend_confirmed.
1875-
let confirmed_txid = us.funding_spend_confirmed.or_else(|| {
1876-
us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
1877-
if let OnchainEvent::FundingSpendConfirmation { .. } = event.event {
1878-
Some(event.txid)
1920+
let txid = confirmed_txid.unwrap();
1921+
if Some(txid) == us.current_counterparty_commitment_txid || Some(txid) == us.prev_counterparty_commitment_txid {
1922+
walk_htlcs!(false, us.counterparty_claimable_outpoints.get(&txid).unwrap().iter().filter_map(|(a, b)| {
1923+
if let &Some(ref source) = b {
1924+
Some((a, &**source))
18791925
} else { None }
1880-
})
1881-
});
1882-
if let Some(txid) = confirmed_txid {
1883-
if Some(txid) == us.current_counterparty_commitment_txid || Some(txid) == us.prev_counterparty_commitment_txid {
1884-
walk_htlcs!(false, us.counterparty_claimable_outpoints.get(&txid).unwrap().iter().filter_map(|(a, b)| {
1885-
if let &Some(ref source) = b {
1886-
Some((a, &**source))
1887-
} else { None }
1888-
}));
1889-
} else if txid == us.current_holder_commitment_tx.txid {
1890-
walk_htlcs!(true, us.current_holder_commitment_tx.htlc_outputs.iter().filter_map(|(a, _, c)| {
1926+
}));
1927+
} else if txid == us.current_holder_commitment_tx.txid {
1928+
walk_htlcs!(true, us.current_holder_commitment_tx.htlc_outputs.iter().filter_map(|(a, _, c)| {
1929+
if let Some(source) = c { Some((a, source)) } else { None }
1930+
}));
1931+
} else if let Some(prev_commitment) = &us.prev_holder_signed_commitment_tx {
1932+
if txid == prev_commitment.txid {
1933+
walk_htlcs!(true, prev_commitment.htlc_outputs.iter().filter_map(|(a, _, c)| {
18911934
if let Some(source) = c { Some((a, source)) } else { None }
18921935
}));
1893-
} else if let Some(prev_commitment) = &us.prev_holder_signed_commitment_tx {
1894-
if txid == prev_commitment.txid {
1895-
walk_htlcs!(true, prev_commitment.htlc_outputs.iter().filter_map(|(a, _, c)| {
1896-
if let Some(source) = c { Some((a, source)) } else { None }
1897-
}));
1898-
}
1899-
}
1900-
} else {
1901-
// If we have not seen a commitment transaction on-chain (ie the channel is not yet
1902-
// closed), just examine the available counterparty commitment transactions. See docs
1903-
// on `fail_unbroadcast_htlcs`, below, for justification.
1904-
macro_rules! walk_counterparty_commitment {
1905-
($txid: expr) => {
1906-
if let Some(ref latest_outpoints) = us.counterparty_claimable_outpoints.get($txid) {
1907-
for &(ref htlc, ref source_option) in latest_outpoints.iter() {
1908-
if let &Some(ref source) = source_option {
1909-
res.insert((**source).clone(), htlc.clone());
1910-
}
1911-
}
1912-
}
1913-
}
1914-
}
1915-
if let Some(ref txid) = us.current_counterparty_commitment_txid {
1916-
walk_counterparty_commitment!(txid);
1917-
}
1918-
if let Some(ref txid) = us.prev_counterparty_commitment_txid {
1919-
walk_counterparty_commitment!(txid);
19201936
}
19211937
}
19221938

0 commit comments

Comments
 (0)