Skip to content

Commit aa8bf83

Browse files
joostjagerclaude
andcommitted
Use DeferredChainMonitor for non-VSS storage backends
This change uses LDK's DeferredChainMonitor for local storage backends (SQLite, filesystem) instead of the regular ChainMonitor. The deferred variant queues watch_channel and update_channel operations for later flushing, enabling safe persistence ordering where the ChannelManager is persisted before the channel monitors. This ensures crash safety. VSS storage backends continue to use the regular ChainMonitor since VSS handles its own persistence ordering. The implementation: - Adds ChainMonitor enum that wraps both Regular and Deferred variants - Implements all required traits (Watch, Listen, Confirm, AChainMonitor, BaseMessageHandler, SendOnlyMessageHandler, EventsProvider) for the enum - Adds use_deferred_chain_monitor parameter to build_with_store_internal - Updates VSS build methods to use regular ChainMonitor (false) - Updates non-VSS build methods to use DeferredChainMonitor (true) Co-Authored-By: Claude Opus 4.5 <[email protected]>
1 parent a6a54a4 commit aa8bf83

File tree

3 files changed

+304
-27
lines changed

3 files changed

+304
-27
lines changed

Cargo.toml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,15 +169,15 @@ harness = false
169169
#vss-client-ng = { path = "../vss-client" }
170170
#vss-client-ng = { git = "https://github.com/lightningdevkit/vss-client", branch = "main" }
171171
#
172-
#[patch."https://github.com/lightningdevkit/rust-lightning"]
173-
#lightning = { path = "../rust-lightning/lightning" }
174-
#lightning-types = { path = "../rust-lightning/lightning-types" }
175-
#lightning-invoice = { path = "../rust-lightning/lightning-invoice" }
176-
#lightning-net-tokio = { path = "../rust-lightning/lightning-net-tokio" }
177-
#lightning-persister = { path = "../rust-lightning/lightning-persister" }
178-
#lightning-background-processor = { path = "../rust-lightning/lightning-background-processor" }
179-
#lightning-rapid-gossip-sync = { path = "../rust-lightning/lightning-rapid-gossip-sync" }
180-
#lightning-block-sync = { path = "../rust-lightning/lightning-block-sync" }
181-
#lightning-transaction-sync = { path = "../rust-lightning/lightning-transaction-sync" }
182-
#lightning-liquidity = { path = "../rust-lightning/lightning-liquidity" }
183-
#lightning-macros = { path = "../rust-lightning/lightning-macros" }
172+
[patch."https://github.com/lightningdevkit/rust-lightning"]
173+
lightning = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
174+
lightning-types = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
175+
lightning-invoice = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
176+
lightning-net-tokio = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
177+
lightning-persister = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
178+
lightning-background-processor = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
179+
lightning-rapid-gossip-sync = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
180+
lightning-block-sync = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
181+
lightning-transaction-sync = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
182+
lightning-liquidity = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }
183+
lightning-macros = { git = "https://github.com/joostjager/rust-lightning", branch = "chain-mon-deferred-writes" }

src/builder.rs

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,8 @@ impl NodeBuilder {
599599
BuildError::KVStoreSetupFailed
600600
})?;
601601

602-
self.build_with_store(node_entropy, vss_store)
602+
// VSS handles its own persistence ordering, so don't use deferred chain monitor
603+
self.build_with_store_internal(node_entropy, vss_store, false)
603604
}
604605

605606
/// Builds a [`Node`] instance with a [VSS] backend and according to the options
@@ -626,7 +627,8 @@ impl NodeBuilder {
626627
BuildError::KVStoreSetupFailed
627628
})?;
628629

629-
self.build_with_store(node_entropy, vss_store)
630+
// VSS handles its own persistence ordering, so don't use deferred chain monitor
631+
self.build_with_store_internal(node_entropy, vss_store, false)
630632
}
631633

632634
/// Builds a [`Node`] instance with a [VSS] backend and according to the options
@@ -651,12 +653,25 @@ impl NodeBuilder {
651653
BuildError::KVStoreSetupFailed
652654
})?;
653655

654-
self.build_with_store(node_entropy, vss_store)
656+
// VSS handles its own persistence ordering, so don't use deferred chain monitor
657+
self.build_with_store_internal(node_entropy, vss_store, false)
655658
}
656659

657660
/// Builds a [`Node`] instance according to the options previously configured.
661+
///
662+
/// For local storage backends (SQLite, filesystem), this uses `DeferredChainMonitor` which
663+
/// enables safe persistence ordering where the `ChannelManager` is persisted before the
664+
/// channel monitors.
658665
pub fn build_with_store<S: SyncAndAsyncKVStore + Send + Sync + 'static>(
659666
&self, node_entropy: NodeEntropy, kv_store: S,
667+
) -> Result<Node, BuildError> {
668+
// Use deferred chain monitor for local storage backends
669+
self.build_with_store_internal(node_entropy, kv_store, true)
670+
}
671+
672+
/// Internal method that builds a node with configurable chain monitor type.
673+
fn build_with_store_internal<S: SyncAndAsyncKVStore + Send + Sync + 'static>(
674+
&self, node_entropy: NodeEntropy, kv_store: S, use_deferred_chain_monitor: bool,
660675
) -> Result<Node, BuildError> {
661676
let logger = setup_logger(&self.log_writer_config, &self.config)?;
662677

@@ -683,6 +698,7 @@ impl NodeBuilder {
683698
runtime,
684699
logger,
685700
Arc::new(DynStoreWrapper(kv_store)),
701+
use_deferred_chain_monitor,
686702
)
687703
}
688704
}
@@ -1028,13 +1044,18 @@ impl ArcedNodeBuilder {
10281044
}
10291045

10301046
/// Builds a [`Node`] instance according to the options previously configured.
1047+
///
1048+
/// If `use_deferred_chain_monitor` is true, uses `DeferredChainMonitor` which defers monitor
1049+
/// operations until explicitly flushed. This enables safe persistence ordering where the
1050+
/// `ChannelManager` is persisted before the channel monitors. This should be used for local
1051+
/// storage backends (SQLite, etc.) but NOT for VSS which handles its own persistence ordering.
10311052
fn build_with_store_internal(
10321053
config: Arc<Config>, chain_data_source_config: Option<&ChainDataSourceConfig>,
10331054
gossip_source_config: Option<&GossipSourceConfig>,
10341055
liquidity_source_config: Option<&LiquiditySourceConfig>,
10351056
pathfinding_scores_sync_config: Option<&PathfindingScoresSyncConfig>,
10361057
async_payments_role: Option<AsyncPaymentsRole>, seed_bytes: [u8; 64], runtime: Arc<Runtime>,
1037-
logger: Arc<Logger>, kv_store: Arc<DynStore>,
1058+
logger: Arc<Logger>, kv_store: Arc<DynStore>, use_deferred_chain_monitor: bool,
10381059
) -> Result<Node, BuildError> {
10391060
optionally_install_rustls_cryptoprovider();
10401061

@@ -1334,15 +1355,29 @@ fn build_with_store_internal(
13341355
));
13351356

13361357
// Initialize the ChainMonitor
1337-
let chain_monitor: Arc<ChainMonitor> = Arc::new(chainmonitor::ChainMonitor::new(
1338-
Some(Arc::clone(&chain_source)),
1339-
Arc::clone(&tx_broadcaster),
1340-
Arc::clone(&logger),
1341-
Arc::clone(&fee_estimator),
1342-
Arc::clone(&persister),
1343-
Arc::clone(&keys_manager),
1344-
peer_storage_key,
1345-
));
1358+
// Use DeferredChainMonitor for local storage backends to enable safe persistence ordering.
1359+
// VSS handles its own persistence ordering, so it uses the regular ChainMonitor.
1360+
let chain_monitor: Arc<ChainMonitor> = if use_deferred_chain_monitor {
1361+
Arc::new(ChainMonitor::Deferred(lightning::chain::deferred::DeferredChainMonitor::new(
1362+
Some(Arc::clone(&chain_source)),
1363+
Arc::clone(&tx_broadcaster),
1364+
Arc::clone(&logger),
1365+
Arc::clone(&fee_estimator),
1366+
Arc::clone(&persister),
1367+
Arc::clone(&keys_manager),
1368+
peer_storage_key,
1369+
)))
1370+
} else {
1371+
Arc::new(ChainMonitor::Regular(chainmonitor::ChainMonitor::new(
1372+
Some(Arc::clone(&chain_source)),
1373+
Arc::clone(&tx_broadcaster),
1374+
Arc::clone(&logger),
1375+
Arc::clone(&fee_estimator),
1376+
Arc::clone(&persister),
1377+
Arc::clone(&keys_manager),
1378+
peer_storage_key,
1379+
)))
1380+
};
13461381

13471382
// Initialize the network graph, scorer, and router
13481383
let network_graph = match network_graph_res {

0 commit comments

Comments
 (0)