diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 01215d400..47c776315 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -4,6 +4,7 @@ namespace ldk_node { dictionary Config { string storage_dir_path = "/tmp/ldk_node/"; + string? log_dir_path = null; Network network = "Bitcoin"; NetAddress? listening_address = null; u32 default_cltv_expiry_delta = 144; diff --git a/src/builder.rs b/src/builder.rs index dddc6d064..1e6fee7fb 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -202,6 +202,12 @@ impl NodeBuilder { self } + /// Sets the log dir path if logs need to live separate from the storage directory path. + pub fn set_log_dir_path(&mut self, log_dir_path: String) -> &mut Self { + self.config.log_dir_path = Some(log_dir_path); + self + } + /// Sets the Bitcoin network used. pub fn set_network(&mut self, network: Network) -> &mut Self { self.config.network = network; @@ -329,6 +335,11 @@ impl ArcedNodeBuilder { self.inner.write().unwrap().set_storage_dir_path(storage_dir_path); } + /// Sets the log dir path if logs need to live separate from the storage directory path. + pub fn set_log_dir_path(&self, log_dir_path: String) { + self.inner.write().unwrap().set_log_dir_path(log_dir_path); + } + /// Sets the Bitcoin network used. pub fn set_network(&self, network: Network) { self.inner.write().unwrap().set_network(network); @@ -377,10 +388,15 @@ fn build_with_store_internal( let bdk_data_dir = format!("{}/bdk", config.storage_dir_path); fs::create_dir_all(bdk_data_dir.clone()).map_err(|_| BuildError::StoragePathAccessFailed)?; + let log_dir = match &config.log_dir_path { + Some(log_dir) => String::from(log_dir), + None => config.storage_dir_path.clone() + "/logs", + }; + // Initialize the Logger let log_file_path = format!( - "{}/logs/ldk_node_{}.log", - config.storage_dir_path, + "{}/ldk_node_{}.log", + log_dir, chrono::offset::Local::now().format("%Y_%m_%d") ); let logger = Arc::new( @@ -646,13 +662,13 @@ fn build_with_store_internal( chan_handler: Arc::clone(&channel_manager), route_handler: Arc::clone(&p2p_gossip_sync) as Arc, - onion_message_handler: onion_messenger, + onion_message_handler: onion_messenger.clone(), }, GossipSync::Rapid(_) => MessageHandler { chan_handler: Arc::clone(&channel_manager), route_handler: Arc::new(IgnoringMessageHandler {}) as Arc, - onion_message_handler: onion_messenger, + onion_message_handler: onion_messenger.clone(), }, GossipSync::None => { unreachable!("We must always have a gossip sync!"); @@ -722,5 +738,6 @@ fn build_with_store_internal( scorer, peer_store, payment_store, + onion_messenger: onion_messenger, }) } diff --git a/src/lib.rs b/src/lib.rs index 1fbd33f78..2aa920bca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,6 +101,8 @@ use error::Error; pub use event::Event; pub use types::NetAddress; +use types::OnionMessenger; + pub use io::utils::generate_entropy_mnemonic; #[cfg(feature = "uniffi")] @@ -128,7 +130,9 @@ use lightning::chain::keysinterface::EntropySource; use lightning::chain::Confirm; use lightning::ln::channelmanager::{self, PaymentId, RecipientOnionFields, Retry}; use lightning::ln::{PaymentHash, PaymentPreimage}; +use lightning::onion_message::{CustomOnionMessageContents, Destination, OnionMessageContents}; +use lightning::util::ser::{Writeable, Writer}; use lightning::util::config::{ChannelConfig, ChannelHandshakeConfig, UserConfig}; pub use lightning::util::logger::Level as LogLevel; @@ -193,26 +197,48 @@ const WALLET_SYNC_INTERVAL_MINIMUM_SECS: u64 = 10; // The length in bytes of our wallets' keys seed. const WALLET_KEYS_SEED_LEN: usize = 64; +struct UserOnionMessageContents { + tlv_type: u64, + data: Vec, +} + +impl CustomOnionMessageContents for UserOnionMessageContents { + fn tlv_type(&self) -> u64 { + self.tlv_type + } +} + +impl Writeable for UserOnionMessageContents { + fn write(&self, w: &mut W) -> Result<(), std::io::Error> { + w.write_all(&self.data) + } +} + #[derive(Debug, Clone)] /// Represents the configuration of an [`Node`] instance. /// /// ### Defaults /// -/// | Parameter | Value | -/// |----------------------------------------|------------------| -/// | `storage_dir_path` | /tmp/ldk_node/ | -/// | `network` | Bitcoin | -/// | `listening_address` | None | -/// | `default_cltv_expiry_delta` | 144 | -/// | `onchain_wallet_sync_interval_secs` | 80 | -/// | `wallet_sync_interval_secs` | 30 | -/// | `fee_rate_cache_update_interval_secs` | 600 | -/// | `trusted_peers_0conf` | [] | -/// | `log_level` | Debug | +/// | Parameter | Value | +/// |----------------------------------------|--------------------| +/// | `storage_dir_path` | /tmp/ldk_node/ | +/// | `log_dir_path` | None | +/// | `network` | Bitcoin | +/// | `listening_address` | None | +/// | `default_cltv_expiry_delta` | 144 | +/// | `onchain_wallet_sync_interval_secs` | 80 | +/// | `wallet_sync_interval_secs` | 30 | +/// | `fee_rate_cache_update_interval_secs` | 600 | +/// | `trusted_peers_0conf` | [] | +/// | `log_level` | Debug | /// pub struct Config { /// The path where the underlying LDK and BDK persist their data. pub storage_dir_path: String, + /// The path where logs are stored. + /// + /// If set to `None`, logs can be found in the `logs` subdirectory in [`Config::storage_dir_path`]. + pub log_dir_path: Option, /// The used Bitcoin network. pub network: Network, /// The IP address and TCP port the node will listen on. @@ -247,6 +273,7 @@ impl Default for Config { fn default() -> Self { Self { storage_dir_path: DEFAULT_STORAGE_DIR_PATH.to_string(), + log_dir_path: None, network: DEFAULT_NETWORK, listening_address: None, default_cltv_expiry_delta: DEFAULT_CLTV_EXPIRY_DELTA, @@ -281,6 +308,7 @@ pub struct Node { scorer: Arc>, peer_store: Arc>>, payment_store: Arc>>, + onion_messenger: Arc, } impl Node { @@ -807,6 +835,21 @@ impl Node { self.wallet.send_to_address(address, None) } + /// Send an onion message to the following address. + pub fn send_onion_message( + &self, node_pks: Vec, destination_pk: PublicKey, tlv_type: u64, data: Vec, + ) { + match self.onion_messenger.send_onion_message( + &node_pks, + Destination::Node(destination_pk), + OnionMessageContents::Custom(UserOnionMessageContents { tlv_type, data }), + None, + ) { + Ok(()) => println!("SUCCESS: forwarded onion message to first hop"), + Err(e) => println!("ERROR: failed to send onion message: {:?}", e), + } + } + /// Retrieve a list of known channels. pub fn list_channels(&self) -> Vec { self.channel_manager.list_channels().into_iter().map(|c| c.into()).collect()