77
88use core:: future:: Future ;
99use core:: task:: { Poll , Waker } ;
10- use std:: collections:: VecDeque ;
10+ use std:: collections:: { HashSet , VecDeque } ;
1111use std:: ops:: Deref ;
1212use std:: sync:: { Arc , Mutex } ;
13+ use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
1314
1415use bitcoin:: blockdata:: locktime:: absolute:: LockTime ;
1516use bitcoin:: secp256k1:: PublicKey ;
@@ -33,6 +34,7 @@ use lightning::{impl_writeable_tlv_based, impl_writeable_tlv_based_enum};
3334use lightning_liquidity:: lsps2:: utils:: compute_opening_fee;
3435use lightning_types:: payment:: { PaymentHash , PaymentPreimage } ;
3536
37+ use crate :: closed_channel:: ClosedChannelDetails ;
3638use crate :: config:: { may_announce_channel, Config } ;
3739use crate :: connection:: ConnectionManager ;
3840use crate :: data_store:: DataStoreUpdateResult ;
@@ -52,7 +54,8 @@ use crate::payment::store::{
5254} ;
5355use crate :: runtime:: Runtime ;
5456use crate :: types:: {
55- CustomTlvRecord , DynStore , KeysManager , OnionMessenger , PaymentStore , Sweeper , Wallet ,
57+ ClosedChannelStore , CustomTlvRecord , DynStore , KeysManager , OnionMessenger , PaymentStore ,
58+ Sweeper , Wallet ,
5659} ;
5760use crate :: {
5861 hex_utils, BumpTransactionEventHandler , ChannelManager , Error , Graph , PeerInfo , PeerStore ,
@@ -269,6 +272,18 @@ pub enum Event {
269272 counterparty_node_id : Option < PublicKey > ,
270273 /// This will be `None` for events serialized by LDK Node v0.2.1 and prior.
271274 reason : Option < ClosureReason > ,
275+ /// The channel's capacity in satoshis.
276+ ///
277+ /// This will be `None` for events serialized by LDK Node v0.8.0 and prior.
278+ channel_capacity_sats : Option < u64 > ,
279+ /// The channel's funding transaction outpoint.
280+ ///
281+ /// This will be `None` for events serialized by LDK Node v0.8.0 and prior.
282+ channel_funding_txo : Option < OutPoint > ,
283+ /// Our local balance in millisatoshis at the time of channel closure.
284+ ///
285+ /// This will be `None` for events serialized by LDK Node v0.8.0 and prior.
286+ last_local_balance_msat : Option < u64 > ,
272287 } ,
273288 /// A channel splice is pending confirmation on-chain.
274289 SplicePending {
@@ -331,6 +346,9 @@ impl_writeable_tlv_based_enum!(Event,
331346 ( 1 , counterparty_node_id, option) ,
332347 ( 2 , user_channel_id, required) ,
333348 ( 3 , reason, upgradable_option) ,
349+ ( 5 , channel_capacity_sats, option) ,
350+ ( 7 , channel_funding_txo, option) ,
351+ ( 9 , last_local_balance_msat, option) ,
334352 } ,
335353 ( 6 , PaymentClaimable ) => {
336354 ( 0 , payment_hash, required) ,
@@ -536,6 +554,13 @@ where
536554 liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > ,
537555 payment_store : Arc < PaymentStore > ,
538556 peer_store : Arc < PeerStore < L > > ,
557+ closed_channel_store : Arc < ClosedChannelStore > ,
558+ // Tracks which user_channel_ids correspond to outbound channels. Populated at startup from
559+ // list_channels() and updated on ChannelPending events. Consumed on ChannelClosed events.
560+ outbound_channel_ids : Mutex < HashSet < UserChannelId > > ,
561+ // Tracks which user_channel_ids correspond to announced channels. Populated at startup from
562+ // list_channels() and updated on ChannelPending events. Consumed on ChannelClosed events.
563+ announced_channel_ids : Mutex < HashSet < UserChannelId > > ,
539564 keys_manager : Arc < KeysManager > ,
540565 runtime : Arc < Runtime > ,
541566 logger : L ,
@@ -556,10 +581,27 @@ where
556581 output_sweeper : Arc < Sweeper > , network_graph : Arc < Graph > ,
557582 liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > ,
558583 payment_store : Arc < PaymentStore > , peer_store : Arc < PeerStore < L > > ,
559- keys_manager : Arc < KeysManager > , static_invoice_store : Option < StaticInvoiceStore > ,
560- onion_messenger : Arc < OnionMessenger > , om_mailbox : Option < Arc < OnionMessageMailbox > > ,
561- runtime : Arc < Runtime > , logger : L , config : Arc < Config > ,
584+ closed_channel_store : Arc < ClosedChannelStore > , keys_manager : Arc < KeysManager > ,
585+ static_invoice_store : Option < StaticInvoiceStore > , onion_messenger : Arc < OnionMessenger > ,
586+ om_mailbox : Option < Arc < OnionMessageMailbox > > , runtime : Arc < Runtime > , logger : L ,
587+ config : Arc < Config > ,
562588 ) -> Self {
589+ // Seed outbound_channel_ids and announced_channel_ids from currently open channels so we
590+ // correctly classify channels that were already open when this node started.
591+ let ( outbound_channel_ids, announced_channel_ids) = {
592+ let mut outbound = HashSet :: new ( ) ;
593+ let mut announced = HashSet :: new ( ) ;
594+ for chan in channel_manager. list_channels ( ) {
595+ if chan. is_outbound {
596+ outbound. insert ( UserChannelId ( chan. user_channel_id ) ) ;
597+ }
598+ if chan. is_announced {
599+ announced. insert ( UserChannelId ( chan. user_channel_id ) ) ;
600+ }
601+ }
602+ ( Mutex :: new ( outbound) , Mutex :: new ( announced) )
603+ } ;
604+
563605 Self {
564606 event_queue,
565607 wallet,
@@ -571,6 +613,9 @@ where
571613 liquidity_source,
572614 payment_store,
573615 peer_store,
616+ closed_channel_store,
617+ outbound_channel_ids,
618+ announced_channel_ids,
574619 keys_manager,
575620 logger,
576621 runtime,
@@ -1506,6 +1551,20 @@ where
15061551 if let Some ( pending_channel) =
15071552 channels. into_iter ( ) . find ( |c| c. channel_id == channel_id)
15081553 {
1554+ if pending_channel. is_outbound {
1555+ self . outbound_channel_ids
1556+ . lock ( )
1557+ . expect ( "Lock poisoned" )
1558+ . insert ( UserChannelId ( user_channel_id) ) ;
1559+ }
1560+
1561+ if pending_channel. is_announced {
1562+ self . announced_channel_ids
1563+ . lock ( )
1564+ . expect ( "Lock poisoned" )
1565+ . insert ( UserChannelId ( user_channel_id) ) ;
1566+ }
1567+
15091568 if !pending_channel. is_outbound
15101569 && self . peer_store . get_peer ( & counterparty_node_id) . is_none ( )
15111570 {
@@ -1581,15 +1640,62 @@ where
15811640 reason,
15821641 user_channel_id,
15831642 counterparty_node_id,
1584- ..
1643+ channel_capacity_sats,
1644+ channel_funding_txo,
1645+ last_local_balance_msat,
15851646 } => {
15861647 log_info ! ( self . logger, "Channel {} closed due to: {}" , channel_id, reason) ;
15871648
1649+ let user_channel_id = UserChannelId ( user_channel_id) ;
1650+ let is_outbound = self
1651+ . outbound_channel_ids
1652+ . lock ( )
1653+ . expect ( "Lock poisoned" )
1654+ . remove ( & user_channel_id) ;
1655+ let is_announced = self
1656+ . announced_channel_ids
1657+ . lock ( )
1658+ . expect ( "Lock poisoned" )
1659+ . remove ( & user_channel_id) ;
1660+
1661+ let closed_at = SystemTime :: now ( )
1662+ . duration_since ( UNIX_EPOCH )
1663+ . unwrap_or ( Duration :: ZERO )
1664+ . as_secs ( ) ;
1665+
1666+ let funding_txo =
1667+ channel_funding_txo. map ( |op| OutPoint { txid : op. txid , vout : op. index as u32 } ) ;
1668+
1669+ let record = ClosedChannelDetails {
1670+ channel_id,
1671+ user_channel_id,
1672+ counterparty_node_id,
1673+ funding_txo,
1674+ channel_capacity_sats,
1675+ last_local_balance_msat,
1676+ is_outbound,
1677+ is_announced,
1678+ closure_reason : Some ( reason. clone ( ) ) ,
1679+ closed_at,
1680+ } ;
1681+
1682+ if let Err ( e) = self . closed_channel_store . insert ( record) {
1683+ log_error ! (
1684+ self . logger,
1685+ "Failed to persist closed channel {}: {}" ,
1686+ channel_id,
1687+ e
1688+ ) ;
1689+ }
1690+
15881691 let event = Event :: ChannelClosed {
15891692 channel_id,
1590- user_channel_id : UserChannelId ( user_channel_id ) ,
1693+ user_channel_id,
15911694 counterparty_node_id,
15921695 reason : Some ( reason) ,
1696+ channel_capacity_sats,
1697+ channel_funding_txo : funding_txo,
1698+ last_local_balance_msat,
15931699 } ;
15941700
15951701 match self . event_queue . add_event ( event) . await {
0 commit comments