Skip to content

Commit d8651e3

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 5a8ede0 commit d8651e3

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

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

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

0 commit comments

Comments
 (0)