From: Matt Corallo Date: Tue, 17 May 2022 20:45:17 +0000 (+0000) Subject: Scan `onchain_events_awaiting_threshold_conf` once in balance calc X-Git-Tag: v0.0.111~34^2~3 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=a17794c3800c94fd23e767c1ee3ffd411d7ace81;p=rust-lightning Scan `onchain_events_awaiting_threshold_conf` once in balance calc Instead of a series of different `onchain_events_awaiting_threshold_conf.iter()...` calls to scan for HTLC status in balance calculation, pull them all out into one `for ... { match ... }` to do it once and simplify the code somewhat. --- diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs index 377657d6b..f08895718 100644 --- a/lightning/src/chain/channelmonitor.rs +++ b/lightning/src/chain/channelmonitor.rs @@ -1449,67 +1449,82 @@ impl ChannelMonitor { ($holder_commitment: expr, $htlc_iter: expr) => { for htlc in $htlc_iter { if let Some(htlc_commitment_tx_output_idx) = htlc.transaction_output_index { - if let Some(conf_thresh) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| { - if let OnchainEvent::MaturingOutput { descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(descriptor) } = &event.event { - if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx { Some(event.confirmation_threshold()) } else { None } - } else { None } - }) { + let mut htlc_update_pending = None; + let mut htlc_spend_pending = None; + let mut delayed_output_pending = None; + for event in us.onchain_events_awaiting_threshold_conf.iter() { + match event.event { + OnchainEvent::HTLCUpdate { commitment_tx_output_idx, htlc_value_satoshis, .. } + if commitment_tx_output_idx == Some(htlc_commitment_tx_output_idx) => { + debug_assert!(htlc_update_pending.is_none()); + htlc_update_pending = + Some((htlc_value_satoshis.unwrap(), event.confirmation_threshold())); + }, + OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } + if commitment_tx_output_idx == htlc_commitment_tx_output_idx => { + debug_assert!(htlc_spend_pending.is_none()); + htlc_spend_pending = Some((event.confirmation_threshold(), preimage.is_some())); + }, + OnchainEvent::MaturingOutput { + descriptor: SpendableOutputDescriptor::DelayedPaymentOutput(ref descriptor) } + if descriptor.outpoint.index as u32 == htlc_commitment_tx_output_idx => { + debug_assert!(delayed_output_pending.is_none()); + delayed_output_pending = Some(event.confirmation_threshold()); + }, + _ => {}, + } + } + let htlc_resolved = us.htlcs_resolved_on_chain.iter() + .find(|v| v.commitment_tx_output_idx == htlc_commitment_tx_output_idx); + debug_assert!(htlc_update_pending.is_some() as u8 + htlc_spend_pending.is_some() as u8 + htlc_resolved.is_some() as u8 <= 1); + + if let Some(conf_thresh) = delayed_output_pending { debug_assert!($holder_commitment); res.push(Balance::ClaimableAwaitingConfirmations { claimable_amount_satoshis: htlc.amount_msat / 1000, confirmation_height: conf_thresh, }); - } else if us.htlcs_resolved_on_chain.iter().any(|v| v.commitment_tx_output_idx == htlc_commitment_tx_output_idx) { + } else if htlc_resolved.is_some() { // Funding transaction spends should be fully confirmed by the time any // HTLC transactions are resolved, unless we're talking about a holder // commitment tx, whose resolution is delayed until the CSV timeout is // reached, even though HTLCs may be resolved after only // ANTI_REORG_DELAY confirmations. debug_assert!($holder_commitment || us.funding_spend_confirmed.is_some()); - } else if htlc.offered == $holder_commitment { - // If the payment was outbound, check if there's an HTLCUpdate - // indicating we have spent this HTLC with a timeout, claiming it back - // and awaiting confirmations on it. - let htlc_update_pending = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| { - if let OnchainEvent::HTLCUpdate { commitment_tx_output_idx: Some(commitment_tx_output_idx), .. } = event.event { - if commitment_tx_output_idx == htlc_commitment_tx_output_idx { - Some(event.confirmation_threshold()) } else { None } - } else { None } - }); - if let Some(conf_thresh) = htlc_update_pending { - res.push(Balance::ClaimableAwaitingConfirmations { - claimable_amount_satoshis: htlc.amount_msat / 1000, - confirmation_height: conf_thresh, - }); - } else { - res.push(Balance::MaybeClaimableHTLCAwaitingTimeout { - claimable_amount_satoshis: htlc.amount_msat / 1000, - claimable_height: htlc.cltv_expiry, - }); - } - } else if us.payment_preimages.get(&htlc.payment_hash).is_some() { - // Otherwise (the payment was inbound), only expose it as claimable if - // we know the preimage. - // Note that if there is a pending claim, but it did not use the - // preimage, we lost funds to our counterparty! We will then continue - // to show it as ContentiousClaimable until ANTI_REORG_DELAY. - let htlc_spend_pending = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| { - if let OnchainEvent::HTLCSpendConfirmation { commitment_tx_output_idx, preimage, .. } = event.event { - if commitment_tx_output_idx == htlc_commitment_tx_output_idx { - Some((event.confirmation_threshold(), preimage.is_some())) - } else { None } - } else { None } - }); - if let Some((conf_thresh, true)) = htlc_spend_pending { - res.push(Balance::ClaimableAwaitingConfirmations { - claimable_amount_satoshis: htlc.amount_msat / 1000, - confirmation_height: conf_thresh, - }); - } else { - res.push(Balance::ContentiousClaimable { - claimable_amount_satoshis: htlc.amount_msat / 1000, - timeout_height: htlc.cltv_expiry, - }); + } else { + if htlc.offered == $holder_commitment { + // If the payment was outbound, check if there's an HTLCUpdate + // indicating we have spent this HTLC with a timeout, claiming it back + // and awaiting confirmations on it. + if let Some((value, conf_thresh)) = htlc_update_pending { + res.push(Balance::ClaimableAwaitingConfirmations { + claimable_amount_satoshis: value, + confirmation_height: conf_thresh, + }); + } else { + res.push(Balance::MaybeClaimableHTLCAwaitingTimeout { + claimable_amount_satoshis: htlc.amount_msat / 1000, + claimable_height: htlc.cltv_expiry, + }); + } + } else if us.payment_preimages.get(&htlc.payment_hash).is_some() { + // Otherwise (the payment was inbound), only expose it as claimable if + // we know the preimage. + // Note that if there is a pending claim, but it did not use the + // preimage, we lost funds to our counterparty! We will then continue + // to show it as ContentiousClaimable until ANTI_REORG_DELAY. + debug_assert!(htlc_update_pending.is_none()); + if let Some((conf_thresh, true)) = htlc_spend_pending { + res.push(Balance::ClaimableAwaitingConfirmations { + claimable_amount_satoshis: htlc.amount_msat / 1000, + confirmation_height: conf_thresh, + }); + } else { + res.push(Balance::ContentiousClaimable { + claimable_amount_satoshis: htlc.amount_msat / 1000, + timeout_height: htlc.cltv_expiry, + }); + } } } }