@@ -171,6 +171,7 @@ pub struct NodeState {
171171 data_dir : PathBuf ,
172172 storage : NodeStorage ,
173173 utxo : Arc < UtxoSet > ,
174+ coin_stats : Arc < bitcoin_rs_coinstats:: CoinStatsListener > ,
174175 mempool : Arc < RwLock < Mempool > > ,
175176 chain_tip : Arc < ArcSwapOption < TipSnapshot > > ,
176177 applied_tip : Arc < ArcSwapOption < TipSnapshot > > ,
@@ -202,7 +203,13 @@ impl NodeState {
202203 std:: fs:: create_dir_all ( & config. data_dir )
203204 . with_context ( || format ! ( "create data_dir {}" , config. data_dir. display( ) ) ) ?;
204205 let storage = NodeStorage :: open ( & config) ?;
205- let utxo = Arc :: new ( UtxoSet :: new ( ) ) ;
206+ let mut utxo_set = bitcoin_rs_utxo:: UtxoSet :: new ( ) ;
207+ let coin_stats_listener = bitcoin_rs_coinstats:: CoinStatsListener :: new (
208+ bitcoin_rs_coinstats:: CoinStats :: default ( ) ,
209+ ) ;
210+ utxo_set. set_listener ( Box :: new ( coin_stats_listener. clone ( ) ) ) ;
211+ let utxo = Arc :: new ( utxo_set) ;
212+ let coin_stats = Arc :: new ( coin_stats_listener) ;
206213 let mempool = Arc :: new ( RwLock :: new ( Mempool :: new ( MempoolLimits :: default ( ) ) ) ) ;
207214 let block_tree = Arc :: new ( RwLock :: new ( bitcoin_rs_chain:: BlockTree :: new ( ) ) ) ;
208215 let chain_tip = block_tree. read ( ) . tip_handle ( ) ;
@@ -226,6 +233,7 @@ impl NodeState {
226233 applied_tip : Arc :: clone ( & applied_tip) ,
227234 block_tree : Arc :: clone ( & block_tree) ,
228235 utxo : Arc :: clone ( & utxo) ,
236+ coin_stats : Arc :: clone ( & coin_stats) ,
229237 mempool : Arc :: clone ( & mempool) ,
230238 blocks : Arc :: clone ( & blocks) ,
231239 transactions : Arc :: clone ( & transactions) ,
@@ -246,6 +254,7 @@ impl NodeState {
246254 data_dir,
247255 storage,
248256 utxo,
257+ coin_stats,
249258 mempool,
250259 chain_tip,
251260 applied_tip,
@@ -289,6 +298,12 @@ impl NodeState {
289298 Arc :: clone ( & self . utxo )
290299 }
291300
301+ /// Returns the shared coinstats listener handle.
302+ #[ must_use]
303+ pub fn coin_stats ( & self ) -> Arc < bitcoin_rs_coinstats:: CoinStatsListener > {
304+ Arc :: clone ( & self . coin_stats )
305+ }
306+
292307 /// Returns the shared mempool handle.
293308 #[ must_use]
294309 pub fn mempool ( & self ) -> Arc < RwLock < Mempool > > {
@@ -435,6 +450,7 @@ impl NodeState {
435450 applied_tip : Arc :: clone ( & self . applied_tip ) ,
436451 block_tree : Arc :: clone ( & self . block_tree ) ,
437452 utxo : Arc :: clone ( & self . utxo ) ,
453+ coin_stats : Arc :: clone ( & self . coin_stats ) ,
438454 mempool : Arc :: clone ( & self . mempool ) ,
439455 blocks : Arc :: clone ( & self . blocks ) ,
440456 transactions : Arc :: clone ( & self . transactions ) ,
@@ -507,6 +523,21 @@ mod tests {
507523 Ok ( ( ) )
508524 }
509525
526+ #[ test]
527+ fn open_constructs_coin_stats_listener ( ) -> anyhow:: Result < ( ) > {
528+ let dir = tempfile:: tempdir ( ) ?;
529+ let mut config = crate :: Config :: default_for_network ( crate :: Network :: Regtest ) ;
530+ config. data_dir = dir. path ( ) . join ( "node" ) ;
531+ config. p2p_listen . clear ( ) ;
532+ let state = NodeState :: open ( config) ?;
533+ let snapshot = state. coin_stats ( ) . snapshot ( ) ;
534+ assert_eq ! (
535+ snapshot. tx_count, 0 ,
536+ "freshly opened coin_stats has zero txs"
537+ ) ;
538+ Ok ( ( ) )
539+ }
540+
510541 #[ test]
511542 fn open_constructs_block_sync_orchestrator ( ) -> anyhow:: Result < ( ) > {
512543 let dir = tempfile:: tempdir ( ) ?;
0 commit comments