diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 50c3cc704..463277571 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -43,6 +43,7 @@ interface Builder { Node build(); [Throws=BuildError] Node build_with_fs_store(); + void restore_encoded_channel_monitors(sequence monitors); }; interface Node { @@ -90,6 +91,9 @@ interface Node { [Throws=NodeError] string sign_message([ByRef]sequence msg); boolean verify_signature([ByRef]sequence msg, [ByRef]string sig, [ByRef]PublicKey pkey); + [Throws=NodeError] + sequence get_encoded_channel_monitors(); + void force_close_all_channels_without_broadcasting_txn(); }; interface Bolt11Payment { @@ -424,6 +428,11 @@ dictionary TlvEntry { sequence value; }; +dictionary KeyValue { + string key; + sequence value; +}; + interface NetworkGraph { sequence list_channels(); ChannelInfo? channel(u64 short_channel_id); diff --git a/src/builder.rs b/src/builder.rs index 56f3f3730..ad2c38c7a 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -15,8 +15,8 @@ use crate::payment::store::PaymentStore; use crate::peer_store::PeerStore; use crate::tx_broadcaster::TransactionBroadcaster; use crate::types::{ - ChainMonitor, ChannelManager, DynStore, GossipSync, Graph, KeysManager, MessageRouter, - OnionMessenger, PeerManager, + ChainMonitor, ChannelManager, DynStore, GossipSync, Graph, KeyValue, KeysManager, + MessageRouter, OnionMessenger, PeerManager, }; use crate::wallet::Wallet; use crate::{LogLevel, Node}; @@ -172,6 +172,7 @@ pub struct NodeBuilder { chain_data_source_config: Option, gossip_source_config: Option, liquidity_source_config: Option, + monitors_to_restore: Option>, } impl NodeBuilder { @@ -187,15 +188,23 @@ impl NodeBuilder { let chain_data_source_config = None; let gossip_source_config = None; let liquidity_source_config = None; + let monitors_to_restore = None; Self { config, entropy_source_config, chain_data_source_config, gossip_source_config, liquidity_source_config, + monitors_to_restore, } } + /// Alby: set monitors to restore when restoring SCB + pub fn restore_encoded_channel_monitors(&mut self, monitors: Vec) -> &mut Self { + self.monitors_to_restore = Some(monitors); + self + } + /// Configures the [`Node`] instance to source its wallet entropy from a seed file on disk. /// /// If the given file does not exist a new random seed file will be generated and @@ -316,6 +325,7 @@ impl NodeBuilder { ) .map_err(|_| BuildError::KVStoreSetupFailed)?, ); + self.build_with_store(kv_store) } @@ -381,6 +391,17 @@ impl NodeBuilder { )?; let config = Arc::new(self.config.clone()); + // Alby: Restore encoded channel monitors for a recovery of last resort + if self.monitors_to_restore.is_some() { + let monitors = self.monitors_to_restore.clone().unwrap(); + for monitor in monitors { + let result = kv_store.write("monitors", "", &monitor.key, &monitor.value); + if result.is_err() { + log_error!(logger, "Failed to restore monitor: {}", result.unwrap_err()); + } + } + } + build_with_store_internal( config, self.chain_data_source_config.as_ref(), @@ -420,6 +441,11 @@ impl ArcedNodeBuilder { Self { inner } } + /// Alby: set monitors to restore when restoring SCB + pub fn restore_encoded_channel_monitors(&self, monitors: Vec) { + self.inner.write().unwrap().restore_encoded_channel_monitors(monitors); + } + /// Configures the [`Node`] instance to source its wallet entropy from a seed file on disk. /// /// If the given file does not exist a new random seed file will be generated and diff --git a/src/lib.rs b/src/lib.rs index 030b31cff..9db31e572 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,7 @@ use types::{ Broadcaster, BumpTransactionEventHandler, ChainMonitor, ChannelManager, DynStore, FeeEstimator, Graph, KeysManager, PeerManager, Router, Scorer, Sweeper, Wallet, }; -pub use types::{ChannelDetails, ChannelType, PeerDetails, TlvEntry, UserChannelId}; +pub use types::{ChannelDetails, ChannelType, KeyValue, PeerDetails, TlvEntry, UserChannelId}; use logger::{log_error, log_info, log_trace, FilesystemLogger, Logger}; @@ -1539,6 +1539,33 @@ impl Node { self.payment_store.remove(&payment_id) } + /// Alby: Used to recover funds after restoring static channel backup + pub fn force_close_all_channels_without_broadcasting_txn(&self) { + self.channel_manager.force_close_all_channels_without_broadcasting_txn(); + } + + /// Alby: Return encoded channel monitors for a recovery of last resort + pub fn get_encoded_channel_monitors(&self) -> Result, Error> { + let channel_monitor_store = Arc::clone(&self.kv_store); + let channel_monitor_logger = Arc::clone(&self.logger); + let keys = channel_monitor_store.list("monitors", "").map_err(|e| { + log_error!(channel_monitor_logger, "Failed to get monitor keys: {}", e); + Error::ConnectionFailed + })?; + + let mut entries = Vec::new(); + + for key in keys { + let value = channel_monitor_store.read("monitors", "", &key).map_err(|e| { + log_error!(channel_monitor_logger, "Failed to get monitor value: {}", e); + Error::ConnectionFailed + })?; + entries.push(KeyValue { key, value }) + } + + return Ok(entries); + } + /// Retrieves an overview of all known balances. pub fn list_balances(&self) -> BalanceDetails { let cur_anchor_reserve_sats = diff --git a/src/types.rs b/src/types.rs index 151de9c38..5f9814cb0 100644 --- a/src/types.rs +++ b/src/types.rs @@ -492,3 +492,12 @@ impl_writeable_tlv_based!(TlvEntry, { (0, r#type, required), (1, value, required), }); + +/// KeyValue from LDK node DB +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct KeyValue { + /// Key. + pub key: String, + /// Serialized value. + pub value: Vec, +}