From 399b02b86c019178b51aa1fb6b0883271d6127cd Mon Sep 17 00:00:00 2001 From: Roman Dmitrienko Date: Mon, 16 Dec 2024 11:08:32 +0300 Subject: [PATCH] Implement transient network graph option. --- bindings/ldk_node.udl | 1 + src/builder.rs | 12 ++++++-- src/config.rs | 6 ++++ src/io/sqlite_store/mod.rs | 59 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 73 insertions(+), 5 deletions(-) diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index a4f659b80..7ab3f71e2 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -14,6 +14,7 @@ dictionary Config { LogLevel log_level; AnchorChannelsConfig? anchor_channels_config; SendingParameters? sending_parameters; + boolean transient_network_graph; }; dictionary AnchorChannelsConfig { diff --git a/src/builder.rs b/src/builder.rs index 0573d6947..1695f61cf 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -12,7 +12,7 @@ use crate::connection::ConnectionManager; use crate::event::EventQueue; use crate::fee_estimator::OnchainFeeEstimator; use crate::gossip::GossipSource; -use crate::io::sqlite_store::SqliteStore; +use crate::io::sqlite_store::{SqliteStore, SqliteStoreConfig}; use crate::io::utils::{read_node_metrics, write_node_metrics}; use crate::io::vss_store::VssStore; use crate::io::{ @@ -383,11 +383,14 @@ impl NodeBuilder { let storage_dir_path = self.config.storage_dir_path.clone(); fs::create_dir_all(storage_dir_path.clone()) .map_err(|_| BuildError::StoragePathAccessFailed)?; + let sql_store_config = + SqliteStoreConfig { transient_graph: self.config.transient_network_graph }; let kv_store = Arc::new( - SqliteStore::new( + SqliteStore::with_config( storage_dir_path.into(), Some(io::sqlite_store::SQLITE_DB_FILE_NAME.to_string()), Some(io::sqlite_store::KV_TABLE_NAME.to_string()), + sql_store_config, ) .map_err(|_| BuildError::KVStoreSetupFailed)?, ); @@ -554,11 +557,14 @@ impl NodeBuilder { // Alby: use a secondary KV store for non-essential data (not needed by VSS) let storage_dir_path = config.storage_dir_path.clone(); + let sql_store_config = + SqliteStoreConfig { transient_graph: self.config.transient_network_graph }; let secondary_kv_store = Arc::new( - SqliteStore::new( + SqliteStore::with_config( storage_dir_path.into(), Some(io::sqlite_store::SQLITE_DB_FILE_NAME.to_string()), Some(io::sqlite_store::KV_TABLE_NAME.to_string()), + sql_store_config, ) .map_err(|_| BuildError::KVStoreSetupFailed)?, ) as Arc; diff --git a/src/config.rs b/src/config.rs index fd48eece4..20317aa16 100644 --- a/src/config.rs +++ b/src/config.rs @@ -166,6 +166,11 @@ pub struct Config { /// **Note:** If unset, default parameters will be used, and you will be able to override the /// parameters on a per-payment basis in the corresponding method calls. pub sending_parameters: Option, + /// Alby: Transient network graph. + /// + /// If set to `true`, the graph is not persisted in the database and is only kept in memory. + /// It will be rebuilt on each restart. + pub transient_network_graph: bool, } impl Default for Config { @@ -181,6 +186,7 @@ impl Default for Config { anchor_channels_config: Some(AnchorChannelsConfig::default()), sending_parameters: None, node_alias: None, + transient_network_graph: false, } } } diff --git a/src/io/sqlite_store/mod.rs b/src/io/sqlite_store/mod.rs index b72db5a2b..7bbcfdd4a 100644 --- a/src/io/sqlite_store/mod.rs +++ b/src/io/sqlite_store/mod.rs @@ -9,7 +9,10 @@ use crate::io::utils::check_namespace_key_validity; use lightning::io; -use lightning::util::persist::KVStore; +use lightning::util::persist::{ + KVStore, NETWORK_GRAPH_PERSISTENCE_KEY, NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, + NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, +}; use lightning::util::string::PrintableString; use rusqlite::{named_params, Connection}; @@ -41,6 +44,19 @@ pub struct SqliteStore { connection: Arc>, data_dir: PathBuf, kv_table_name: String, + config: SqliteStoreConfig, +} + +/// Alby: extended SqliteStore configuration. +pub struct SqliteStoreConfig { + /// Do not persist network graph. + pub(crate) transient_graph: bool, +} + +impl Default for SqliteStoreConfig { + fn default() -> Self { + Self { transient_graph: false } + } } impl SqliteStore { @@ -120,7 +136,28 @@ impl SqliteStore { })?; let connection = Arc::new(Mutex::new(connection)); - Ok(Self { connection, data_dir, kv_table_name }) + Ok(Self { connection, data_dir, kv_table_name, config: SqliteStoreConfig::default() }) + } + + /// Alby: constructs a new [`SqliteStore`] with an extended configuration. + pub fn with_config( + data_dir: PathBuf, db_file_name: Option, kv_table_name: Option, + config: SqliteStoreConfig, + ) -> io::Result { + let mut ret = SqliteStore::new(data_dir, db_file_name, kv_table_name)?; + + if config.transient_graph { + // Drop existing network graph if it has been persisted before. + ret.remove( + NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE, + NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE, + NETWORK_GRAPH_PERSISTENCE_KEY, + false, + )?; + } + + ret.config = config; + Ok(ret) } /// Returns the data directory. @@ -135,6 +172,15 @@ impl KVStore for SqliteStore { ) -> io::Result> { check_namespace_key_validity(primary_namespace, secondary_namespace, Some(key), "read")?; + if self.config.transient_graph + && primary_namespace == NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE + && secondary_namespace == NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE + && key == NETWORK_GRAPH_PERSISTENCE_KEY + { + // Alby: returning "not found" here will cause the network graph to be rebuilt from scratch. + return Err(io::Error::new(io::ErrorKind::NotFound, "network graph is not persisted")); + } + let locked_conn = self.connection.lock().unwrap(); let sql = format!("SELECT value FROM {} WHERE primary_namespace=:primary_namespace AND secondary_namespace=:secondary_namespace AND key=:key;", @@ -183,6 +229,15 @@ impl KVStore for SqliteStore { ) -> io::Result<()> { check_namespace_key_validity(primary_namespace, secondary_namespace, Some(key), "write")?; + if self.config.transient_graph + && primary_namespace == NETWORK_GRAPH_PERSISTENCE_PRIMARY_NAMESPACE + && secondary_namespace == NETWORK_GRAPH_PERSISTENCE_SECONDARY_NAMESPACE + && key == NETWORK_GRAPH_PERSISTENCE_KEY + { + // Alby: transient network graph is not persisted. + return Ok(()); + } + let locked_conn = self.connection.lock().unwrap(); let sql = format!(