From def8dd10970a8b24c19d6b75a3b211b140054152 Mon Sep 17 00:00:00 2001 From: Sergi Delgado Segura Date: Tue, 3 Oct 2023 12:09:58 -0400 Subject: [PATCH] sim-lib: Adds LightningNode::get_network The current approach to get the network from a node stores the information in `NodeInfo`. However, this is troublesome going forward given we will start using `NodeInfo` to store information about nodes we do not control (and from which we cannot query the network). Furthermore, the network information is worthless once we've sanity-checked that we are running on a network we support and all nodes are running on the same one, so there is no point keeping that around --- sim-lib/src/cln.rs | 15 +++++++++++++-- sim-lib/src/lib.rs | 41 ++++++++++++++++++++--------------------- sim-lib/src/lnd.rs | 41 +++++++++++++++++++++++++++++++++-------- 3 files changed, 66 insertions(+), 31 deletions(-) diff --git a/sim-lib/src/cln.rs b/sim-lib/src/cln.rs index dd4e75d3..de173980 100644 --- a/sim-lib/src/cln.rs +++ b/sim-lib/src/cln.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; use bitcoin::secp256k1::PublicKey; +use bitcoin::Network; use cln_grpc::pb::{ listpays_pays::ListpaysPaysStatus, node_client::NodeClient, Amount, GetinfoRequest, GetinfoResponse, KeysendRequest, KeysendResponse, ListchannelsRequest, ListnodesRequest, @@ -59,7 +60,6 @@ impl ClnNode { id, alias, our_features, - network, .. } = client .getinfo(GetinfoRequest {}) @@ -81,7 +81,6 @@ impl ClnNode { .map_err(|err| LightningError::GetInfoError(err.to_string()))?, features, alias: alias.unwrap_or("".to_string()), - network, }, }) } @@ -123,6 +122,18 @@ impl LightningNode for ClnNode { &self.info } + async fn get_network(&mut self) -> Result { + let info = self + .client + .getinfo(GetinfoRequest {}) + .await + .map_err(|err| LightningError::GetInfoError(err.to_string()))? + .into_inner(); + + Ok(Network::from_core_arg(&info.network) + .map_err(|err| LightningError::ValidationError(err.to_string()))?) + } + async fn send_payment( &mut self, dest: PublicKey, diff --git a/sim-lib/src/lib.rs b/sim-lib/src/lib.rs index 6806f8bc..ce6f302b 100644 --- a/sim-lib/src/lib.rs +++ b/sim-lib/src/lib.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; use bitcoin::secp256k1::PublicKey; +use bitcoin::Network; use csv::WriterBuilder; use lightning::ln::features::NodeFeatures; use lightning::ln::PaymentHash; @@ -120,7 +121,6 @@ pub struct NodeInfo { pub pubkey: PublicKey, pub alias: String, pub features: NodeFeatures, - pub network: String, } /// LightningNode represents the functionality that is required to execute events on a lightning node. @@ -128,6 +128,8 @@ pub struct NodeInfo { pub trait LightningNode { /// Get information about the node. fn get_info(&self) -> &NodeInfo; + /// Get the network this node is running at + async fn get_network(&mut self) -> Result; /// Keysend payment worth `amount_msat` from a source node to the destination node. async fn send_payment( &mut self, @@ -348,37 +350,34 @@ impl Simulation { Ok(()) } - // it validates that the nodes are all on the same network and ensures that we're not running on mainnet. + // validates that the nodes are all on the same network and ensures that we're not running on mainnet. async fn validate_node_network(&self) -> Result<(), LightningError> { - let mut valid_network = Option::None; - let unsupported_networks: HashSet = vec!["mainnet", "bitcoin"] - .into_iter() - .map(|s| s.to_string()) - .collect(); + if self.nodes.is_empty() { + return Err(LightningError::ValidationError( + "we don't control any nodes. Specify at least one node in your config file" + .to_string(), + )); + } + let mut running_network = Option::None; for node in self.nodes.values() { - let network = node.lock().await.get_info().network.clone(); - if unsupported_networks.contains(&network) { + let network = node.lock().await.get_network().await?; + if network == Network::Bitcoin { return Err(LightningError::ValidationError( "mainnet is not supported".to_string(), )); } - valid_network = valid_network.take().or_else(|| Some(network.clone())); - if let Some(valid) = &valid_network { - if valid != &network { - return Err(LightningError::ValidationError(format!( - "nodes are not on the same network {}.", - network, - ))); - } + running_network = running_network.take().or(Some(network)); + if running_network != Some(network) { + return Err(LightningError::ValidationError(format!( + "nodes are not on the same network {}.", + network, + ))); } } - log::info!( - "Simulation is running on the network: {}.", - valid_network.as_ref().unwrap() - ); + log::info!("Simulation is running on {}.", running_network.unwrap()); Ok(()) } diff --git a/sim-lib/src/lnd.rs b/sim-lib/src/lnd.rs index ef958807..61532920 100644 --- a/sim-lib/src/lnd.rs +++ b/sim-lib/src/lnd.rs @@ -7,6 +7,7 @@ use crate::{ use async_trait::async_trait; use bitcoin::hashes::{sha256, Hash}; use bitcoin::secp256k1::PublicKey; +use bitcoin::Network; use lightning::ln::features::NodeFeatures; use lightning::ln::{PaymentHash, PaymentPreimage}; use tonic_lnd::lnrpc::{payment::PaymentStatus, GetInfoRequest, GetInfoResponse}; @@ -53,7 +54,6 @@ impl LndNode { identity_pubkey, features, alias, - chains, .. } = client .lightning() @@ -62,12 +62,6 @@ impl LndNode { .map_err(|err| LightningError::GetInfoError(err.to_string()))? .into_inner(); - if chains.len() != 1 { - return Err(LightningError::GetInfoError( - "LND node is not connected to a single chain".to_string(), - )); - } - Ok(Self { client, info: NodeInfo { @@ -75,7 +69,6 @@ impl LndNode { .map_err(|err| LightningError::GetInfoError(err.to_string()))?, features: parse_node_features(features.keys().cloned().collect()), alias, - network: chains[0].network.clone(), }, }) } @@ -90,6 +83,38 @@ impl LightningNode for LndNode { &self.info } + async fn get_network(&mut self) -> Result { + let info = self + .client + .lightning() + .get_info(GetInfoRequest {}) + .await + .map_err(|err| LightningError::GetInfoError(err.to_string()))? + .into_inner(); + + if info.chains.is_empty() { + return Err(LightningError::ValidationError( + "LND node is not connected any chain".to_string(), + )); + } else if info.chains.len() > 1 { + return Err(LightningError::ValidationError(format!( + "LND node is connected to more than one chain: {:?}", + info.chains.iter().map(|c| c.chain.to_string()) + ))); + } + + Ok(Network::from_str(match info.chains[0].network.as_str() { + "mainnet" => "bitcoin", + "simnet" => { + return Err(LightningError::ValidationError( + "simnet is not supported".to_string(), + )) + } + x => x, + }) + .map_err(|err| LightningError::ValidationError(err.to_string()))?) + } + async fn send_payment( &mut self, dest: PublicKey,