55// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66// accordance with one or both of these licenses.
77
8- use std:: collections:: { BTreeMap , HashMap } ;
8+ use std:: collections:: { BTreeMap , HashMap , HashSet } ;
99use std:: net:: SocketAddr ;
1010use std:: sync:: atomic:: { AtomicU32 , Ordering } ;
1111use std:: sync:: { Arc , Mutex , RwLock } ;
@@ -19,7 +19,7 @@ use bip157::{
1919 SyncUpdate , TrustedPeer , Warning ,
2020} ;
2121use bitcoin:: constants:: SUBSIDY_HALVING_INTERVAL ;
22- use bitcoin:: { Amount , FeeRate , Network , Script , ScriptBuf , Transaction , Txid } ;
22+ use bitcoin:: { Amount , FeeRate , Network , OutPoint , Script , ScriptBuf , Transaction , Txid } ;
2323use electrum_client:: ElectrumApi ;
2424use lightning:: chain:: { Confirm , WatchedOutput } ;
2525use lightning:: util:: ser:: Writeable ;
@@ -705,6 +705,7 @@ impl CbfChainSource {
705705 all_scripts. extend ( self . registered_scripts . lock ( ) . unwrap ( ) . iter ( ) . cloned ( ) ) ;
706706 let skip_height =
707707 onchain_wallet. latest_checkpoint ( ) . height ( ) . checked_sub ( REORG_SAFETY_BLOCKS ) ;
708+ let script_set: HashSet < ScriptBuf > = all_scripts. iter ( ) . cloned ( ) . collect ( ) ;
708709 let ( sync_update, matched) = self . run_filter_scan ( all_scripts, skip_height) . await ?;
709710
710711 log_debug ! (
@@ -713,10 +714,25 @@ impl CbfChainSource {
713714 matched. len( )
714715 ) ;
715716
716- // Fetch matching blocks and include all their transactions.
717- // The compact block filter already matched our scripts (covering both
718- // created outputs and spent inputs), so we include every transaction
719- // from matched blocks and let BDK determine relevance.
717+ // Fetch matching blocks and include only script-relevant transactions.
718+ // The compact filter gives us block-level matches; here we narrow to
719+ // individual transactions that create or spend outputs to watched
720+ // scripts. This avoids pushing thousands of irrelevant txs into BDK's
721+ // TxGraph on wide filter scans.
722+
723+ // Seed the known-outpoint set with outputs from BDK's existing tx
724+ // graph that pay to our scripts, so we can also detect txs that
725+ // *spend* our UTXOs (not just receive to them).
726+ let mut known_outpoints: HashSet < OutPoint > = HashSet :: new ( ) ;
727+ for cached_tx in onchain_wallet. get_cached_txs ( ) {
728+ let cached_txid = cached_tx. compute_txid ( ) ;
729+ for ( vout, output) in cached_tx. output . iter ( ) . enumerate ( ) {
730+ if script_set. contains ( & output. script_pubkey ) {
731+ known_outpoints. insert ( OutPoint :: new ( cached_txid, vout as u32 ) ) ;
732+ }
733+ }
734+ }
735+
720736 let mut tx_update = TxUpdate :: default ( ) ;
721737 let per_request_timeout =
722738 Duration :: from_secs ( self . sync_config . timeouts_config . per_request_timeout_secs . into ( ) ) ;
@@ -737,9 +753,21 @@ impl CbfChainSource {
737753 let conf_time =
738754 ConfirmationBlockTime { block_id, confirmation_time : block. header . time as u64 } ;
739755 for tx in & block. txdata {
740- let txid = tx. compute_txid ( ) ;
741- tx_update. txs . push ( Arc :: new ( tx. clone ( ) ) ) ;
742- tx_update. anchors . insert ( ( conf_time, txid) ) ;
756+ let dominated = tx. output . iter ( ) . any ( |o| script_set. contains ( & o. script_pubkey ) ) ;
757+ let spends_known =
758+ tx. input . iter ( ) . any ( |i| known_outpoints. contains ( & i. previous_output ) ) ;
759+
760+ if dominated || spends_known {
761+ let txid = tx. compute_txid ( ) ;
762+ tx_update. txs . push ( Arc :: new ( tx. clone ( ) ) ) ;
763+ tx_update. anchors . insert ( ( conf_time, txid) ) ;
764+
765+ for ( vout, output) in tx. output . iter ( ) . enumerate ( ) {
766+ if script_set. contains ( & output. script_pubkey ) {
767+ known_outpoints. insert ( OutPoint :: new ( txid, vout as u32 ) ) ;
768+ }
769+ }
770+ }
743771 }
744772 }
745773
0 commit comments