Skip to content

Commit 2110eae

Browse files
committed
Expose the amount of funds available for claim in ChannelMonitor
In general, we should always allow users to query for how much is currently in-flight being claimed on-chain at any time. This does so by examining the confirmed claims on-chain and breaking down what is left to be claimed into a new `ClaimableBalance` enum. Fixes #995.
1 parent b8414b7 commit 2110eae

File tree

2 files changed

+468
-2
lines changed

2 files changed

+468
-2
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,56 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
511511
},
512512
);
513513

514+
/// Details about the balance available for claim once the channel appears on chain.
515+
#[derive(Clone, Debug, PartialEq, Eq)]
516+
#[cfg_attr(test, derive(PartialOrd, Ord))]
517+
pub enum ClaimableBalance {
518+
/// The channel is not yet closed (or the initial commitment or closing transaction has not yet
519+
/// been confirmed). The given balance is claimable (less on-chain fees) if the channel is
520+
/// force-closed now.
521+
ClaimableOnChannelClose {
522+
/// The amount available to claim, in satoshis, ignoring the on-chain fees which will be
523+
/// required to do so.
524+
claimable_amount_satoshis: u64,
525+
},
526+
/// The channel has been closed, and the given balance is ours but awaiting confirmations until
527+
/// we consider it spendable.
528+
ClaimableAwaitingConfirmations {
529+
/// The amount available to claim, in satoshis, possibly ignoring the on-chain fees which
530+
/// were spent in broadcasting the transaction.
531+
claimable_amount_satoshis: u64,
532+
/// The height at which an [`Event::SpendableOutputs`] event will be generated for this
533+
/// amount.
534+
confirmation_height: u32,
535+
},
536+
/// The channel has been closed, and the given balance should be ours but awaiting spending
537+
/// transaction confirmation. If the spending transaction does not confirm in time, it is
538+
/// possible our counterparty can take the funds by broadcasting an HTLC timeout on-chain.
539+
///
540+
/// Once the spending transaction confirms, before it has reached enough confirmations to be
541+
/// considered safe from chain reorganizations, the balance will instead be provided via
542+
/// [`ClaimableBalance::ClaimableAwaitingConfirmations`].
543+
ContentiousClaimable {
544+
/// The amount available to claim, in satoshis, ignoring the on-chain fees which will be
545+
/// required to do so.
546+
claimable_amount_satoshis: u64,
547+
/// The height at which the counterparty may be able to claim the balance if we have not
548+
/// done so.
549+
timeout_height: u32,
550+
},
551+
/// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain
552+
/// fees) if the counterparty does not know the preimage for the HTLCs. These are somewhat
553+
/// likely to be claimed by our counterparty before we do.
554+
PossiblyClaimableHTLCAwaitingTimeout {
555+
/// The amount available to claim, in satoshis, ignoring the on-chain fees which will be
556+
/// required to do so.
557+
claimable_amount_satoshis: u64,
558+
/// The height at which we will be able to claim the balance if our counterparty has not
559+
/// done so.
560+
claimable_height: u32,
561+
},
562+
}
563+
514564
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
515565
#[derive(PartialEq)]
516566
struct HTLCIrrevocablyResolved {
@@ -1273,6 +1323,107 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
12731323
pub fn current_best_block(&self) -> BestBlock {
12741324
self.inner.lock().unwrap().best_block.clone()
12751325
}
1326+
1327+
/// Gets the balances in this channel which are either claimable by us if we were to
1328+
/// force-close the channel now or which are claimable on-chain or claims which are awaiting
1329+
/// confirmation.
1330+
///
1331+
/// Any balances in the channel which are available on-chain (ignoring on-chain fees) are
1332+
/// included here until an [`Event::SpendableOutputs`] event has been generated for the
1333+
/// balance, or until our counterparty has claimed the balance and accrued several
1334+
/// confirmations on the claim transaction.
1335+
///
1336+
/// See [`ClaimableBalance`] for additional details on the types of claimable balances which
1337+
/// may be returned here and their meanings.
1338+
pub fn get_claimable_balances(&self) -> Vec<ClaimableBalance> {
1339+
let mut res = Vec::new();
1340+
let us = self.inner.lock().unwrap();
1341+
1342+
let mut confirmed_txid = us.funding_spend_confirmed;
1343+
if let Some((txid, conf_thresh)) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
1344+
if let OnchainEvent::FundingSpendConfirmation { txid, .. } = event.event {
1345+
Some((txid, event.confirmation_threshold()))
1346+
} else { None }
1347+
}) {
1348+
debug_assert!(us.funding_spend_confirmed.is_none(), "We have a pending funding spend awaiting confirmation, we can't have confirmed it already!");
1349+
confirmed_txid = Some(txid);
1350+
res.push(ClaimableBalance::ClaimableAwaitingConfirmations {
1351+
claimable_amount_satoshis: us.current_holder_commitment_tx.to_self_value_sat,
1352+
confirmation_height: conf_thresh,
1353+
});
1354+
}
1355+
1356+
macro_rules! walk_htlcs {
1357+
($holder_commitment: expr, $htlc_iter: expr) => {
1358+
for htlc in $htlc_iter {
1359+
if let Some(htlc_input_idx) = htlc.transaction_output_index {
1360+
if us.htlcs_resolved_on_chain.iter().any(|v| v.input_idx == htlc_input_idx) {
1361+
assert!(us.funding_spend_confirmed.is_some());
1362+
} else if htlc.offered == $holder_commitment {
1363+
res.push(ClaimableBalance::PossiblyClaimableHTLCAwaitingTimeout {
1364+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1365+
claimable_height: htlc.cltv_expiry,
1366+
});
1367+
} else {
1368+
if us.payment_preimages.get(&htlc.payment_hash).is_some() {
1369+
if let Some(conf_thresh) = us.onchain_events_awaiting_threshold_conf.iter().find_map(|event| {
1370+
if let OnchainEvent::HTLCSpendConfirmation { input_idx, .. } = event.event {
1371+
if input_idx == htlc_input_idx { Some(event.confirmation_threshold()) } else { None }
1372+
} else { None }
1373+
}) {
1374+
res.push(ClaimableBalance::ClaimableAwaitingConfirmations {
1375+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1376+
confirmation_height: conf_thresh,
1377+
});
1378+
} else {
1379+
res.push(ClaimableBalance::ContentiousClaimable {
1380+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1381+
timeout_height: htlc.cltv_expiry,
1382+
});
1383+
}
1384+
}
1385+
}
1386+
}
1387+
}
1388+
}
1389+
}
1390+
1391+
if let Some(txid) = confirmed_txid {
1392+
if Some(txid) == us.current_counterparty_commitment_txid || Some(txid) == us.prev_counterparty_commitment_txid {
1393+
walk_htlcs!(false, us.counterparty_claimable_outpoints.get(&txid).unwrap().iter().map(|(a, _)| a));
1394+
} else if txid == us.current_holder_commitment_tx.txid {
1395+
walk_htlcs!(true, us.current_holder_commitment_tx.htlc_outputs.iter().map(|(a, _, _)| a));
1396+
} else if let Some(prev_commitment) = &us.prev_holder_signed_commitment_tx {
1397+
if txid == prev_commitment.txid {
1398+
walk_htlcs!(true, prev_commitment.htlc_outputs.iter().map(|(a, _, _)| a));
1399+
}
1400+
}
1401+
// TODO: Add logic to provide claimable balances for counterparty broadcasting revoked
1402+
// outputs.
1403+
// Otherwise assume we closed with a cooperative close which only needs the
1404+
// `ClaimableAwaitingConfirmations` balance pushed first.
1405+
} else {
1406+
let mut claimable_inbound_htlc_value_sat = 0;
1407+
for (htlc, _, _) in us.current_holder_commitment_tx.htlc_outputs.iter() {
1408+
if htlc.transaction_output_index.is_none() { continue; }
1409+
if htlc.offered {
1410+
res.push(ClaimableBalance::PossiblyClaimableHTLCAwaitingTimeout {
1411+
claimable_amount_satoshis: htlc.amount_msat / 1000,
1412+
claimable_height: htlc.cltv_expiry,
1413+
});
1414+
} else {
1415+
if us.payment_preimages.get(&htlc.payment_hash).is_some() {
1416+
claimable_inbound_htlc_value_sat += htlc.amount_msat / 1000;
1417+
}
1418+
}
1419+
}
1420+
res.push(ClaimableBalance::ClaimableOnChannelClose {
1421+
claimable_amount_satoshis: us.current_holder_commitment_tx.to_self_value_sat + claimable_inbound_htlc_value_sat,
1422+
});
1423+
}
1424+
1425+
res
1426+
}
12761427
}
12771428

12781429
/// Compares a broadcasted commitment transaction's HTLCs with those in the latest state,

0 commit comments

Comments
 (0)