Skip to content

Commit a52cf41

Browse files
committed
Move per-HTLC logic out of get_claimable_balances into a helper
Val suggested this as an obvious cleanup to separate per_HTLC logic from the total commitment transaction logic, separating the large function into two.
1 parent 26a44ad commit a52cf41

File tree

1 file changed

+146
-129
lines changed

1 file changed

+146
-129
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 146 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,7 +1423,150 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
14231423
pub fn current_best_block(&self) -> BestBlock {
14241424
self.inner.lock().unwrap().best_block.clone()
14251425
}
1426+
}
1427+
1428+
impl<Signer: Sign> ChannelMonitorImpl<Signer> {
1429+
/// Helper for get_claimable_balances which does the work for an individual HTLC, generating up
1430+
/// to one `Balance` for the HTLC.
1431+
fn get_htlc_balance(&self, htlc: &HTLCOutputInCommitment, holder_commitment: bool,
1432+
counterparty_revoked_commitment: bool, confirmed_txid: Option<Txid>)
1433+
-> Option<Balance> {
1434+
let htlc_commitment_tx_output_idx =
1435+
if let Some(v) = htlc.transaction_output_index { v } else { return None; };
1436+
1437+
let mut htlc_spend_txid_opt = None;
1438+
let mut holder_timeout_spend_pending = None;
1439+
let mut htlc_spend_pending = None;
1440+
let mut holder_delayed_output_pending = None;
1441+
for event in self.onchain_events_awaiting_threshold_conf.iter() {
1442+
match event.event {
1443+
OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. }
1444+
if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => {
1445+
debug_assert!(htlc_spend_txid_opt.is_none());
1446+
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1447+
debug_assert!(holder_timeout_spend_pending.is_none());
1448+
debug_assert_eq!(htlc_value_satoshis.unwrap(), htlc.amount_msat / 1000);
1449+
holder_timeout_spend_pending = Some(event.confirmation_threshold());
1450+
},
1451+
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. }
1452+
if commitment_tx_output_idx == htlc_commitment_tx_output_idx => {
1453+
debug_assert!(htlc_spend_txid_opt.is_none());
1454+
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1455+
debug_assert!(htlc_spend_pending.is_none());
1456+
htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some()));
1457+
},
1458+
OnchainEvent::MaturingOutput {
1459+
descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) }
1460+
if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => {
1461+
debug_assert!(holder_delayed_output_pending.is_none());
1462+
holder_delayed_output_pending = Some(event.confirmation_threshold());
1463+
},
1464+
_ => {},
1465+
}
1466+
}
1467+
let htlc_resolved = self.htlcs_resolved_on_chain.iter()
1468+
.find(|v| if v.commitment_tx_output_idx == htlc_commitment_tx_output_idx {
1469+
debug_assert!(htlc_spend_txid_opt.is_none());
1470+
htlc_spend_txid_opt = v.resolving_txid;
1471+
true
1472+
} else { false });
1473+
debug_assert!(holder_timeout_spend_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1);
1474+
1475+
let htlc_output_to_spend =
1476+
if let Some(txid) = htlc_spend_txid_opt {
1477+
debug_assert!(
1478+
self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_none(),
1479+
"This code needs updating for anchors");
1480+
BitcoinOutPoint::new(txid, 0)
1481+
} else {
1482+
BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx)
1483+
};
1484+
let htlc_output_spend_pending = self.onchain_tx_handler.is_output_spend_pending(&htlc_output_to_spend);
14261485

1486+
if let Some(conf_thresh) = holder_delayed_output_pending {
1487+
debug_assert!(holder_commitment);
1488+
return Some(Balance::ClaimableAwaitingConfirmations {
1489+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1490+
confirmation_height: conf_thresh,
1491+
});
1492+
} else if htlc_resolved.is_some() && !htlc_output_spend_pending {
1493+
// Funding transaction spends should be fully confirmed by the time any
1494+
// HTLC transactions are resolved, unless we're talking about a holder
1495+
// commitment tx, whose resolution is delayed until the CSV timeout is
1496+
// reached, even though HTLCs may be resolved after only
1497+
// ANTI_REORG_DELAY confirmations.
1498+
debug_assert!(holder_commitment || self.funding_spend_confirmed.is_some());
1499+
} else if counterparty_revoked_commitment {
1500+
let htlc_output_claim_pending = self.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
1501+
if let OnchainEvent::MaturingOutput {
1502+
descriptor: SpendableOutputDescriptor::StaticOutput { .. }
1503+
} = &event.event {
1504+
if event.transaction.as_ref().map(|tx| tx.input.iter().any(|inp| {
1505+
if let Some(htlc_spend_txid) = htlc_spend_txid_opt {
1506+
Some(tx.txid()) == htlc_spend_txid_opt ||
1507+
inp.previous_output.txid == htlc_spend_txid
1508+
} else {
1509+
Some(inp.previous_output.txid) == confirmed_txid &&
1510+
inp.previous_output.vout == htlc_commitment_tx_output_idx
1511+
}
1512+
})).unwrap_or(false) {
1513+
Some(())
1514+
} else { None }
1515+
} else { None }
1516+
});
1517+
if htlc_output_claim_pending.is_some() {
1518+
// We already push `Balance`s onto the `res` list for every
1519+
// `StaticOutput` in a `MaturingOutput` in the revoked
1520+
// counterparty commitment transaction case generally, so don't
1521+
// need to do so again here.
1522+
} else {
1523+
debug_assert!(holder_timeout_spend_pending.is_none(),
1524+
"HTLCUpdate OnchainEvents should never appear for preimage claims");
1525+
debug_assert!(!htlc.offered || htlc_spend_pending.is_none() || !htlc_spend_pending.unwrap().1,
1526+
"We don't (currently) generate preimage claims against revoked outputs, where did you get one?!");
1527+
return Some(Balance::CounterpartyRevokedOutputClaimable {
1528+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1529+
});
1530+
}
1531+
} else if htlc.offered == holder_commitment {
1532+
// If the payment was outbound, check if there's an HTLCUpdate
1533+
// indicating we have spent this HTLC with a timeout, claiming it back
1534+
// and awaiting confirmations on it.
1535+
if let Some(conf_thresh) = holder_timeout_spend_pending {
1536+
return Some(Balance::ClaimableAwaitingConfirmations {
1537+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1538+
confirmation_height: conf_thresh,
1539+
});
1540+
} else {
1541+
return Some(Balance::MaybeClaimableHTLCAwaitingTimeout {
1542+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1543+
claimable_height: htlc.cltv_expiry,
1544+
});
1545+
}
1546+
} else if self.payment_preimages.get(&htlc.payment_hash).is_some() {
1547+
// Otherwise (the payment was inbound), only expose it as claimable if
1548+
// we know the preimage.
1549+
// Note that if there is a pending claim, but it did not use the
1550+
// preimage, we lost funds to our counterparty! We will then continue
1551+
// to show it as ContentiousClaimable until ANTI_REORG_DELAY.
1552+
debug_assert!(holder_timeout_spend_pending.is_none());
1553+
if let Some((conf_thresh, true)) = htlc_spend_pending {
1554+
return Some(Balance::ClaimableAwaitingConfirmations {
1555+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1556+
confirmation_height: conf_thresh,
1557+
});
1558+
} else {
1559+
return Some(Balance::ContentiousClaimable {
1560+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1561+
timeout_height: htlc.cltv_expiry,
1562+
});
1563+
}
1564+
}
1565+
None
1566+
}
1567+
}
1568+
1569+
impl<Signer: Sign> ChannelMonitor<Signer> {
14271570
/// Gets the balances in this channel which are either claimable by us if we were to
14281571
/// force-close the channel now or which are claimable on-chain (possibly awaiting
14291572
/// confirmation).
@@ -1464,136 +1607,10 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
14641607
macro_rules! walk_htlcs {
14651608
($holder_commitment: expr, $counterparty_revoked_commitment: expr, $htlc_iter: expr) => {
14661609
for htlc in $htlc_iter {
1467-
if let Some(htlc_commitment_tx_output_idx) = htlc.transaction_output_index {
1468-
let mut htlc_spend_txid_opt = None;
1469-
let mut htlc_update_pending = None;
1470-
let mut htlc_spend_pending = None;
1471-
let mut delayed_output_pending = None;
1472-
for event in us.onchain_events_awaiting_threshold_conf.iter() {
1473-
match event.event {
1474-
OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. }
1475-
if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => {
1476-
debug_assert!(htlc_spend_txid_opt.is_none());
1477-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1478-
debug_assert!(htlc_update_pending.is_none());
1479-
debug_assert_eq!(htlc_value_satoshis.unwrap(), htlc.amount_msat / 1000);
1480-
htlc_update_pending = Some(event.confirmation_threshold());
1481-
},
1482-
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. }
1483-
if commitment_tx_output_idx == htlc_commitment_tx_output_idx => {
1484-
debug_assert!(htlc_spend_txid_opt.is_none());
1485-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1486-
debug_assert!(htlc_spend_pending.is_none());
1487-
htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some()));
1488-
},
1489-
OnchainEvent::MaturingOutput {
1490-
descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) }
1491-
if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => {
1492-
debug_assert!(delayed_output_pending.is_none());
1493-
delayed_output_pending = Some(event.confirmation_threshold());
1494-
},
1495-
_ => {},
1496-
}
1497-
}
1498-
let htlc_resolved = us.htlcs_resolved_on_chain.iter()
1499-
.find(|v| if v.commitment_tx_output_idx == htlc_commitment_tx_output_idx {
1500-
debug_assert!(htlc_spend_txid_opt.is_none());
1501-
htlc_spend_txid_opt = v.resolving_txid;
1502-
true
1503-
} else { false });
1504-
debug_assert!(htlc_update_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1);
1505-
1506-
let htlc_output_to_spend =
1507-
if let Some(txid) = htlc_spend_txid_opt {
1508-
debug_assert!(
1509-
us.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_none(),
1510-
"This code needs updating for anchors");
1511-
BitcoinOutPoint::new(txid, 0)
1512-
} else {
1513-
BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx)
1514-
};
1515-
let htlc_output_needs_spending = us.onchain_tx_handler.is_output_spend_pending(&htlc_output_to_spend);
1610+
if htlc.transaction_output_index.is_some() {
15161611

1517-
if let Some(conf_thresh) = delayed_output_pending {
1518-
debug_assert!($holder_commitment);
1519-
res.push(Balance::ClaimableAwaitingConfirmations {
1520-
claimable_amount_satoshis: htlc.amount_msat / 1000,
1521-
confirmation_height: conf_thresh,
1522-
});
1523-
} else if htlc_resolved.is_some() && !htlc_output_needs_spending {
1524-
// Funding transaction spends should be fully confirmed by the time any
1525-
// HTLC transactions are resolved, unless we're talking about a holder
1526-
// commitment tx, whose resolution is delayed until the CSV timeout is
1527-
// reached, even though HTLCs may be resolved after only
1528-
// ANTI_REORG_DELAY confirmations.
1529-
debug_assert!($holder_commitment || us.funding_spend_confirmed.is_some());
1530-
} else if $counterparty_revoked_commitment {
1531-
let htlc_output_claim_pending = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
1532-
if let OnchainEvent::MaturingOutput {
1533-
descriptor: SpendableOutputDescriptor::StaticOutput { .. }
1534-
} = &event.event {
1535-
if event.transaction.as_ref().map(|tx| tx.input.iter().any(|inp| {
1536-
if let Some(htlc_spend_txid) = htlc_spend_txid_opt {
1537-
Some(tx.txid()) == htlc_spend_txid_opt ||
1538-
inp.previous_output.txid == htlc_spend_txid
1539-
} else {
1540-
Some(inp.previous_output.txid) == confirmed_txid &&
1541-
inp.previous_output.vout == htlc_commitment_tx_output_idx
1542-
}
1543-
})).unwrap_or(false) {
1544-
Some(())
1545-
} else { None }
1546-
} else { None }
1547-
});
1548-
if htlc_output_claim_pending.is_some() {
1549-
// We already push `Balance`s onto the `res` list for every
1550-
// `StaticOutput` in a `MaturingOutput` in the revoked
1551-
// counterparty commitment transaction case generally, so don't
1552-
// need to do so again here.
1553-
} else {
1554-
debug_assert!(htlc_update_pending.is_none(),
1555-
"HTLCUpdate OnchainEvents should never appear for preimage claims");
1556-
debug_assert!(!htlc.offered || htlc_spend_pending.is_none() || !htlc_spend_pending.unwrap().1,
1557-
"We don't (currently) generate preimage claims against revoked outputs, where did you get one?!");
1558-
res.push(Balance::CounterpartyRevokedOutputClaimable {
1559-
claimable_amount_satoshis: htlc.amount_msat / 1000,
1560-
});
1561-
}
1562-
} else {
1563-
if htlc.offered == $holder_commitment {
1564-
// If the payment was outbound, check if there's an HTLCUpdate
1565-
// indicating we have spent this HTLC with a timeout, claiming it back
1566-
// and awaiting confirmations on it.
1567-
if let Some(conf_thresh) = htlc_update_pending {
1568-
res.push(Balance::ClaimableAwaitingConfirmations {
1569-
claimable_amount_satoshis: htlc.amount_msat / 1000,
1570-
confirmation_height: conf_thresh,
1571-
});
1572-
} else {
1573-
res.push(Balance::MaybeClaimableHTLCAwaitingTimeout {
1574-
claimable_amount_satoshis: htlc.amount_msat / 1000,
1575-
claimable_height: htlc.cltv_expiry,
1576-
});
1577-
}
1578-
} else if us.payment_preimages.get(&htlc.payment_hash).is_some() {
1579-
// Otherwise (the payment was inbound), only expose it as claimable if
1580-
// we know the preimage.
1581-
// Note that if there is a pending claim, but it did not use the
1582-
// preimage, we lost funds to our counterparty! We will then continue
1583-
// to show it as ContentiousClaimable until ANTI_REORG_DELAY.
1584-
debug_assert!(htlc_update_pending.is_none());
1585-
if let Some((conf_thresh, true)) = htlc_spend_pending {
1586-
res.push(Balance::ClaimableAwaitingConfirmations {
1587-
claimable_amount_satoshis: htlc.amount_msat / 1000,
1588-
confirmation_height: conf_thresh,
1589-
});
1590-
} else {
1591-
res.push(Balance::ContentiousClaimable {
1592-
claimable_amount_satoshis: htlc.amount_msat / 1000,
1593-
timeout_height: htlc.cltv_expiry,
1594-
});
1595-
}
1596-
}
1612+
if let Some(bal) = us.get_htlc_balance(htlc, $holder_commitment, $counterparty_revoked_commitment, confirmed_txid) {
1613+
res.push(bal);
15971614
}
15981615
}
15991616
}

0 commit comments

Comments
 (0)