($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,
+ });
+ }
}
}
}