Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 161
Set node alias#330
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Set node alias #330
Changes from all commits
12dfc1ae54bfe05bd4a888e732967ad702981a0f4d32e7096059a30e09fca0911600346c3deaf6aff2820af5df64fd1cb8File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -32,6 +32,7 @@ use lightning::chain::{chainmonitor, BestBlock, Watch}; | ||
| use lightning::ln::channelmanager::{self, ChainParameters, ChannelManagerReadArgs}; | ||
| use lightning::ln::msgs::{RoutingMessageHandler, SocketAddress}; | ||
| use lightning::ln::peer_handler::{IgnoringMessageHandler, MessageHandler}; | ||
| use lightning::routing::gossip::NodeAlias; | ||
| use lightning::routing::router::DefaultRouter; | ||
| use lightning::routing::scoring::{ | ||
| ProbabilisticScorer, ProbabilisticScoringDecayParameters, ProbabilisticScoringFeeParameters, | ||
| @@ -109,7 +110,7 @@ impl Default for LiquiditySourceConfig { | ||
| /// An error encountered during building a [`Node`]. | ||
| /// | ||
| /// [`Node`]: crate::Node | ||
| #[derive(Debug, Clone)] | ||
| #[derive(Debug, Clone, PartialEq)] | ||
| pub enum BuildError { | ||
| /// The given seed bytes are invalid, e.g., have invalid length. | ||
| InvalidSeedBytes, | ||
| @@ -121,6 +122,8 @@ pub enum BuildError { | ||
| InvalidChannelMonitor, | ||
| /// The given listening addresses are invalid, e.g. too many were passed. | ||
| InvalidListeningAddresses, | ||
| /// The provided alias is invalid. | ||
| InvalidNodeAlias, | ||
| /// We failed to read data from the [`KVStore`]. | ||
| /// | ||
| /// [`KVStore`]: lightning::util::persist::KVStore | ||
| @@ -159,6 +162,7 @@ impl fmt::Display for BuildError { | ||
| Self::KVStoreSetupFailed => write!(f, "Failed to setup KVStore."), | ||
| Self::WalletSetupFailed => write!(f, "Failed to setup onchain wallet."), | ||
| Self::LoggerSetupFailed => write!(f, "Failed to setup the logger."), | ||
| Self::InvalidNodeAlias => write!(f, "Given node alias is invalid."), | ||
| } | ||
| } | ||
| } | ||
| @@ -303,6 +307,16 @@ impl NodeBuilder { | ||
| Ok(self) | ||
| } | ||
| /// Sets the alias the [`Node`] will use in its announcement. | ||
| /// | ||
| /// The provided alias must be a valid UTF-8 string. | ||
| pub fn set_node_alias(&mut self, node_alias: String) -> Result<&mut Self, BuildError> { | ||
| let node_alias = sanitize_alias(&node_alias)?; | ||
| self.config.node_alias = Some(node_alias); | ||
| Ok(self) | ||
| } | ||
| /// Sets the level at which [`Node`] will log messages. | ||
| pub fn set_log_level(&mut self, level: LogLevel) -> &mut Self { | ||
| self.config.log_level = level; | ||
| @@ -501,6 +515,11 @@ impl ArcedNodeBuilder { | ||
| self.inner.write().unwrap().set_listening_addresses(listening_addresses).map(|_| ()) | ||
| } | ||
| /// Sets the node alias. | ||
| pub fn set_node_alias(&self, node_alias: String) -> Result<(), BuildError> { | ||
| self.inner.write().unwrap().set_node_alias(node_alias).map(|_| ()) | ||
| } | ||
| /// Sets the level at which [`Node`] will log messages. | ||
| pub fn set_log_level(&self, level: LogLevel) { | ||
| self.inner.write().unwrap().set_log_level(level); | ||
| @@ -1050,3 +1069,58 @@ fn seed_bytes_from_config( | ||
| }, | ||
| } | ||
| } | ||
| /// Sanitize the user-provided node alias to ensure that it is a valid protocol-specified UTF-8 string. | ||
| pub(crate) fn sanitize_alias(alias_str: &str) -> Result<NodeAlias, BuildError> { | ||
tnull marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| let alias = alias_str.trim(); | ||
| // Alias must be 32-bytes long or less. | ||
| if alias.as_bytes().len() > 32 { | ||
| return Err(BuildError::InvalidNodeAlias); | ||
| } | ||
| let mut bytes = [0u8; 32]; | ||
| bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); | ||
| Ok(NodeAlias(bytes)) | ||
| } | ||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::{sanitize_alias, BuildError, NodeAlias}; | ||
| #[test] | ||
| fn sanitize_empty_node_alias() { | ||
| // Empty node alias | ||
| let alias = ""; | ||
| let mut buf = [0u8; 32]; | ||
| buf[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); | ||
| let expected_node_alias = NodeAlias([0; 32]); | ||
| let node_alias = sanitize_alias(alias).unwrap(); | ||
| assert_eq!(node_alias, expected_node_alias); | ||
| } | ||
| #[test] | ||
| fn sanitize_alias_with_sandwiched_null() { | ||
| // Alias with emojis | ||
| let alias = "I\u{1F496}LDK-Node!"; | ||
| let mut buf = [0u8; 32]; | ||
| buf[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); | ||
| let expected_alias = NodeAlias(buf); | ||
| let user_provided_alias = "I\u{1F496}LDK-Node!\0\u{26A1}"; | ||
| let node_alias = sanitize_alias(user_provided_alias).unwrap(); | ||
| let node_alias_display = format!("{}", node_alias); | ||
| assert_eq!(alias, &node_alias_display); | ||
| assert_ne!(expected_alias, node_alias); | ||
| } | ||
| #[test] | ||
| fn sanitize_alias_gt_32_bytes() { | ||
| let alias = "This is a string longer than thirty-two bytes!"; // 46 bytes | ||
| let node = sanitize_alias(alias); | ||
| assert_eq!(node.err().unwrap(), BuildError::InvalidNodeAlias); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -8,6 +8,7 @@ | ||
| use crate::payment::SendingParameters; | ||
| use lightning::ln::msgs::SocketAddress; | ||
| use lightning::routing::gossip::NodeAlias; | ||
| use lightning::util::config::UserConfig; | ||
| use lightning::util::logger::Level as LogLevel; | ||
| @@ -86,6 +87,7 @@ pub(crate) const WALLET_KEYS_SEED_LEN: usize = 64; | ||
| /// | `log_dir_path` | None | | ||
| /// | `network` | Bitcoin | | ||
| /// | `listening_addresses` | None | | ||
| /// | `node_alias` | None | | ||
tnull marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// | `default_cltv_expiry_delta` | 144 | | ||
| /// | `onchain_wallet_sync_interval_secs` | 80 | | ||
| /// | `wallet_sync_interval_secs` | 30 | | ||
| @@ -110,7 +112,15 @@ pub struct Config { | ||
| /// The used Bitcoin network. | ||
| pub network: Network, | ||
| /// The addresses on which the node will listen for incoming connections. | ||
| /// | ||
| /// **Note**: Node announcements will only be broadcast if the `node_alias` and the | ||
| /// `listening_addresses` are set. | ||
| pub listening_addresses: Option<Vec<SocketAddress>>, | ||
| /// The node alias to be used in announcements. | ||
| /// | ||
| /// **Note**: Node announcements will only be broadcast if the `node_alias` and the | ||
| /// `listening_addresses` are set. | ||
| pub node_alias: Option<NodeAlias>, | ||
| /// The time in-between background sync attempts of the onchain wallet, in seconds. | ||
| /// | ||
| /// **Note:** A minimum of 10 seconds is always enforced. | ||
| @@ -180,6 +190,7 @@ impl Default for Config { | ||
| log_level: DEFAULT_LOG_LEVEL, | ||
| anchor_channels_config: Some(AnchorChannelsConfig::default()), | ||
| sending_parameters: None, | ||
| node_alias: None, | ||
| } | ||
| } | ||
| } | ||
| @@ -265,17 +276,124 @@ pub fn default_config() -> Config { | ||
| Config::default() | ||
| } | ||
| /// Specifies reasons why a channel cannot be announced. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) enum ChannelAnnouncementBlocker { | ||
tnull marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| /// The node alias is not set. | ||
| MissingNodeAlias, | ||
| /// The listening addresses are not set. | ||
| MissingListeningAddresses, | ||
| // This listening addresses is set but the vector is empty. | ||
| EmptyListeningAddresses, | ||
| } | ||
| /// Enumeration defining the announcement status of a channel. | ||
| #[derive(Debug, PartialEq)] | ||
| pub(crate) enum ChannelAnnouncementStatus { | ||
| /// The channel is announceable. | ||
| Announceable, | ||
| /// The channel is not announceable. | ||
| Unannounceable(ChannelAnnouncementBlocker), | ||
| } | ||
| /// Checks if a node is can announce a channel based on the configured values of both the node's | ||
| /// alias and its listening addresses. | ||
| /// | ||
| /// If either of them is unset, the node cannot announce the channel. This ability to announce/ | ||
| /// unannounce a channel is codified with `ChannelAnnouncementStatus` | ||
| pub(crate) fn can_announce_channel(config: &Config) -> ChannelAnnouncementStatus { | ||
| if config.node_alias.is_none() { | ||
| return ChannelAnnouncementStatus::Unannounceable( | ||
| ChannelAnnouncementBlocker::MissingNodeAlias, | ||
| ); | ||
| } | ||
| match &config.listening_addresses { | ||
| None => ChannelAnnouncementStatus::Unannounceable( | ||
| ChannelAnnouncementBlocker::MissingListeningAddresses, | ||
| ), | ||
| Some(addresses) if addresses.is_empty() => ChannelAnnouncementStatus::Unannounceable( | ||
| ChannelAnnouncementBlocker::EmptyListeningAddresses, | ||
| ), | ||
| Some(_) => ChannelAnnouncementStatus::Announceable, | ||
| } | ||
| } | ||
| pub(crate) fn default_user_config(config: &Config) -> UserConfig { | ||
| // Initialize the default config values. | ||
| // | ||
| // Note that methods such as Node::connect_open_channel might override some of the values set | ||
| // here, e.g. the ChannelHandshakeConfig, meaning these default values will mostly be relevant | ||
| // for inbound channels. | ||
| // Note that methods such as Node::open_channel and Node::open_announced_channel might override | ||
| // some of the values set here, e.g. the ChannelHandshakeConfig, meaning these default values | ||
| // will mostly be relevant for inbound channels. | ||
| let mut user_config = UserConfig::default(); | ||
| user_config.channel_handshake_limits.force_announced_channel_preference = false; | ||
| user_config.manually_accept_inbound_channels = true; | ||
| user_config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = | ||
| config.anchor_channels_config.is_some(); | ||
| match can_announce_channel(config) { | ||
| ChannelAnnouncementStatus::Announceable => (), | ||
| ChannelAnnouncementStatus::Unannounceable(_) => { | ||
| user_config.accept_forwards_to_priv_channels = false; | ||
| user_config.channel_handshake_config.announced_channel = false; | ||
| user_config.channel_handshake_limits.force_announced_channel_preference = true; | ||
| }, | ||
| } | ||
| user_config | ||
| } | ||
| #[cfg(test)] | ||
| mod tests { | ||
| use std::str::FromStr; | ||
| use crate::config::ChannelAnnouncementStatus; | ||
| use super::can_announce_channel; | ||
| use super::Config; | ||
| use super::NodeAlias; | ||
| use super::SocketAddress; | ||
| #[test] | ||
| fn node_can_announce_channel() { | ||
| // Default configuration with node alias and listening addresses unset | ||
| let mut node_config = Config::default(); | ||
| assert_eq!( | ||
| can_announce_channel(&node_config), | ||
| ChannelAnnouncementStatus::Unannounceable( | ||
| crate::config::ChannelAnnouncementBlocker::MissingNodeAlias | ||
| ) | ||
| ); | ||
| // Set node alias with listening addresses unset | ||
| let alias_frm_str = |alias: &str| { | ||
| let mut bytes = [0u8; 32]; | ||
| bytes[..alias.as_bytes().len()].copy_from_slice(alias.as_bytes()); | ||
| NodeAlias(bytes) | ||
| }; | ||
| node_config.node_alias = Some(alias_frm_str("LDK_Node")); | ||
| assert_eq!( | ||
| can_announce_channel(&node_config), | ||
| ChannelAnnouncementStatus::Unannounceable( | ||
| crate::config::ChannelAnnouncementBlocker::MissingListeningAddresses | ||
| ) | ||
| ); | ||
| // Set node alias with an empty list of listening addresses | ||
| node_config.listening_addresses = Some(vec![]); | ||
| assert_eq!( | ||
| can_announce_channel(&node_config), | ||
| ChannelAnnouncementStatus::Unannounceable( | ||
| crate::config::ChannelAnnouncementBlocker::EmptyListeningAddresses | ||
| ) | ||
| ); | ||
| // Set node alias with a non-empty list of listening addresses | ||
| let socket_address = | ||
| SocketAddress::from_str("localhost:8000").expect("Socket address conversion failed."); | ||
| if let Some(ref mut addresses) = node_config.listening_addresses { | ||
| addresses.push(socket_address); | ||
| } | ||
| assert_eq!(can_announce_channel(&node_config), ChannelAnnouncementStatus::Announceable); | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.