Skip to content

Commit e8a1b37

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 4dcaa31 commit e8a1b37

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
@@ -1418,7 +1418,150 @@ 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+
let mut htlc_spend_txid_opt = None;
1433+
let mut holder_timeout_spend_pending = None;
1434+
let mut htlc_spend_pending = None;
1435+
let mut holder_delayed_output_pending = None;
1436+
for event in self.onchain_events_awaiting_threshold_conf.iter() {
1437+
match event.event {
1438+
OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. }
1439+
if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => {
1440+
debug_assert!(htlc_spend_txid_opt.is_none());
1441+
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1442+
debug_assert!(holder_timeout_spend_pending.is_none());
1443+
debug_assert_eq!(htlc_value_satoshis.unwrap(), htlc.amount_msat / 1000);
1444+
holder_timeout_spend_pending = Some(event.confirmation_threshold());
1445+
},
1446+
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. }
1447+
if commitment_tx_output_idx == htlc_commitment_tx_output_idx => {
1448+
debug_assert!(htlc_spend_txid_opt.is_none());
1449+
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1450+
debug_assert!(htlc_spend_pending.is_none());
1451+
htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some()));
1452+
},
1453+
OnchainEvent::MaturingOutput {
1454+
descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) }
1455+
if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => {
1456+
debug_assert!(holder_delayed_output_pending.is_none());
1457+
holder_delayed_output_pending = Some(event.confirmation_threshold());
1458+
},
1459+
_ => {},
1460+
}
1461+
}
1462+
let htlc_resolved = self.htlcs_resolved_on_chain.iter()
1463+
.find(|v| if v.commitment_tx_output_idx == htlc_commitment_tx_output_idx {
1464+
debug_assert!(htlc_spend_txid_opt.is_none());
1465+
htlc_spend_txid_opt = v.resolving_txid;
1466+
true
1467+
} else { false });
1468+
debug_assert!(holder_timeout_spend_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1);
1469+
1470+
let htlc_output_to_spend =
1471+
if let Some(txid) = htlc_spend_txid_opt {
1472+
debug_assert!(
1473+
self.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_none(),
1474+
"This code needs updating for anchors");
1475+
BitcoinOutPoint::new(txid, 0)
1476+
} else {
1477+
BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx)
1478+
};
1479+
let htlc_output_spend_pending = self.onchain_tx_handler.is_output_spend_pending(&htlc_output_to_spend);
14211480

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

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-
}
1607+
if let Some(bal) = us.get_htlc_balance(htlc, $holder_commitment, $counterparty_revoked_commitment, confirmed_txid) {
1608+
res.push(bal);
15921609
}
15931610
}
15941611
}

0 commit comments

Comments
 (0)