Skip to content

Commit 58e2aea

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 6817957 commit 58e2aea

File tree

1 file changed

+147
-129
lines changed

1 file changed

+147
-129
lines changed

lightning/src/chain/channelmonitor.rs

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

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

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

0 commit comments

Comments
 (0)