Skip to content

Commit 4cb6618

Browse files
committed
Add bip157 dependency and CBF builder configuration
1 parent b0e159a commit 4cb6618

5 files changed

Lines changed: 230 additions & 3 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ lightning-macros = { git = "https://github.com/lightningdevkit/rust-lightning",
5454
bdk_chain = { version = "0.23.0", default-features = false, features = ["std"] }
5555
bdk_esplora = { version = "0.22.0", default-features = false, features = ["async-https-rustls", "tokio"]}
5656
bdk_electrum = { version = "0.23.0", default-features = false, features = ["use-rustls-ring"]}
57+
bip157 = { version = "0.4.2", default-features = false }
5758
bdk_wallet = { version = "2.3.0", default-features = false, features = ["std", "keys-bip39"]}
5859

5960
bitreq = { version = "0.3", default-features = false, features = ["async-https", "json-using-serde"] }

src/builder.rs

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use vss_client::headers::VssHeaderProvider;
4545
use crate::chain::ChainSource;
4646
use crate::config::{
4747
default_user_config, may_announce_channel, AnnounceError, AsyncPaymentsRole,
48-
BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig,
48+
BitcoindRestClientConfig, CbfSyncConfig, Config, ElectrumSyncConfig, EsploraSyncConfig,
4949
DEFAULT_ESPLORA_SERVER_URL, DEFAULT_LOG_FILENAME, DEFAULT_LOG_LEVEL,
5050
};
5151
use crate::connection::ConnectionManager;
@@ -105,6 +105,10 @@ enum ChainDataSourceConfig {
105105
rpc_password: String,
106106
rest_client_config: Option<BitcoindRestClientConfig>,
107107
},
108+
Cbf {
109+
peers: Vec<String>,
110+
sync_config: Option<CbfSyncConfig>,
111+
},
108112
}
109113

110114
#[derive(Debug, Clone)]
@@ -376,6 +380,21 @@ impl NodeBuilder {
376380
self
377381
}
378382

383+
/// Configures the [`Node`] instance to source its chain data via BIP 157 compact block
384+
/// filters.
385+
///
386+
/// `peers` is an optional list of peer addresses to connect to for sourcing compact block
387+
/// filters. If empty, the node will discover peers via DNS seeds.
388+
///
389+
/// If no `sync_config` is given, default values are used. See [`CbfSyncConfig`] for more
390+
/// information.
391+
pub fn set_chain_source_cbf(
392+
&mut self, peers: Vec<String>, sync_config: Option<CbfSyncConfig>,
393+
) -> &mut Self {
394+
self.chain_data_source_config = Some(ChainDataSourceConfig::Cbf { peers, sync_config });
395+
self
396+
}
397+
379398
/// Configures the [`Node`] instance to source its gossip data from the Lightning peer-to-peer
380399
/// network.
381400
pub fn set_gossip_source_p2p(&mut self) -> &mut Self {
@@ -1255,6 +1274,20 @@ fn build_with_store_internal(
12551274
}),
12561275
},
12571276

1277+
Some(ChainDataSourceConfig::Cbf { peers, sync_config }) => {
1278+
let sync_config = sync_config.clone().unwrap_or(CbfSyncConfig::default());
1279+
ChainSource::new_cbf(
1280+
peers.clone(),
1281+
sync_config,
1282+
Arc::clone(&fee_estimator),
1283+
Arc::clone(&tx_broadcaster),
1284+
Arc::clone(&kv_store),
1285+
Arc::clone(&config),
1286+
Arc::clone(&logger),
1287+
Arc::clone(&node_metrics),
1288+
)
1289+
},
1290+
12581291
None => {
12591292
// Default to Esplora client.
12601293
let server_url = DEFAULT_ESPLORA_SERVER_URL.to_string();

src/chain/cbf.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// This file is Copyright its original authors, visible in version control history.
2+
//
3+
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5+
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
6+
// accordance with one or both of these licenses.
7+
8+
use std::sync::{Arc, RwLock};
9+
10+
use bitcoin::{Script, Transaction, Txid};
11+
use lightning::chain::WatchedOutput;
12+
13+
use crate::config::{CbfSyncConfig, Config};
14+
use crate::fee_estimator::OnchainFeeEstimator;
15+
use crate::logger::{log_error, LdkLogger, Logger};
16+
use crate::runtime::Runtime;
17+
use crate::types::{ChainMonitor, ChannelManager, DynStore, Sweeper, Wallet};
18+
use crate::{Error, NodeMetrics};
19+
20+
pub(super) struct CbfChainSource {
21+
/// Peer addresses for sourcing compact block filters via P2P.
22+
peers: Vec<String>,
23+
/// User-provided sync configuration (timeouts, background sync intervals).
24+
pub(super) sync_config: CbfSyncConfig,
25+
/// Shared fee rate estimator, updated by this chain source.
26+
fee_estimator: Arc<OnchainFeeEstimator>,
27+
/// Persistent key-value store for node metrics.
28+
kv_store: Arc<DynStore>,
29+
/// Node configuration (network, storage path, etc.).
30+
config: Arc<Config>,
31+
/// Logger instance.
32+
logger: Arc<Logger>,
33+
/// Shared node metrics (sync timestamps, etc.).
34+
node_metrics: Arc<RwLock<NodeMetrics>>,
35+
}
36+
37+
impl CbfChainSource {
38+
pub(crate) fn new(
39+
peers: Vec<String>, sync_config: CbfSyncConfig, fee_estimator: Arc<OnchainFeeEstimator>,
40+
kv_store: Arc<DynStore>, config: Arc<Config>, logger: Arc<Logger>,
41+
node_metrics: Arc<RwLock<NodeMetrics>>,
42+
) -> Self {
43+
Self { peers, sync_config, fee_estimator, kv_store, config, logger, node_metrics }
44+
}
45+
46+
/// Start the bip157 node and spawn background tasks for event processing.
47+
pub(crate) fn start(&self, _runtime: Arc<Runtime>) {
48+
log_error!(self.logger, "CBF chain source start is not yet implemented.");
49+
}
50+
51+
/// Shut down the bip157 node and stop all background tasks.
52+
pub(crate) fn stop(&self) {
53+
log_error!(self.logger, "CBF chain source stop is not yet implemented.");
54+
}
55+
56+
/// Sync the on-chain wallet by scanning compact block filters for relevant transactions.
57+
pub(crate) async fn sync_onchain_wallet(
58+
&self, _onchain_wallet: Arc<Wallet>,
59+
) -> Result<(), Error> {
60+
log_error!(self.logger, "On-chain wallet sync via CBF is not yet implemented.");
61+
Err(Error::WalletOperationFailed)
62+
}
63+
64+
/// Sync the Lightning wallet by confirming channel transactions via compact block filters.
65+
pub(crate) async fn sync_lightning_wallet(
66+
&self, _channel_manager: Arc<ChannelManager>, _chain_monitor: Arc<ChainMonitor>,
67+
_output_sweeper: Arc<Sweeper>,
68+
) -> Result<(), Error> {
69+
log_error!(self.logger, "Lightning wallet sync via CBF is not yet implemented.");
70+
Err(Error::TxSyncFailed)
71+
}
72+
73+
/// Estimate fee rates from recent block data.
74+
pub(crate) async fn update_fee_rate_estimates(&self) -> Result<(), Error> {
75+
log_error!(self.logger, "Fee rate estimation via CBF is not yet implemented.");
76+
Err(Error::FeerateEstimationUpdateFailed)
77+
}
78+
79+
/// Broadcast a package of transactions via the P2P network.
80+
pub(crate) async fn process_broadcast_package(&self, _package: Vec<Transaction>) {
81+
log_error!(self.logger, "Transaction broadcasting via CBF is not yet implemented.");
82+
}
83+
84+
/// Register a transaction script for Lightning channel monitoring.
85+
pub(crate) fn register_tx(&self, _txid: &Txid, _script_pubkey: &Script) {
86+
log_error!(self.logger, "CBF register_tx is not yet implemented.");
87+
}
88+
89+
/// Register a watched output script for Lightning channel monitoring.
90+
pub(crate) fn register_output(&self, _output: WatchedOutput) {
91+
log_error!(self.logger, "CBF register_output is not yet implemented.");
92+
}
93+
}

src/chain/mod.rs

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
// accordance with one or both of these licenses.
77

88
pub(crate) mod bitcoind;
9+
mod cbf;
910
mod electrum;
1011
mod esplora;
1112

@@ -17,11 +18,12 @@ use bitcoin::{Script, Txid};
1718
use lightning::chain::{BestBlock, Filter};
1819

1920
use crate::chain::bitcoind::{BitcoindChainSource, UtxoSourceClient};
21+
use crate::chain::cbf::CbfChainSource;
2022
use crate::chain::electrum::ElectrumChainSource;
2123
use crate::chain::esplora::EsploraChainSource;
2224
use crate::config::{
23-
BackgroundSyncConfig, BitcoindRestClientConfig, Config, ElectrumSyncConfig, EsploraSyncConfig,
24-
WALLET_SYNC_INTERVAL_MINIMUM_SECS,
25+
BackgroundSyncConfig, BitcoindRestClientConfig, CbfSyncConfig, Config, ElectrumSyncConfig,
26+
EsploraSyncConfig, WALLET_SYNC_INTERVAL_MINIMUM_SECS,
2527
};
2628
use crate::fee_estimator::OnchainFeeEstimator;
2729
use crate::logger::{log_debug, log_info, log_trace, LdkLogger, Logger};
@@ -93,6 +95,7 @@ enum ChainSourceKind {
9395
Esplora(EsploraChainSource),
9496
Electrum(ElectrumChainSource),
9597
Bitcoind(BitcoindChainSource),
98+
Cbf(CbfChainSource),
9699
}
97100

98101
impl ChainSource {
@@ -184,11 +187,33 @@ impl ChainSource {
184187
(Self { kind, registered_txids, tx_broadcaster, logger }, best_block)
185188
}
186189

190+
pub(crate) fn new_cbf(
191+
peers: Vec<String>, sync_config: CbfSyncConfig, fee_estimator: Arc<OnchainFeeEstimator>,
192+
tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>, config: Arc<Config>,
193+
logger: Arc<Logger>, node_metrics: Arc<RwLock<NodeMetrics>>,
194+
) -> (Self, Option<BestBlock>) {
195+
let cbf_chain_source = CbfChainSource::new(
196+
peers,
197+
sync_config,
198+
fee_estimator,
199+
kv_store,
200+
config,
201+
Arc::clone(&logger),
202+
node_metrics,
203+
);
204+
let kind = ChainSourceKind::Cbf(cbf_chain_source);
205+
let registered_txids = Mutex::new(Vec::new());
206+
(Self { kind, registered_txids, tx_broadcaster, logger }, None)
207+
}
208+
187209
pub(crate) fn start(&self, runtime: Arc<Runtime>) -> Result<(), Error> {
188210
match &self.kind {
189211
ChainSourceKind::Electrum(electrum_chain_source) => {
190212
electrum_chain_source.start(runtime)?
191213
},
214+
ChainSourceKind::Cbf(cbf_chain_source) => {
215+
cbf_chain_source.start(runtime);
216+
},
192217
_ => {
193218
// Nothing to do for other chain sources.
194219
},
@@ -199,6 +224,9 @@ impl ChainSource {
199224
pub(crate) fn stop(&self) {
200225
match &self.kind {
201226
ChainSourceKind::Electrum(electrum_chain_source) => electrum_chain_source.stop(),
227+
ChainSourceKind::Cbf(cbf_chain_source) => {
228+
cbf_chain_source.stop();
229+
},
202230
_ => {
203231
// Nothing to do for other chain sources.
204232
},
@@ -210,6 +238,7 @@ impl ChainSource {
210238
ChainSourceKind::Bitcoind(bitcoind_chain_source) => {
211239
Some(bitcoind_chain_source.as_utxo_source())
212240
},
241+
ChainSourceKind::Cbf { .. } => None,
213242
_ => None,
214243
}
215244
}
@@ -223,6 +252,7 @@ impl ChainSource {
223252
ChainSourceKind::Esplora(_) => true,
224253
ChainSourceKind::Electrum { .. } => true,
225254
ChainSourceKind::Bitcoind { .. } => false,
255+
ChainSourceKind::Cbf { .. } => false,
226256
}
227257
}
228258

@@ -289,6 +319,28 @@ impl ChainSource {
289319
)
290320
.await
291321
},
322+
ChainSourceKind::Cbf(cbf_chain_source) => {
323+
if let Some(background_sync_config) =
324+
cbf_chain_source.sync_config.background_sync_config.as_ref()
325+
{
326+
self.start_tx_based_sync_loop(
327+
stop_sync_receiver,
328+
onchain_wallet,
329+
channel_manager,
330+
chain_monitor,
331+
output_sweeper,
332+
background_sync_config,
333+
Arc::clone(&self.logger),
334+
)
335+
.await
336+
} else {
337+
log_info!(
338+
self.logger,
339+
"Background syncing is disabled. Manual syncing required for onchain wallet, lightning wallet, and fee rate updates.",
340+
);
341+
return;
342+
}
343+
},
292344
}
293345
}
294346

@@ -368,6 +420,9 @@ impl ChainSource {
368420
// `ChainPoller`. So nothing to do here.
369421
unreachable!("Onchain wallet will be synced via chain polling")
370422
},
423+
ChainSourceKind::Cbf(cbf_chain_source) => {
424+
cbf_chain_source.sync_onchain_wallet(onchain_wallet).await
425+
},
371426
}
372427
}
373428

@@ -393,6 +448,11 @@ impl ChainSource {
393448
// `ChainPoller`. So nothing to do here.
394449
unreachable!("Lightning wallet will be synced via chain polling")
395450
},
451+
ChainSourceKind::Cbf(cbf_chain_source) => {
452+
cbf_chain_source
453+
.sync_lightning_wallet(channel_manager, chain_monitor, output_sweeper)
454+
.await
455+
},
396456
}
397457
}
398458

@@ -421,6 +481,10 @@ impl ChainSource {
421481
)
422482
.await
423483
},
484+
ChainSourceKind::Cbf { .. } => {
485+
// In CBF mode we sync wallets via compact block filters.
486+
unreachable!("Listeners will be synced via compact block filter syncing")
487+
},
424488
}
425489
}
426490

@@ -435,6 +499,9 @@ impl ChainSource {
435499
ChainSourceKind::Bitcoind(bitcoind_chain_source) => {
436500
bitcoind_chain_source.update_fee_rate_estimates().await
437501
},
502+
ChainSourceKind::Cbf(cbf_chain_source) => {
503+
cbf_chain_source.update_fee_rate_estimates().await
504+
},
438505
}
439506
}
440507

@@ -463,6 +530,9 @@ impl ChainSource {
463530
ChainSourceKind::Bitcoind(bitcoind_chain_source) => {
464531
bitcoind_chain_source.process_broadcast_package(next_package).await
465532
},
533+
ChainSourceKind::Cbf(cbf_chain_source) => {
534+
cbf_chain_source.process_broadcast_package(next_package).await
535+
},
466536
}
467537
}
468538
}
@@ -481,6 +551,9 @@ impl Filter for ChainSource {
481551
electrum_chain_source.register_tx(txid, script_pubkey)
482552
},
483553
ChainSourceKind::Bitcoind { .. } => (),
554+
ChainSourceKind::Cbf(cbf_chain_source) => {
555+
cbf_chain_source.register_tx(txid, script_pubkey)
556+
},
484557
}
485558
}
486559
fn register_output(&self, output: lightning::chain::WatchedOutput) {
@@ -492,6 +565,7 @@ impl Filter for ChainSource {
492565
electrum_chain_source.register_output(output)
493566
},
494567
ChainSourceKind::Bitcoind { .. } => (),
568+
ChainSourceKind::Cbf(cbf_chain_source) => cbf_chain_source.register_output(output),
495569
}
496570
}
497571
}

src/config.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,32 @@ impl Default for ElectrumSyncConfig {
478478
}
479479
}
480480

481+
/// Configuration for syncing via BIP 157 compact block filters.
482+
///
483+
/// Background syncing is enabled by default, using the default values specified in
484+
/// [`BackgroundSyncConfig`].
485+
#[derive(Debug, Clone, PartialEq, Eq)]
486+
pub struct CbfSyncConfig {
487+
/// Background sync configuration.
488+
///
489+
/// If set to `None`, background syncing will be disabled. Users will need to manually
490+
/// sync via [`Node::sync_wallets`] for the wallets and fee rate updates.
491+
///
492+
/// [`Node::sync_wallets`]: crate::Node::sync_wallets
493+
pub background_sync_config: Option<BackgroundSyncConfig>,
494+
/// Sync timeouts configuration.
495+
pub timeouts_config: SyncTimeoutsConfig,
496+
}
497+
498+
impl Default for CbfSyncConfig {
499+
fn default() -> Self {
500+
Self {
501+
background_sync_config: Some(BackgroundSyncConfig::default()),
502+
timeouts_config: SyncTimeoutsConfig::default(),
503+
}
504+
}
505+
}
506+
481507
/// Configuration for syncing with Bitcoin Core backend via REST.
482508
#[derive(Debug, Clone)]
483509
pub struct BitcoindRestClientConfig {

0 commit comments

Comments
 (0)