Skip to content

Commit

Permalink
Move Esplora-specific sync options to dedicated config
Browse files Browse the repository at this point in the history
.. as other upcoming chain sources might not have the same config
options such as syncing intervals, or at least not with the same
semantics.
  • Loading branch information
tnull committed Oct 8, 2024
1 parent 2d2b151 commit b90363f
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 70 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::str::FromStr;
fn main() {
let mut builder = Builder::new();
builder.set_network(Network::Testnet);
builder.set_esplora_server("https://blockstream.info/testnet/api".to_string());
builder.set_chain_source_esplora("https://blockstream.info/testnet/api".to_string(), None);
builder.set_gossip_source_rgs("https://rapidsync.lightningdevkit.org/testnet/snapshot".to_string());

let node = builder.build().unwrap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ class LibraryTest {
println("Config 2: $config2")

val builder1 = Builder.fromConfig(config1)
builder1.setEsploraServer(esploraEndpoint)
builder1.setChainSourceEsplora(esploraEndpoint, null)
val builder2 = Builder.fromConfig(config2)
builder2.setEsploraServer(esploraEndpoint)
builder2.setChainSourceEsplora(esploraEndpoint, null)

val node1 = builder1.build()
val node2 = builder2.build()
Expand Down
11 changes: 7 additions & 4 deletions bindings/ldk_node.udl
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ dictionary Config {
Network network;
sequence<SocketAddress>? listening_addresses;
NodeAlias? node_alias;
u64 onchain_wallet_sync_interval_secs;
u64 wallet_sync_interval_secs;
u64 fee_rate_cache_update_interval_secs;
sequence<PublicKey> trusted_peers_0conf;
u64 probing_liquidity_limit_multiplier;
LogLevel log_level;
Expand All @@ -24,6 +21,12 @@ dictionary AnchorChannelsConfig {
u64 per_channel_reserve_sats;
};

dictionary EsploraSyncConfig {
u64 onchain_wallet_sync_interval_secs;
u64 lightning_wallet_sync_interval_secs;
u64 fee_rate_cache_update_interval_secs;
};

interface Builder {
constructor();
[Name=from_config]
Expand All @@ -32,7 +35,7 @@ interface Builder {
[Throws=BuildError]
void set_entropy_seed_bytes(sequence<u8> seed_bytes);
void set_entropy_bip39_mnemonic(Mnemonic mnemonic, string? passphrase);
void set_esplora_server(string esplora_server_url);
void set_chain_source_esplora(string server_url, EsploraSyncConfig? config);
void set_gossip_source_p2p();
void set_gossip_source_rgs(string rgs_server_url);
void set_liquidity_source_lsps2(SocketAddress address, PublicKey node_id, string? token);
Expand Down
2 changes: 1 addition & 1 deletion bindings/python/src/ldk_node/test_ldk_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def setup_node(tmp_dir, esplora_endpoint, listening_addresses):
config = default_config()
builder = Builder.from_config(config)
builder.set_storage_dir_path(tmp_dir)
builder.set_esplora_server(esplora_endpoint)
builder.set_chain_source_esplora(esplora_endpoint, None)
builder.set_network(DEFAULT_TEST_NETWORK)
builder.set_listening_addresses(listening_addresses)
return builder.build()
Expand Down
49 changes: 33 additions & 16 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// accordance with one or both of these licenses.

use crate::chain::{ChainSource, DEFAULT_ESPLORA_SERVER_URL};
use crate::config::{default_user_config, Config, WALLET_KEYS_SEED_LEN};
use crate::config::{default_user_config, Config, EsploraSyncConfig, WALLET_KEYS_SEED_LEN};

use crate::connection::ConnectionManager;
use crate::event::EventQueue;
Expand Down Expand Up @@ -77,7 +77,7 @@ use std::time::SystemTime;

#[derive(Debug, Clone)]
enum ChainDataSourceConfig {
Esplora(String),
Esplora { server_url: String, sync_config: Option<EsploraSyncConfig> },
}

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -237,8 +237,14 @@ impl NodeBuilder {
}

/// Configures the [`Node`] instance to source its chain data from the given Esplora server.
pub fn set_esplora_server(&mut self, esplora_server_url: String) -> &mut Self {
self.chain_data_source_config = Some(ChainDataSourceConfig::Esplora(esplora_server_url));
///
/// If no `sync_config` is given, default values are used. See [`EsploraSyncConfig`] for more
/// information.
pub fn set_chain_source_esplora(
&mut self, server_url: String, sync_config: Option<EsploraSyncConfig>,
) -> &mut Self {
self.chain_data_source_config =
Some(ChainDataSourceConfig::Esplora { server_url, sync_config });
self
}

Expand Down Expand Up @@ -464,8 +470,13 @@ impl ArcedNodeBuilder {
}

/// Configures the [`Node`] instance to source its chain data from the given Esplora server.
pub fn set_esplora_server(&self, esplora_server_url: String) {
self.inner.write().unwrap().set_esplora_server(esplora_server_url);
///
/// If no `sync_config` is given, default values are used. See [`EsploraSyncConfig`] for more
/// information.
pub fn set_chain_source_esplora(
&self, server_url: String, sync_config: Option<EsploraSyncConfig>,
) {
self.inner.write().unwrap().set_chain_source_esplora(server_url, sync_config);
}

/// Configures the [`Node`] instance to source its gossip data from the Lightning peer-to-peer
Expand Down Expand Up @@ -608,21 +619,27 @@ fn build_with_store_internal(
));

let chain_source = match chain_data_source_config {
Some(ChainDataSourceConfig::Esplora(server_url)) => Arc::new(ChainSource::new_esplora(
server_url.clone(),
Arc::clone(&wallet),
Arc::clone(&fee_estimator),
Arc::clone(&tx_broadcaster),
Arc::clone(&kv_store),
Arc::clone(&config),
Arc::clone(&logger),
Arc::clone(&node_metrics),
)),
Some(ChainDataSourceConfig::Esplora { server_url, sync_config }) => {
let sync_config = sync_config.unwrap_or(EsploraSyncConfig::default());
Arc::new(ChainSource::new_esplora(
server_url.clone(),
sync_config,
Arc::clone(&wallet),
Arc::clone(&fee_estimator),
Arc::clone(&tx_broadcaster),
Arc::clone(&kv_store),
Arc::clone(&config),
Arc::clone(&logger),
Arc::clone(&node_metrics),
))
},
None => {
// Default to Esplora client.
let server_url = DEFAULT_ESPLORA_SERVER_URL.to_string();
let sync_config = EsploraSyncConfig::default();
Arc::new(ChainSource::new_esplora(
server_url.clone(),
sync_config,
Arc::clone(&wallet),
Arc::clone(&fee_estimator),
Arc::clone(&tx_broadcaster),
Expand Down
35 changes: 20 additions & 15 deletions src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
// accordance with one or both of these licenses.

use crate::config::{
Config, BDK_CLIENT_CONCURRENCY, BDK_CLIENT_STOP_GAP, BDK_WALLET_SYNC_TIMEOUT_SECS,
FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, LDK_WALLET_SYNC_TIMEOUT_SECS,
Config, EsploraSyncConfig, BDK_CLIENT_CONCURRENCY, BDK_CLIENT_STOP_GAP,
BDK_WALLET_SYNC_TIMEOUT_SECS, FEE_RATE_CACHE_UPDATE_TIMEOUT_SECS, LDK_WALLET_SYNC_TIMEOUT_SECS,
RESOLVED_CHANNEL_MONITOR_ARCHIVAL_INTERVAL, TX_BROADCAST_TIMEOUT_SECS,
WALLET_SYNC_INTERVAL_MINIMUM_SECS,
};
Expand Down Expand Up @@ -96,6 +96,7 @@ impl WalletSyncStatus {

pub(crate) enum ChainSource {
Esplora {
sync_config: EsploraSyncConfig,
esplora_client: EsploraAsyncClient,
onchain_wallet: Arc<Wallet>,
onchain_wallet_sync_status: Mutex<WalletSyncStatus>,
Expand All @@ -112,9 +113,10 @@ pub(crate) enum ChainSource {

impl ChainSource {
pub(crate) fn new_esplora(
server_url: String, onchain_wallet: Arc<Wallet>, fee_estimator: Arc<OnchainFeeEstimator>,
tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>, config: Arc<Config>,
logger: Arc<FilesystemLogger>, node_metrics: Arc<RwLock<NodeMetrics>>,
server_url: String, sync_config: EsploraSyncConfig, onchain_wallet: Arc<Wallet>,
fee_estimator: Arc<OnchainFeeEstimator>, tx_broadcaster: Arc<Broadcaster>,
kv_store: Arc<DynStore>, config: Arc<Config>, logger: Arc<FilesystemLogger>,
node_metrics: Arc<RwLock<NodeMetrics>>,
) -> Self {
let mut client_builder = esplora_client::Builder::new(&server_url);
client_builder = client_builder.timeout(DEFAULT_ESPLORA_CLIENT_TIMEOUT_SECS);
Expand All @@ -124,6 +126,7 @@ impl ChainSource {
let onchain_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed);
let lightning_wallet_sync_status = Mutex::new(WalletSyncStatus::Completed);
Self::Esplora {
sync_config,
esplora_client,
onchain_wallet,
onchain_wallet_sync_status,
Expand All @@ -144,16 +147,17 @@ impl ChainSource {
output_sweeper: Arc<Sweeper>,
) {
match self {
Self::Esplora { config, logger, .. } => {
Self::Esplora { sync_config, logger, .. } => {
// Setup syncing intervals
let onchain_wallet_sync_interval_secs =
config.onchain_wallet_sync_interval_secs.max(WALLET_SYNC_INTERVAL_MINIMUM_SECS);
let onchain_wallet_sync_interval_secs = sync_config
.onchain_wallet_sync_interval_secs
.max(WALLET_SYNC_INTERVAL_MINIMUM_SECS);
let mut onchain_wallet_sync_interval =
tokio::time::interval(Duration::from_secs(onchain_wallet_sync_interval_secs));
onchain_wallet_sync_interval
.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);

let fee_rate_cache_update_interval_secs = config
let fee_rate_cache_update_interval_secs = sync_config
.fee_rate_cache_update_interval_secs
.max(WALLET_SYNC_INTERVAL_MINIMUM_SECS);
let mut fee_rate_update_interval =
Expand All @@ -163,11 +167,12 @@ impl ChainSource {
fee_rate_update_interval
.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);

let wallet_sync_interval_secs =
config.wallet_sync_interval_secs.max(WALLET_SYNC_INTERVAL_MINIMUM_SECS);
let mut wallet_sync_interval =
tokio::time::interval(Duration::from_secs(wallet_sync_interval_secs));
wallet_sync_interval
let lightning_wallet_sync_interval_secs = sync_config
.lightning_wallet_sync_interval_secs
.max(WALLET_SYNC_INTERVAL_MINIMUM_SECS);
let mut lightning_wallet_sync_interval =
tokio::time::interval(Duration::from_secs(lightning_wallet_sync_interval_secs));
lightning_wallet_sync_interval
.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip);

// Start the syncing loop.
Expand All @@ -186,7 +191,7 @@ impl ChainSource {
_ = fee_rate_update_interval.tick() => {
let _ = self.update_fee_rate_estimates().await;
}
_ = wallet_sync_interval.tick() => {
_ = lightning_wallet_sync_interval.tick() => {
let _ = self.sync_lightning_wallet(
Arc::clone(&channel_manager),
Arc::clone(&chain_monitor),
Expand Down
50 changes: 35 additions & 15 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,18 +119,6 @@ pub struct Config {
/// **Note**: We will only allow opening and accepting public channels if the `node_alias` and the
/// `listening_addresses` are set.
pub node_alias: Option<NodeAlias>,
/// The time in-between background sync attempts of the onchain wallet, in seconds.
///
/// **Note:** A minimum of 10 seconds is always enforced.
pub onchain_wallet_sync_interval_secs: u64,
/// The time in-between background sync attempts of the LDK wallet, in seconds.
///
/// **Note:** A minimum of 10 seconds is always enforced.
pub wallet_sync_interval_secs: u64,
/// The time in-between background update attempts to our fee rate cache, in seconds.
///
/// **Note:** A minimum of 10 seconds is always enforced.
pub fee_rate_cache_update_interval_secs: u64,
/// A list of peers that we allow to establish zero confirmation channels to us.
///
/// **Note:** Allowing payments via zero-confirmation channels is potentially insecure if the
Expand Down Expand Up @@ -180,9 +168,6 @@ impl Default for Config {
log_dir_path: None,
network: DEFAULT_NETWORK,
listening_addresses: None,
onchain_wallet_sync_interval_secs: DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS,
wallet_sync_interval_secs: DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS,
fee_rate_cache_update_interval_secs: DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS,
trusted_peers_0conf: Vec::new(),
probing_liquidity_limit_multiplier: DEFAULT_PROBING_LIQUIDITY_LIMIT_MULTIPLIER,
log_level: DEFAULT_LOG_LEVEL,
Expand Down Expand Up @@ -300,6 +285,41 @@ pub(crate) fn default_user_config(config: &Config) -> UserConfig {
user_config
}

/// Options related to syncing the Lightning and on-chain wallets via an Esplora backend.
///
/// ### Defaults
///
/// | Parameter | Value |
/// |----------------------------------------|--------------------|
/// | `onchain_wallet_sync_interval_secs` | 80 |
/// | `lightning_wallet_sync_interval_secs` | 30 |
/// | `fee_rate_cache_update_interval_secs` | 600 |
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct EsploraSyncConfig {
/// The time in-between background sync attempts of the onchain wallet, in seconds.
///
/// **Note:** A minimum of 10 seconds is always enforced.
pub onchain_wallet_sync_interval_secs: u64,
/// The time in-between background sync attempts of the LDK wallet, in seconds.
///
/// **Note:** A minimum of 10 seconds is always enforced.
pub lightning_wallet_sync_interval_secs: u64,
/// The time in-between background update attempts to our fee rate cache, in seconds.
///
/// **Note:** A minimum of 10 seconds is always enforced.
pub fee_rate_cache_update_interval_secs: u64,
}

impl Default for EsploraSyncConfig {
fn default() -> Self {
Self {
onchain_wallet_sync_interval_secs: DEFAULT_BDK_WALLET_SYNC_INTERVAL_SECS,
lightning_wallet_sync_interval_secs: DEFAULT_LDK_WALLET_SYNC_INTERVAL_SECS,
fee_rate_cache_update_interval_secs: DEFAULT_FEE_RATE_CACHE_UPDATE_INTERVAL_SECS,
}
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down
12 changes: 8 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1187,10 +1187,14 @@ impl Node {
/// Manually sync the LDK and BDK wallets with the current chain state and update the fee rate
/// cache.
///
/// **Note:** The wallets are regularly synced in the background, which is configurable via
/// [`Config::onchain_wallet_sync_interval_secs`] and [`Config::wallet_sync_interval_secs`].
/// Therefore, using this blocking sync method is almost always redundant and should be avoided
/// where possible.
/// **Note:** The wallets are regularly synced in the background, which is configurable via the
/// respective config object, e.g., via
/// [`EsploraSyncConfig::onchain_wallet_sync_interval_secs`] and
/// [`EsploraSyncConfig::lightning_wallet_sync_interval_secs`]. Therefore, using this blocking
/// sync method is almost always redundant and should be avoided where possible.
///
/// [`EsploraSyncConfig::onchain_wallet_sync_interval_secs`]: crate::config::EsploraSyncConfig::onchain_wallet_sync_interval_secs
/// [`EsploraSyncConfig::lightning_wallet_sync_interval_secs`]: crate::config::EsploraSyncConfig::lightning_wallet_sync_interval_secs
pub fn sync_wallets(&self) -> Result<(), Error> {
let rt_lock = self.runtime.read().unwrap();
if rt_lock.is_none() {
Expand Down
2 changes: 1 addition & 1 deletion src/uniffi_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//
// Make sure to add any re-exported items that need to be used in uniffi below.

pub use crate::config::{default_config, AnchorChannelsConfig};
pub use crate::config::{default_config, AnchorChannelsConfig, EsploraSyncConfig};
pub use crate::graph::{ChannelInfo, ChannelUpdateInfo, NodeAnnouncementInfo, NodeInfo};
pub use crate::payment::store::{LSPFeeLimits, PaymentDirection, PaymentKind, PaymentStatus};
pub use crate::payment::{MaxTotalRoutingFeeLimit, QrPaymentResult, SendingParameters};
Expand Down
9 changes: 5 additions & 4 deletions tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#![cfg(any(test, cln_test, vss_test))]
#![allow(dead_code)]

use ldk_node::config::Config;
use ldk_node::config::{Config, EsploraSyncConfig};
use ldk_node::io::sqlite_store::SqliteStore;
use ldk_node::payment::{PaymentDirection, PaymentKind, PaymentStatus};
use ldk_node::{Builder, Event, LightningBalance, LogLevel, Node, NodeError, PendingSweepBalance};
Expand Down Expand Up @@ -217,8 +217,6 @@ pub(crate) fn random_config(anchor_channels: bool) -> Config {
}

config.network = Network::Regtest;
config.onchain_wallet_sync_interval_secs = 100000;
config.wallet_sync_interval_secs = 100000;
println!("Setting network: {}", config.network);

let rand_dir = random_storage_path();
Expand Down Expand Up @@ -280,8 +278,11 @@ pub(crate) fn setup_two_nodes(

pub(crate) fn setup_node(electrsd: &ElectrsD, config: Config) -> TestNode {
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
let mut sync_config = EsploraSyncConfig::default();
sync_config.onchain_wallet_sync_interval_secs = 100000;
sync_config.lightning_wallet_sync_interval_secs = 100000;
setup_builder!(builder, config);
builder.set_esplora_server(esplora_url.clone());
builder.set_chain_source_esplora(esplora_url.clone(), Some(sync_config));
let test_sync_store = Arc::new(TestSyncStore::new(config.storage_dir_path.into()));
let node = builder.build_with_store(test_sync_store).unwrap();
node.start().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion tests/integration_tests_cln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn test_cln() {
// Setup LDK Node
let config = common::random_config(true);
let mut builder = Builder::from_config(config);
builder.set_esplora_server("http://127.0.0.1:3002".to_string());
builder.set_chain_source_esplora("http://127.0.0.1:3002".to_string(), None);

let node = builder.build().unwrap();
node.start().unwrap();
Expand Down
Loading

0 comments on commit b90363f

Please sign in to comment.