@@ -57,9 +57,20 @@ pub const DEFAULT_STORAGE_DIR_PATH: &str = "/tmp/ldk_node";
5757// The default Esplora server we're using.
5858pub ( crate ) const DEFAULT_ESPLORA_SERVER_URL : & str = "https://blockstream.info/api" ;
5959
60- // The 'stop gap' parameter used by BDK's wallet sync. This seems to configure the threshold
61- // number of derivation indexes after which BDK stops looking for new scripts belonging to the wallet.
62- pub ( crate ) const BDK_CLIENT_STOP_GAP : usize = 20 ;
60+ /// The default stop gap used for BDK full scans of the on-chain wallet.
61+ ///
62+ /// The current default is 20.
63+ pub const DEFAULT_FULL_SCAN_STOP_GAP : u32 = 20 ;
64+
65+ /// The minimum allowed stop gap used for BDK full scans of the on-chain wallet.
66+ ///
67+ /// Values below 1 are clamped to 1 when a full scan runs.
68+ pub const MIN_FULL_SCAN_STOP_GAP : u32 = 1 ;
69+
70+ /// The maximum allowed stop gap used for BDK full scans of the on-chain wallet.
71+ ///
72+ /// Values above 1000 are clamped to 1000 when a full scan runs.
73+ pub const MAX_FULL_SCAN_STOP_GAP : u32 = 1000 ;
6374
6475// The number of concurrent requests made against the API provider.
6576pub ( crate ) const BDK_CLIENT_CONCURRENCY : usize = 4 ;
@@ -506,6 +517,23 @@ pub struct EsploraSyncConfig {
506517 pub background_sync_config : Option < BackgroundSyncConfig > ,
507518 /// Sync timeouts configuration.
508519 pub timeouts_config : SyncTimeoutsConfig ,
520+ /// The stop gap used for BDK full scans of the on-chain wallet.
521+ ///
522+ /// A full scan for each keychain stops after this many consecutive script pubkeys
523+ /// with no associated transactions. This value is only used for BDK `full_scan`
524+ /// calls, which ldk-node performs on the first on-chain wallet sync or when
525+ /// [`Self::force_wallet_full_scan`] is set. Incremental BDK `sync` calls do not use it.
526+ ///
527+ /// **Default:** 20 ([`DEFAULT_FULL_SCAN_STOP_GAP`])
528+ ///
529+ /// **Allowed values:** 1 ([`MIN_FULL_SCAN_STOP_GAP`]) to 1000
530+ /// ([`MAX_FULL_SCAN_STOP_GAP`]), inclusive. Values outside this range will be clamped to the
531+ /// nearest bound and a warning will be logged when the full scan runs.
532+ ///
533+ /// **Note:** Large values can cause many Esplora requests, hit server rate limits,
534+ /// take a long time to complete, or cause syncs to fail with
535+ /// [`SyncTimeoutsConfig::onchain_wallet_sync_timeout_secs`].
536+ pub full_scan_stop_gap : u32 ,
509537 /// Whether to force BDK full scans until one succeeds.
510538 ///
511539 /// This can be useful when restoring a wallet from seed on a node that has already synced
@@ -518,6 +546,7 @@ impl Default for EsploraSyncConfig {
518546 Self {
519547 background_sync_config : Some ( BackgroundSyncConfig :: default ( ) ) ,
520548 timeouts_config : SyncTimeoutsConfig :: default ( ) ,
549+ full_scan_stop_gap : DEFAULT_FULL_SCAN_STOP_GAP ,
521550 force_wallet_full_scan : false ,
522551 }
523552 }
@@ -539,6 +568,23 @@ pub struct ElectrumSyncConfig {
539568 pub background_sync_config : Option < BackgroundSyncConfig > ,
540569 /// Sync timeouts configuration.
541570 pub timeouts_config : SyncTimeoutsConfig ,
571+ /// The stop gap used for BDK full scans of the on-chain wallet.
572+ ///
573+ /// A full scan for each keychain stops after this many consecutive script pubkeys
574+ /// with no associated transactions. This value is only used for BDK `full_scan`
575+ /// calls, which ldk-node performs on the first on-chain wallet sync or when
576+ /// [`Self::force_wallet_full_scan`] is set. Incremental BDK `sync` calls do not use it.
577+ ///
578+ /// **Default:** 20 ([`DEFAULT_FULL_SCAN_STOP_GAP`])
579+ ///
580+ /// **Allowed values:** 1 ([`MIN_FULL_SCAN_STOP_GAP`]) to 1000
581+ /// ([`MAX_FULL_SCAN_STOP_GAP`]), inclusive. Values outside this range will be clamped to the
582+ /// nearest bound and a warning will be logged when the full scan runs.
583+ ///
584+ /// **Note:** Large values can cause many Electrum requests, hit server rate limits,
585+ /// take a long time to complete, or cause syncs to fail with
586+ /// [`SyncTimeoutsConfig::onchain_wallet_sync_timeout_secs`].
587+ pub full_scan_stop_gap : u32 ,
542588 /// Whether to force BDK full scans until one succeeds.
543589 ///
544590 /// This can be useful when restoring a wallet from seed on a node that has already synced
@@ -551,11 +597,16 @@ impl Default for ElectrumSyncConfig {
551597 Self {
552598 background_sync_config : Some ( BackgroundSyncConfig :: default ( ) ) ,
553599 timeouts_config : SyncTimeoutsConfig :: default ( ) ,
600+ full_scan_stop_gap : DEFAULT_FULL_SCAN_STOP_GAP ,
554601 force_wallet_full_scan : false ,
555602 }
556603 }
557604}
558605
606+ pub ( crate ) fn clamp_full_scan_stop_gap ( full_scan_stop_gap : u32 ) -> u32 {
607+ full_scan_stop_gap. clamp ( MIN_FULL_SCAN_STOP_GAP , MAX_FULL_SCAN_STOP_GAP )
608+ }
609+
559610/// Configuration for syncing with Bitcoin Core backend via REST.
560611#[ derive( Debug , Clone ) ]
561612pub struct BitcoindRestClientConfig {
@@ -711,7 +762,11 @@ pub enum AsyncPaymentsRole {
711762mod tests {
712763 use std:: str:: FromStr ;
713764
714- use super :: { may_announce_channel, AnnounceError , Config , NodeAlias , SocketAddress } ;
765+ use super :: {
766+ clamp_full_scan_stop_gap, may_announce_channel, AnnounceError , Config , ElectrumSyncConfig ,
767+ EsploraSyncConfig , NodeAlias , SocketAddress , DEFAULT_FULL_SCAN_STOP_GAP ,
768+ MAX_FULL_SCAN_STOP_GAP , MIN_FULL_SCAN_STOP_GAP ,
769+ } ;
715770
716771 #[ test]
717772 fn node_announce_channel ( ) {
@@ -758,4 +813,22 @@ mod tests {
758813 }
759814 assert ! ( may_announce_channel( & node_config) . is_ok( ) ) ;
760815 }
816+
817+ #[ test]
818+ fn full_scan_stop_gap_defaults ( ) {
819+ assert_eq ! ( EsploraSyncConfig :: default ( ) . full_scan_stop_gap, DEFAULT_FULL_SCAN_STOP_GAP ) ;
820+ assert_eq ! ( ElectrumSyncConfig :: default ( ) . full_scan_stop_gap, DEFAULT_FULL_SCAN_STOP_GAP ) ;
821+ }
822+
823+ #[ test]
824+ fn full_scan_stop_gap_is_clamped_to_valid_range ( ) {
825+ assert_eq ! ( clamp_full_scan_stop_gap( MIN_FULL_SCAN_STOP_GAP ) , MIN_FULL_SCAN_STOP_GAP ) ;
826+ assert_eq ! (
827+ clamp_full_scan_stop_gap( DEFAULT_FULL_SCAN_STOP_GAP ) ,
828+ DEFAULT_FULL_SCAN_STOP_GAP
829+ ) ;
830+ assert_eq ! ( clamp_full_scan_stop_gap( MAX_FULL_SCAN_STOP_GAP ) , MAX_FULL_SCAN_STOP_GAP ) ;
831+ assert_eq ! ( clamp_full_scan_stop_gap( 0 ) , MIN_FULL_SCAN_STOP_GAP ) ;
832+ assert_eq ! ( clamp_full_scan_stop_gap( MAX_FULL_SCAN_STOP_GAP + 1 ) , MAX_FULL_SCAN_STOP_GAP ) ;
833+ }
761834}
0 commit comments