Skip to content

Commit b355a1f

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 6424fb2 commit b355a1f

File tree

1 file changed

+61
-46
lines changed

1 file changed

+61
-46
lines changed

lightning/src/chain/channelmonitor.rs

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

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

1883+
let mut res = HashMap::new();
18371884
macro_rules! walk_htlcs {
18381885
($holder_commitment: expr, $htlc_iter: expr) => {
18391886
for (htlc, source) in $htlc_iter {
@@ -1869,54 +1916,22 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
18691916
}
18701917
}
18711918

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)
1919+
let txid = confirmed_txid.unwrap();
1920+
if Some(txid) == us.current_counterparty_commitment_txid || Some(txid) == us.prev_counterparty_commitment_txid {
1921+
walk_htlcs!(false, us.counterparty_claimable_outpoints.get(&txid).unwrap().iter().filter_map(|(a, b)| {
1922+
if let &Some(ref source) = b {
1923+
Some((a, &**source))
18791924
} 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)| {
1925+
}));
1926+
} else if txid == us.current_holder_commitment_tx.txid {
1927+
walk_htlcs!(true, us.current_holder_commitment_tx.htlc_outputs.iter().filter_map(|(a, _, c)| {
1928+
if let Some(source) = c { Some((a, source)) } else { None }
1929+
}));
1930+
} else if let Some(prev_commitment) = &us.prev_holder_signed_commitment_tx {
1931+
if txid == prev_commitment.txid {
1932+
walk_htlcs!(true, prev_commitment.htlc_outputs.iter().filter_map(|(a, _, c)| {
18911933
if let Some(source) = c { Some((a, source)) } else { None }
18921934
}));
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);
19201935
}
19211936
}
19221937

0 commit comments

Comments
 (0)