Skip to content

Commit 095041c

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 f8bea88 commit 095041c

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
@@ -1419,7 +1419,150 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
14191419
pub fn current_best_block(&self) -> BestBlock {
14201420
self.inner.lock().unwrap().best_block.clone()
14211421
}
1422+
}
1423+
1424+
impl<Signer: Sign> ChannelMonitorImpl<Signer> {
1425+
/// Helper for get_claimable_balances which does the work for an individual HTLC, generating up
1426+
/// to one `Balance` for the HTLC.
1427+
fn get_htlc_balance(&self, htlc: &HTLCOutputInCommitment, holder_commitment: bool,
1428+
counterparty_revoked_commitment: bool, confirmed_txid: Option<Txid>)
1429+
-> Option<Balance> {
1430+
let htlc_commitment_tx_output_idx =
1431+
if let Some(v) = htlc.transaction_output_index { v } else { return None; };
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);
14221481

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> {
14231566
/// Gets the balances in this channel which are either claimable by us if we were to
14241567
/// force-close the channel now or which are claimable on-chain (possibly awaiting
14251568
/// confirmation).
@@ -1460,136 +1603,10 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
14601603
macro_rules! walk_htlcs {
14611604
($holder_commitment: expr, $counterparty_revoked_commitment: expr, $htlc_iter: expr) => {
14621605
for htlc in $htlc_iter {
1463-
if let Some(htlc_commitment_tx_output_idx) = htlc.transaction_output_index {
1464-
let mut htlc_spend_txid_opt = None;
1465-
let mut htlc_update_pending = None;
1466-
let mut htlc_spend_pending = None;
1467-
let mut delayed_output_pending = None;
1468-
for event in us.onchain_events_awaiting_threshold_conf.iter() {
1469-
match event.event {
1470-
OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. }
1471-
if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => {
1472-
debug_assert!(htlc_spend_txid_opt.is_none());
1473-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1474-
debug_assert!(htlc_update_pending.is_none());
1475-
debug_assert_eq!(htlc_value_satoshis.unwrap(), htlc.amount_msat / 1000);
1476-
htlc_update_pending = Some(event.confirmation_threshold());
1477-
},
1478-
OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. }
1479-
if commitment_tx_output_idx == htlc_commitment_tx_output_idx => {
1480-
debug_assert!(htlc_spend_txid_opt.is_none());
1481-
htlc_spend_txid_opt = event.transaction.as_ref().map(|tx| tx.txid());
1482-
debug_assert!(htlc_spend_pending.is_none());
1483-
htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some()));
1484-
},
1485-
OnchainEvent::MaturingOutput {
1486-
descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) }
1487-
if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => {
1488-
debug_assert!(delayed_output_pending.is_none());
1489-
delayed_output_pending = Some(event.confirmation_threshold());
1490-
},
1491-
_ => {},
1492-
}
1493-
}
1494-
let htlc_resolved = us.htlcs_resolved_on_chain.iter()
1495-
.find(|v| if v.commitment_tx_output_idx == htlc_commitment_tx_output_idx {
1496-
debug_assert!(htlc_spend_txid_opt.is_none());
1497-
htlc_spend_txid_opt = v.resolving_txid;
1498-
true
1499-
} else { false });
1500-
debug_assert!(htlc_update_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1);
1501-
1502-
let htlc_output_to_spend =
1503-
if let Some(txid) = htlc_spend_txid_opt {
1504-
debug_assert!(
1505-
us.onchain_tx_handler.channel_transaction_parameters.opt_anchors.is_none(),
1506-
"This code needs updating for anchors");
1507-
BitcoinOutPoint::new(txid, 0)
1508-
} else {
1509-
BitcoinOutPoint::new(confirmed_txid.unwrap(), htlc_commitment_tx_output_idx)
1510-
};
1511-
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() {
15121607

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

0 commit comments

Comments
 (0)