@@ -49,8 +49,12 @@ use crate::{Error, PersistedNodeMetrics};
4949const CHAIN_POLLING_INTERVAL_SECS : u64 = 2 ;
5050const CHAIN_POLLING_TIMEOUT_SECS : u64 = 10 ;
5151
52+ type BitcoindSpvClient =
53+ SpvClient < ChainPoller < Arc < BitcoindClient > , BitcoindClient > , Arc < ChainListener > > ;
54+
5255pub ( super ) struct BitcoindChainSource {
5356 api_client : Arc < BitcoindClient > ,
57+ spv_client : tokio:: sync:: Mutex < Option < BitcoindSpvClient > > ,
5458 latest_chain_tip : RwLock < Option < ValidatedBlockHeader > > ,
5559 wallet_polling_status : Mutex < WalletSyncStatus > ,
5660 fee_estimator : Arc < OnchainFeeEstimator > ,
@@ -74,9 +78,11 @@ impl BitcoindChainSource {
7478 ) ) ;
7579
7680 let latest_chain_tip = RwLock :: new ( None ) ;
81+ let spv_client = tokio:: sync:: Mutex :: new ( None ) ;
7782 let wallet_polling_status = Mutex :: new ( WalletSyncStatus :: Completed ) ;
7883 Self {
7984 api_client,
85+ spv_client,
8086 latest_chain_tip,
8187 wallet_polling_status,
8288 fee_estimator,
@@ -103,10 +109,12 @@ impl BitcoindChainSource {
103109 ) ) ;
104110
105111 let latest_chain_tip = RwLock :: new ( None ) ;
112+ let spv_client = tokio:: sync:: Mutex :: new ( None ) ;
106113 let wallet_polling_status = Mutex :: new ( WalletSyncStatus :: Completed ) ;
107114
108115 Self {
109116 api_client,
117+ spv_client,
110118 latest_chain_tip,
111119 wallet_polling_status,
112120 fee_estimator,
@@ -210,7 +218,16 @@ impl BitcoindChainSource {
210218 )
211219 . await
212220 {
213- Ok ( ( _header_cache, chain_tip) ) => {
221+ Ok ( ( header_cache, chain_tip) ) => {
222+ let spv_client = self . new_spv_client (
223+ chain_tip,
224+ header_cache,
225+ Arc :: clone ( & onchain_wallet) ,
226+ Arc :: clone ( & channel_manager) ,
227+ Arc :: clone ( & chain_monitor) ,
228+ Arc :: clone ( & output_sweeper) ,
229+ ) ;
230+ * self . spv_client . lock ( ) . await = Some ( spv_client) ;
214231 {
215232 let elapsed_ms = now. elapsed ( ) . map ( |d| d. as_millis ( ) ) . unwrap_or ( 0 ) ;
216233 log_info ! (
@@ -415,19 +432,24 @@ impl BitcoindChainSource {
415432 & self , onchain_wallet : Arc < Wallet > , channel_manager : Arc < ChannelManager > ,
416433 chain_monitor : Arc < ChainMonitor > , output_sweeper : Arc < Sweeper > ,
417434 ) -> Result < ( ) , Error > {
418- let latest_chain_tip_opt = self . latest_chain_tip . read ( ) . expect ( "lock" ) . clone ( ) ;
419- let chain_tip =
420- if let Some ( tip) = latest_chain_tip_opt { tip } else { self . poll_chain_tip ( ) . await ? } ;
421-
422- let chain_poller = ChainPoller :: new ( Arc :: clone ( & self . api_client ) , self . config . network ) ;
423- let chain_listener = ChainListener {
424- onchain_wallet : Arc :: clone ( & onchain_wallet) ,
425- channel_manager : Arc :: clone ( & channel_manager) ,
426- chain_monitor : Arc :: clone ( & chain_monitor) ,
427- output_sweeper,
428- } ;
429- let mut spv_client =
430- SpvClient :: new ( chain_tip, chain_poller, HeaderCache :: new ( ) , & chain_listener) ;
435+ let mut spv_client_lock = self . spv_client . lock ( ) . await ;
436+ if spv_client_lock. is_none ( ) {
437+ let latest_chain_tip_opt = self . latest_chain_tip . read ( ) . expect ( "lock" ) . clone ( ) ;
438+ let chain_tip = if let Some ( tip) = latest_chain_tip_opt {
439+ tip
440+ } else {
441+ self . poll_chain_tip ( ) . await ?
442+ } ;
443+ * spv_client_lock = Some ( self . new_spv_client (
444+ chain_tip,
445+ HeaderCache :: new ( ) ,
446+ Arc :: clone ( & onchain_wallet) ,
447+ Arc :: clone ( & channel_manager) ,
448+ chain_monitor,
449+ output_sweeper,
450+ ) ) ;
451+ }
452+ let spv_client = spv_client_lock. as_mut ( ) . expect ( "initialized above" ) ;
431453
432454 let now = SystemTime :: now ( ) ;
433455 match spv_client. poll_best_tip ( ) . await {
@@ -442,6 +464,7 @@ impl BitcoindChainSource {
442464 return Err ( Error :: TxSyncFailed ) ;
443465 } ,
444466 }
467+ drop ( spv_client_lock) ;
445468
446469 let cur_height = channel_manager. current_best_block ( ) . height ;
447470
@@ -485,6 +508,21 @@ impl BitcoindChainSource {
485508 Ok ( ( ) )
486509 }
487510
511+ fn new_spv_client (
512+ & self , chain_tip : ValidatedBlockHeader , header_cache : HeaderCache ,
513+ onchain_wallet : Arc < Wallet > , channel_manager : Arc < ChannelManager > ,
514+ chain_monitor : Arc < ChainMonitor > , output_sweeper : Arc < Sweeper > ,
515+ ) -> BitcoindSpvClient {
516+ let chain_poller = ChainPoller :: new ( Arc :: clone ( & self . api_client ) , self . config . network ) ;
517+ let chain_listener = Arc :: new ( ChainListener {
518+ onchain_wallet : Arc :: downgrade ( & onchain_wallet) ,
519+ channel_manager : Arc :: downgrade ( & channel_manager) ,
520+ chain_monitor : Arc :: downgrade ( & chain_monitor) ,
521+ output_sweeper : Arc :: downgrade ( & output_sweeper) ,
522+ } ) ;
523+ SpvClient :: new ( chain_tip, chain_poller, header_cache, chain_listener)
524+ }
525+
488526 pub ( super ) async fn update_fee_rate_estimates ( & self ) -> Result < ( ) , Error > {
489527 macro_rules! get_fee_rate_update {
490528 ( $estimation_fut: expr) => { {
@@ -1280,8 +1318,13 @@ impl BlockSource for BitcoindClient {
12801318 BitcoindClient :: Rpc { rpc_client, .. } => {
12811319 rpc_client. get_header ( header_hash, height_hint) . await
12821320 } ,
1283- BitcoindClient :: Rest { rest_client, .. } => {
1284- rest_client. get_header ( header_hash, height_hint) . await
1321+ BitcoindClient :: Rest { rest_client, rpc_client, .. } => {
1322+ match rest_client. get_header ( header_hash, height_hint) . await {
1323+ Err ( e) if e. kind ( ) == BlockSourceErrorKind :: Persistent => {
1324+ rpc_client. get_header ( header_hash, height_hint) . await
1325+ } ,
1326+ result => result,
1327+ }
12851328 } ,
12861329 }
12871330 }
@@ -1462,34 +1505,59 @@ pub(crate) enum FeeRateEstimationMode {
14621505}
14631506
14641507pub ( crate ) struct ChainListener {
1465- pub ( crate ) onchain_wallet : Arc < Wallet > ,
1466- pub ( crate ) channel_manager : Arc < ChannelManager > ,
1467- pub ( crate ) chain_monitor : Arc < ChainMonitor > ,
1468- pub ( crate ) output_sweeper : Arc < Sweeper > ,
1508+ pub ( crate ) onchain_wallet : std:: sync:: Weak < Wallet > ,
1509+ pub ( crate ) channel_manager : std:: sync:: Weak < ChannelManager > ,
1510+ pub ( crate ) chain_monitor : std:: sync:: Weak < ChainMonitor > ,
1511+ pub ( crate ) output_sweeper : std:: sync:: Weak < Sweeper > ,
1512+ }
1513+
1514+ impl ChainListener {
1515+ fn upgrade (
1516+ & self ,
1517+ ) -> Option < ( Arc < Wallet > , Arc < ChannelManager > , Arc < ChainMonitor > , Arc < Sweeper > ) > {
1518+ Some ( (
1519+ self . onchain_wallet . upgrade ( ) ?,
1520+ self . channel_manager . upgrade ( ) ?,
1521+ self . chain_monitor . upgrade ( ) ?,
1522+ self . output_sweeper . upgrade ( ) ?,
1523+ ) )
1524+ }
14691525}
14701526
14711527impl Listen for ChainListener {
14721528 fn filtered_block_connected (
14731529 & self , header : & bitcoin:: block:: Header ,
14741530 txdata : & lightning:: chain:: transaction:: TransactionData , height : u32 ,
14751531 ) {
1476- self . onchain_wallet . filtered_block_connected ( header, txdata, height) ;
1477- self . channel_manager . filtered_block_connected ( header, txdata, height) ;
1478- self . chain_monitor . filtered_block_connected ( header, txdata, height) ;
1479- self . output_sweeper . filtered_block_connected ( header, txdata, height) ;
1532+ if let Some ( ( onchain_wallet, channel_manager, chain_monitor, output_sweeper) ) =
1533+ self . upgrade ( )
1534+ {
1535+ onchain_wallet. filtered_block_connected ( header, txdata, height) ;
1536+ channel_manager. filtered_block_connected ( header, txdata, height) ;
1537+ chain_monitor. filtered_block_connected ( header, txdata, height) ;
1538+ output_sweeper. filtered_block_connected ( header, txdata, height) ;
1539+ }
14801540 }
14811541 fn block_connected ( & self , block : & bitcoin:: Block , height : u32 ) {
1482- self . onchain_wallet . block_connected ( block, height) ;
1483- self . channel_manager . block_connected ( block, height) ;
1484- self . chain_monitor . block_connected ( block, height) ;
1485- self . output_sweeper . block_connected ( block, height) ;
1542+ if let Some ( ( onchain_wallet, channel_manager, chain_monitor, output_sweeper) ) =
1543+ self . upgrade ( )
1544+ {
1545+ onchain_wallet. block_connected ( block, height) ;
1546+ channel_manager. block_connected ( block, height) ;
1547+ chain_monitor. block_connected ( block, height) ;
1548+ output_sweeper. block_connected ( block, height) ;
1549+ }
14861550 }
14871551
14881552 fn blocks_disconnected ( & self , fork_point_block : lightning:: chain:: BlockLocator ) {
1489- self . onchain_wallet . blocks_disconnected ( fork_point_block) ;
1490- self . channel_manager . blocks_disconnected ( fork_point_block) ;
1491- self . chain_monitor . blocks_disconnected ( fork_point_block) ;
1492- self . output_sweeper . blocks_disconnected ( fork_point_block) ;
1553+ if let Some ( ( onchain_wallet, channel_manager, chain_monitor, output_sweeper) ) =
1554+ self . upgrade ( )
1555+ {
1556+ onchain_wallet. blocks_disconnected ( fork_point_block) ;
1557+ channel_manager. blocks_disconnected ( fork_point_block) ;
1558+ chain_monitor. blocks_disconnected ( fork_point_block) ;
1559+ output_sweeper. blocks_disconnected ( fork_point_block) ;
1560+ }
14931561 }
14941562}
14951563
0 commit comments