Skip to content

Commit 6458c40

Browse files
committed
Expose tier storage configuration across the FFI boundary
Introduce FFI-safe abstractions and builder APIs to allow foreign language targets to configure custom backup and ephemeral stores when constructing nodes with a custom store. Major changes include: - Addition of FfiDynStoreTrait, an FFI-safe equivalent of DynStoreTrait, working around uniffi's lack of support for Pin<Box<T>> - Addition of FfiDynStore, a concrete wrapper for foreign language store implementations - Provision of FfiDynStoreTrait implementation for DynStoreWrapper to bridge native Rust stores to FFI layer (useful in testing) - Extension of ArcedNodeBuilder with methods for configuring backup and ephemeral stores - Exposure of build_with_store so foreign targets can build nodes with custom store implementations - Addition of build_node_with_store test helper to abstract uniffi-gated store wrapping at build_with_store call sites
1 parent f20fc18 commit 6458c40

File tree

7 files changed

+402
-28
lines changed

7 files changed

+402
-28
lines changed

bindings/ldk_node.udl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ interface LogWriter {
3232
void log(LogRecord record);
3333
};
3434

35+
typedef interface FfiDynStore;
36+
3537
interface Builder {
3638
constructor();
3739
[Name=from_config]
@@ -58,6 +60,8 @@ interface Builder {
5860
void set_tor_config(TorConfig tor_config);
5961
[Throws=BuildError]
6062
void set_node_alias(string node_alias);
63+
void set_backup_store(FfiDynStore backup_store);
64+
void set_ephemeral_store(FfiDynStore ephemeral_store);
6165
[Throws=BuildError]
6266
void set_async_payments_role(AsyncPaymentsRole? role);
6367
void set_wallet_recovery_mode();
@@ -73,6 +77,8 @@ interface Builder {
7377
Node build_with_vss_store_and_fixed_headers(NodeEntropy node_entropy, string vss_url, string store_id, record<string, string> fixed_headers);
7478
[Throws=BuildError]
7579
Node build_with_vss_store_and_header_provider(NodeEntropy node_entropy, string vss_url, string store_id, VssHeaderProvider header_provider);
80+
[Throws=BuildError]
81+
Node build_with_store(NodeEntropy node_entropy, FfiDynStore store);
7682
};
7783

7884
interface Node {

src/builder.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ use crate::connection::ConnectionManager;
5252
use crate::entropy::NodeEntropy;
5353
use crate::event::EventQueue;
5454
use crate::fee_estimator::OnchainFeeEstimator;
55+
#[cfg(feature = "uniffi")]
56+
use crate::ffi::FfiDynStore;
5557
use crate::gossip::GossipSource;
5658
use crate::io::sqlite_store::SqliteStore;
5759
use crate::io::tier_store::TierStore;
@@ -639,7 +641,6 @@ impl NodeBuilder {
639641
/// of all critical data written to the primary store.
640642
///
641643
/// Backup writes are non-blocking and do not affect primary store operation performance.
642-
#[allow(dead_code)]
643644
pub fn set_backup_store(&mut self, backup_store: Arc<DynStore>) -> &mut Self {
644645
let tier_store_config = self.tier_store_config.get_or_insert(TierStoreConfig::default());
645646
tier_store_config.backup = Some(backup_store);
@@ -653,7 +654,6 @@ impl NodeBuilder {
653654
/// can be rebuilt if lost.
654655
///
655656
/// If not set, non-critical data will be stored in the primary store.
656-
#[allow(dead_code)]
657657
pub fn set_ephemeral_store(&mut self, ephemeral_store: Arc<DynStore>) -> &mut Self {
658658
let tier_store_config = self.tier_store_config.get_or_insert(TierStoreConfig::default());
659659
tier_store_config.ephemeral = Some(ephemeral_store);
@@ -1144,6 +1144,31 @@ impl ArcedNodeBuilder {
11441144
self.inner.write().unwrap().set_wallet_recovery_mode();
11451145
}
11461146

1147+
/// Configures the backup store for local disaster recovery.
1148+
///
1149+
/// When building with tiered storage, this store receives asynchronous copies
1150+
/// of all critical data written to the primary store.
1151+
///
1152+
/// Backup writes are non-blocking and do not affect primary store operation performance.
1153+
pub fn set_backup_store(&self, backup_store: Arc<FfiDynStore>) {
1154+
let wrapper = DynStoreWrapper((*backup_store).clone());
1155+
let store: Arc<DynStore> = Arc::new(wrapper);
1156+
self.inner.write().unwrap().set_backup_store(store);
1157+
}
1158+
1159+
/// Configures the ephemeral store for non-critical, frequently-accessed data.
1160+
///
1161+
/// When building with tiered storage, this store is used for ephemeral data like
1162+
/// the network graph and scorer data to reduce latency for reads. Data stored here
1163+
/// can be rebuilt if lost.
1164+
///
1165+
/// If not set, non-critical data will be stored in the primary store.
1166+
pub fn set_ephemeral_store(&self, ephemeral_store: Arc<FfiDynStore>) {
1167+
let wrapper = DynStoreWrapper((*ephemeral_store).clone());
1168+
let store: Arc<DynStore> = Arc::new(wrapper);
1169+
self.inner.write().unwrap().set_ephemeral_store(store);
1170+
}
1171+
11471172
/// Builds a [`Node`] instance with a [`SqliteStore`] backend and according to the options
11481173
/// previously configured.
11491174
pub fn build(&self, node_entropy: Arc<NodeEntropy>) -> Result<Arc<Node>, BuildError> {
@@ -1272,12 +1297,19 @@ impl ArcedNodeBuilder {
12721297
}
12731298

12741299
/// Builds a [`Node`] instance according to the options previously configured.
1275-
// Note that the generics here don't actually work for Uniffi, but we don't currently expose
1276-
// this so its not needed.
1277-
pub fn build_with_store<S: SyncAndAsyncKVStore + Send + Sync + 'static>(
1278-
&self, node_entropy: Arc<NodeEntropy>, kv_store: S,
1300+
///
1301+
/// The provided `kv_store` will be used as the primary storage backend. Optionally,
1302+
/// an ephemeral store for frequently-accessed non-critical data (e.g., network graph, scorer)
1303+
/// and a backup store for local disaster recovery can be configured via
1304+
/// [`set_ephemeral_store`] and [`set_backup_store`].
1305+
///
1306+
/// [`set_ephemeral_store`]: Self::set_ephemeral_store
1307+
/// [`set_backup_store`]: Self::set_backup_store
1308+
pub fn build_with_store(
1309+
&self, node_entropy: Arc<NodeEntropy>, kv_store: Arc<FfiDynStore>,
12791310
) -> Result<Arc<Node>, BuildError> {
1280-
self.inner.read().unwrap().build_with_store(*node_entropy, kv_store).map(Arc::new)
1311+
let store = (*kv_store).clone();
1312+
self.inner.read().unwrap().build_with_store(*node_entropy, store).map(Arc::new)
12811313
}
12821314
}
12831315

0 commit comments

Comments
 (0)