@@ -535,6 +535,59 @@ impl_writeable_tlv_based_enum_upgradable!(ChannelMonitorUpdateStep,
535
535
} ,
536
536
) ;
537
537
538
+ /// Details about the balance(s) available for spending once the channel appears on chain.
539
+ ///
540
+ /// See [`ChannelMonitor::get_claimable_balances`] for more details on when these will or will not
541
+ /// be provided.
542
+ #[ derive( Clone , Debug , PartialEq , Eq ) ]
543
+ #[ cfg_attr( test, derive( PartialOrd , Ord ) ) ]
544
+ pub enum Balance {
545
+ /// The channel is not yet closed (or the commitment or closing transaction has not yet
546
+ /// appeared in a block). The given balance is claimable (less on-chain fees) if the channel is
547
+ /// force-closed now.
548
+ ClaimableOnChannelClose {
549
+ /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
550
+ /// required to do so.
551
+ claimable_amount_satoshis : u64 ,
552
+ } ,
553
+ /// The channel has been closed, and the given balance is ours but awaiting confirmations until
554
+ /// we consider it spendable.
555
+ ClaimableAwaitingConfirmations {
556
+ /// The amount available to claim, in satoshis, possibly excluding the on-chain fees which
557
+ /// were spent in broadcasting the transaction.
558
+ claimable_amount_satoshis : u64 ,
559
+ /// The height at which an [`Event::SpendableOutputs`] event will be generated for this
560
+ /// amount.
561
+ confirmation_height : u32 ,
562
+ } ,
563
+ /// The channel has been closed, and the given balance should be ours but awaiting spending
564
+ /// transaction confirmation. If the spending transaction does not confirm in time, it is
565
+ /// possible our counterparty can take the funds by broadcasting an HTLC timeout on-chain.
566
+ ///
567
+ /// Once the spending transaction confirms, before it has reached enough confirmations to be
568
+ /// considered safe from chain reorganizations, the balance will instead be provided via
569
+ /// [`Balance::ClaimableAwaitingConfirmations`].
570
+ ContentiousClaimable {
571
+ /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
572
+ /// required to do so.
573
+ claimable_amount_satoshis : u64 ,
574
+ /// The height at which the counterparty may be able to claim the balance if we have not
575
+ /// done so.
576
+ timeout_height : u32 ,
577
+ } ,
578
+ /// HTLCs which we sent to our counterparty which are claimable after a timeout (less on-chain
579
+ /// fees) if the counterparty does not know the preimage for the HTLCs. These are somewhat
580
+ /// likely to be claimed by our counterparty before we do.
581
+ MaybeClaimableHTLCAwaitingTimeout {
582
+ /// The amount available to claim, in satoshis, excluding the on-chain fees which will be
583
+ /// required to do so.
584
+ claimable_amount_satoshis : u64 ,
585
+ /// The height at which we will be able to claim the balance if our counterparty has not
586
+ /// done so.
587
+ claimable_height : u32 ,
588
+ } ,
589
+ }
590
+
538
591
/// An HTLC which has been irrevocably resolved on-chain, and has reached ANTI_REORG_DELAY.
539
592
#[ derive( PartialEq ) ]
540
593
struct IrrevocablyResolvedHTLC {
@@ -1302,6 +1355,173 @@ impl<Signer: Sign> ChannelMonitor<Signer> {
1302
1355
pub fn current_best_block ( & self ) -> BestBlock {
1303
1356
self . inner . lock ( ) . unwrap ( ) . best_block . clone ( )
1304
1357
}
1358
+
1359
+ /// Gets the balances in this channel which are either claimable by us if we were to
1360
+ /// force-close the channel now or which are claimable on-chain (possibly awaiting
1361
+ /// confirmation).
1362
+ ///
1363
+ /// Any balances in the channel which are available on-chain (excluding on-chain fees) are
1364
+ /// included here until an [`Event::SpendableOutputs`] event has been generated for the
1365
+ /// balance, or until our counterparty has claimed the balance and accrued several
1366
+ /// confirmations on the claim transaction.
1367
+ ///
1368
+ /// Note that the balances available when you or your counterparty have broadcasted revoked
1369
+ /// state(s) may not be fully captured here.
1370
+ // TODO, fix that ^
1371
+ ///
1372
+ /// See [`Balance`] for additional details on the types of claimable balances which
1373
+ /// may be returned here and their meanings.
1374
+ pub fn get_claimable_balances ( & self ) -> Vec < Balance > {
1375
+ let mut res = Vec :: new ( ) ;
1376
+ let us = self . inner . lock ( ) . unwrap ( ) ;
1377
+
1378
+ let mut confirmed_txid = us. funding_spend_confirmed ;
1379
+ let mut pending_commitment_tx_conf_thresh = None ;
1380
+ let funding_spend_pending = us. onchain_events_awaiting_threshold_conf . iter ( ) . find_map ( |event| {
1381
+ if let OnchainEvent :: FundingSpendConfirmation { .. } = event. event {
1382
+ Some ( ( event. txid , event. confirmation_threshold ( ) ) )
1383
+ } else { None }
1384
+ } ) ;
1385
+ if let Some ( ( txid, conf_thresh) ) = funding_spend_pending {
1386
+ debug_assert ! ( us. funding_spend_confirmed. is_none( ) ,
1387
+ "We have a pending funding spend awaiting anti-reorg confirmation, we can't have confirmed it already!" ) ;
1388
+ confirmed_txid = Some ( txid) ;
1389
+ pending_commitment_tx_conf_thresh = Some ( conf_thresh) ;
1390
+ }
1391
+
1392
+ macro_rules! walk_htlcs {
1393
+ ( $holder_commitment: expr, $htlc_iter: expr) => {
1394
+ for htlc in $htlc_iter {
1395
+ if let Some ( htlc_input_idx) = htlc. transaction_output_index {
1396
+ if us. htlcs_resolved_on_chain. iter( ) . any( |v| v. input_idx == htlc_input_idx) {
1397
+ assert!( us. funding_spend_confirmed. is_some( ) ) ;
1398
+ } else if htlc. offered == $holder_commitment {
1399
+ // If the payment was outbound, check if there's an HTLCUpdate
1400
+ // indicating we have spent this HTLC with a timeout, claiming it back
1401
+ // and awaiting confirmations on it.
1402
+ let htlc_update_pending = us. onchain_events_awaiting_threshold_conf. iter( ) . find_map( |event| {
1403
+ if let OnchainEvent :: HTLCUpdate { input_idx: Some ( input_idx) , .. } = event. event {
1404
+ if input_idx == htlc_input_idx { Some ( event. confirmation_threshold( ) ) } else { None }
1405
+ } else { None }
1406
+ } ) ;
1407
+ if let Some ( conf_thresh) = htlc_update_pending {
1408
+ res. push( Balance :: ClaimableAwaitingConfirmations {
1409
+ claimable_amount_satoshis: htlc. amount_msat / 1000 ,
1410
+ confirmation_height: conf_thresh,
1411
+ } ) ;
1412
+ } else {
1413
+ res. push( Balance :: MaybeClaimableHTLCAwaitingTimeout {
1414
+ claimable_amount_satoshis: htlc. amount_msat / 1000 ,
1415
+ claimable_height: htlc. cltv_expiry,
1416
+ } ) ;
1417
+ }
1418
+ } else if us. payment_preimages. get( & htlc. payment_hash) . is_some( ) {
1419
+ // Otherwise (the payment was inbound), only expose it as claimable if
1420
+ // we know the preimage.
1421
+ // Note that if there is a pending claim, but it did not use the
1422
+ // preimage, we lost funds to our counterparty! We will then continue
1423
+ // to show it as ContentiousClaimable until ANTI_REORG_DELAY.
1424
+ let htlc_spend_pending = us. onchain_events_awaiting_threshold_conf. iter( ) . find_map( |event| {
1425
+ if let OnchainEvent :: HTLCSpendConfirmation { input_idx, preimage, .. } = event. event {
1426
+ if input_idx == htlc_input_idx {
1427
+ Some ( ( event. confirmation_threshold( ) , preimage. is_some( ) ) )
1428
+ } else { None }
1429
+ } else { None }
1430
+ } ) ;
1431
+ if let Some ( ( conf_thresh, true ) ) = htlc_spend_pending {
1432
+ res. push( Balance :: ClaimableAwaitingConfirmations {
1433
+ claimable_amount_satoshis: htlc. amount_msat / 1000 ,
1434
+ confirmation_height: conf_thresh,
1435
+ } ) ;
1436
+ } else {
1437
+ res. push( Balance :: ContentiousClaimable {
1438
+ claimable_amount_satoshis: htlc. amount_msat / 1000 ,
1439
+ timeout_height: htlc. cltv_expiry,
1440
+ } ) ;
1441
+ }
1442
+ }
1443
+ }
1444
+ }
1445
+ }
1446
+ }
1447
+
1448
+ if let Some ( txid) = confirmed_txid {
1449
+ let mut found_commitment_tx = false ;
1450
+ if Some ( txid) == us. current_counterparty_commitment_txid || Some ( txid) == us. prev_counterparty_commitment_txid {
1451
+ walk_htlcs ! ( false , us. counterparty_claimable_outpoints. get( & txid) . unwrap( ) . iter( ) . map( |( a, _) | a) ) ;
1452
+ if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
1453
+ if let Some ( value) = us. onchain_events_awaiting_threshold_conf . iter ( ) . find_map ( |event| {
1454
+ if let OnchainEvent :: MaturingOutput {
1455
+ descriptor : SpendableOutputDescriptor :: StaticPaymentOutput ( descriptor)
1456
+ } = & event. event {
1457
+ Some ( descriptor. output . value )
1458
+ } else { None }
1459
+ } ) {
1460
+ res. push ( Balance :: ClaimableAwaitingConfirmations {
1461
+ claimable_amount_satoshis : value,
1462
+ confirmation_height : conf_thresh,
1463
+ } ) ;
1464
+ } else {
1465
+ // If a counterparty commitment transaction is awaiting confirmation, we
1466
+ // should either have a StaticPaymentOutput MaturingOutput event awaiting
1467
+ // confirmation with the same height or have never met our dust amount.
1468
+ }
1469
+ }
1470
+ found_commitment_tx = true ;
1471
+ } else if txid == us. current_holder_commitment_tx . txid {
1472
+ walk_htlcs ! ( true , us. current_holder_commitment_tx. htlc_outputs. iter( ) . map( |( a, _, _) | a) ) ;
1473
+ if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
1474
+ res. push ( Balance :: ClaimableAwaitingConfirmations {
1475
+ claimable_amount_satoshis : us. current_holder_commitment_tx . to_self_value_sat ,
1476
+ confirmation_height : conf_thresh,
1477
+ } ) ;
1478
+ }
1479
+ found_commitment_tx = true ;
1480
+ } else if let Some ( prev_commitment) = & us. prev_holder_signed_commitment_tx {
1481
+ if txid == prev_commitment. txid {
1482
+ walk_htlcs ! ( true , prev_commitment. htlc_outputs. iter( ) . map( |( a, _, _) | a) ) ;
1483
+ if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
1484
+ res. push ( Balance :: ClaimableAwaitingConfirmations {
1485
+ claimable_amount_satoshis : prev_commitment. to_self_value_sat ,
1486
+ confirmation_height : conf_thresh,
1487
+ } ) ;
1488
+ }
1489
+ found_commitment_tx = true ;
1490
+ }
1491
+ }
1492
+ if !found_commitment_tx {
1493
+ if let Some ( conf_thresh) = pending_commitment_tx_conf_thresh {
1494
+ // We blindly assume this is a cooperative close transaction here, and that
1495
+ // neither us nor our counterparty misbehaved. At worst we've under-estimated
1496
+ // the amount we can claim as we'll punish a misbehaving counterparty.
1497
+ res. push ( Balance :: ClaimableAwaitingConfirmations {
1498
+ claimable_amount_satoshis : us. current_holder_commitment_tx . to_self_value_sat ,
1499
+ confirmation_height : conf_thresh,
1500
+ } ) ;
1501
+ }
1502
+ }
1503
+ // TODO: Add logic to provide claimable balances for counterparty broadcasting revoked
1504
+ // outputs.
1505
+ } else {
1506
+ let mut claimable_inbound_htlc_value_sat = 0 ;
1507
+ for ( htlc, _, _) in us. current_holder_commitment_tx . htlc_outputs . iter ( ) {
1508
+ if htlc. transaction_output_index . is_none ( ) { continue ; }
1509
+ if htlc. offered {
1510
+ res. push ( Balance :: MaybeClaimableHTLCAwaitingTimeout {
1511
+ claimable_amount_satoshis : htlc. amount_msat / 1000 ,
1512
+ claimable_height : htlc. cltv_expiry ,
1513
+ } ) ;
1514
+ } else if us. payment_preimages . get ( & htlc. payment_hash ) . is_some ( ) {
1515
+ claimable_inbound_htlc_value_sat += htlc. amount_msat / 1000 ;
1516
+ }
1517
+ }
1518
+ res. push ( Balance :: ClaimableOnChannelClose {
1519
+ claimable_amount_satoshis : us. current_holder_commitment_tx . to_self_value_sat + claimable_inbound_htlc_value_sat,
1520
+ } ) ;
1521
+ }
1522
+
1523
+ res
1524
+ }
1305
1525
}
1306
1526
1307
1527
/// Compares a broadcasted commitment transaction's HTLCs with those in the latest state,
@@ -2488,7 +2708,7 @@ impl<Signer: Sign> ChannelMonitorImpl<Signer> {
2488
2708
// we've already failed the HTLC as the commitment transaction
2489
2709
// which was broadcasted was revoked. In that case, we should
2490
2710
// spend the HTLC output here immediately, and expose that fact
2491
- // as a ClaimableBalance , something which we do not yet do.
2711
+ // as a Balance , something which we do not yet do.
2492
2712
// TODO: Track the above as claimable!
2493
2713
}
2494
2714
continue ' outer_loop;
0 commit comments