Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,072 changes: 928 additions & 144 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion sim-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ serde_json = "1.0.104"
simple_logger = "4.2.0"
simln-lib = { path = "../simln-lib" }
tokio = { version = "1.26.0", features = ["full"] }
bitcoin = { version = "0.30.1" }
bitcoin = { version = "0.32" }
ctrlc = "3.4.0"
rand = "0.8.5"
hex = {version = "0.4.3"}
Expand Down
39 changes: 29 additions & 10 deletions sim-cli/src/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use simln_lib::sim_node::{
SimGraph, SimNode, SimulatedChannel,
};
use simln_lib::{
cln, cln::ClnNode, eclair, eclair::EclairNode, lnd, lnd::LndNode, serializers,
cln, cln::ClnNode, eclair, eclair::EclairNode, ldk, lnd, lnd::LndNode, serializers,
ActivityDefinition, Amount, Interval, LightningError, LightningNode, NodeId, NodeInfo,
Simulation, SimulationCfg, WriteResults,
};
Expand Down Expand Up @@ -152,6 +152,9 @@ pub struct SimParams {
pub activity: Vec<ActivityParser>,
#[serde(default)]
pub exclude: Vec<PublicKey>,
/// Optional hub configuration. See [`ldk::LdkHubConfig`] for how absence is interpreted.
#[serde(default)]
pub ldk_hub: Option<ldk::LdkHubConfig>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
Expand All @@ -160,6 +163,7 @@ pub enum NodeConnection {
Lnd(lnd::LndConnection),
Cln(cln::ClnConnection),
Eclair(eclair::EclairConnection),
Ldk(ldk::LdkNodeConfig),
}

/// Data structure that is used to parse information from the simulation file. It is used to
Expand Down Expand Up @@ -260,6 +264,7 @@ pub async fn create_simulation_with_network(
sim_network,
activity: _activity,
exclude,
ldk_hub: _,
} = sim_params;

// Convert nodes representation for parsing to SimulatedChannel
Expand Down Expand Up @@ -351,9 +356,10 @@ pub async fn create_simulation(
sim_network: _sim_network,
activity: _activity,
exclude: _,
ldk_hub: _,
} = sim_params;

let (clients, clients_info) = get_clients(nodes.to_vec()).await?;
let (clients, clients_info) = get_clients(nodes.to_vec(), sim_params.ldk_hub.clone()).await?;
let (shutdown_trigger, shutdown_listener) = triggered::trigger();

let validated_activities =
Expand All @@ -374,10 +380,9 @@ pub async fn create_simulation(
))
}

/// Connects to the set of nodes providing, returning a map of node public keys to LightningNode implementations and
/// a map of public key to node info to be used for validation.
async fn get_clients(
nodes: Vec<NodeConnection>,
ldk_hub: Option<ldk::LdkHubConfig>,
) -> Result<
(
HashMap<PublicKey, Arc<Mutex<dyn LightningNode>>>,
Expand All @@ -388,18 +393,32 @@ async fn get_clients(
let mut clients: HashMap<PublicKey, Arc<Mutex<dyn LightningNode>>> = HashMap::new();
let mut clients_info: HashMap<PublicKey, NodeInfo> = HashMap::new();

for connection in nodes {
// TODO: Feels like there should be a better way of doing this without having to Arc<Mutex<T>>> it at this time.
// Box sort of works, but we won't know the size of the dyn LightningNode at compile time so the compiler will
// scream at us when trying to create the Arc<Mutex>> later on while adding the node to the clients map
let (ldk_connections, other_connections): (Vec<_>, Vec<_>) =
nodes.into_iter().partition(|n| matches!(n, NodeConnection::Ldk(_)));

let ldk_configs: Vec<ldk::LdkNodeConfig> = ldk_connections
.into_iter()
.filter_map(|n| match n {
NodeConnection::Ldk(cfg) => Some(cfg),
_ => None,
})
.collect();

for ldk_node in ldk::build_ldk_nodes(ldk_configs, ldk_hub).await? {
let info = ldk_node.get_info().clone();
let node: Arc<Mutex<dyn LightningNode>> = Arc::new(Mutex::new(ldk_node));
clients.insert(info.pubkey, node);
clients_info.insert(info.pubkey, info);
}

for connection in other_connections {
let node: Arc<Mutex<dyn LightningNode>> = match connection {
NodeConnection::Lnd(c) => Arc::new(Mutex::new(LndNode::new(c).await?)),
NodeConnection::Cln(c) => Arc::new(Mutex::new(ClnNode::new(c).await?)),
NodeConnection::Eclair(c) => Arc::new(Mutex::new(EclairNode::new(c).await?)),
NodeConnection::Ldk(_) => unreachable!(),
};

let node_info = node.lock().await.get_info().clone();

clients.insert(node_info.pubkey, node);
clients_info.insert(node_info.pubkey, node_info);
}
Expand Down
10 changes: 6 additions & 4 deletions simln-lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ Components to build a network-agnostic lightning payments simulator. Used as the
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
ldk-node = "0.7.0"
corepc-client = { version = "0.10.0", features = ["client-sync"] }
anyhow = { version = "1.0.69", features = ["backtrace"] }
cln-grpc = "0.1.3"
cln-grpc = "0.6.0"
expanduser = "1.2.2"
serde = { version="1.0.183", features=["derive"] }
serde_json = "1.0.104"
bitcoin = { version = "0.30.1", features=["serde"] }
lightning = { version = "0.0.123" }
bitcoin = { version = "0.32", features=["serde"] }
lightning = { version = "0.2.2" }
tonic_lnd = { package="fedimint-tonic-lnd", version="0.1.2", features=["lightningrpc", "routerrpc"]}
tonic = { version = "0.8", features = ["tls", "transport"] }
tonic = { version = "0.11", features = ["tls", "transport"] }
async-trait = "0.1.73"
thiserror = "1.0.45"
log = "0.4.20"
Expand Down
10 changes: 5 additions & 5 deletions simln-lib/src/cln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use cln_grpc::pb::{
KeysendRequest, KeysendResponse, ListchannelsRequest, ListnodesRequest, ListpaysRequest,
ListpaysResponse,
};
use lightning::ln::features::NodeFeatures;
use lightning::ln::PaymentHash;
use lightning::types::features::NodeFeatures;
use lightning::types::payment::PaymentHash;
use serde::{Deserialize, Serialize};
use tokio::fs::File;
use tokio::io::{AsyncReadExt, Error};
Expand Down Expand Up @@ -94,7 +94,7 @@ impl ClnNode {

let pubkey = PublicKey::from_slice(&info.id)
.map_err(|err| LightningError::GetInfoError(err.to_string()))?;
let mut alias = info.alias.unwrap_or_default();
let mut alias = info.alias;
connection.id.validate(&pubkey, &mut alias)?;

let features = match info.our_features {
Expand Down Expand Up @@ -216,8 +216,8 @@ impl LightningNode for ClnNode {
.into_inner();

if let Some(pay) = pays.first() {
let payment_status = ListpaysPaysStatus::from_i32(pay.status)
.ok_or(LightningError::TrackPaymentError("Invalid payment status".to_string()))?;
let payment_status = ListpaysPaysStatus::try_from(pay.status)
.map_err(|_| LightningError::TrackPaymentError("Invalid payment status".to_string()))?;

let payment_outcome = match payment_status {
ListpaysPaysStatus::Pending => continue,
Expand Down
4 changes: 2 additions & 2 deletions simln-lib/src/eclair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
use async_trait::async_trait;
use bitcoin::secp256k1::PublicKey;
use bitcoin::Network;
use lightning::ln::features::NodeFeatures;
use lightning::ln::{PaymentHash, PaymentPreimage};
use lightning::types::features::NodeFeatures;
use lightning::types::payment::{PaymentHash, PaymentPreimage};
use reqwest::multipart::Form;
use reqwest::{Client, Method, Url};
use serde::{Deserialize, Serialize};
Expand Down
2 changes: 1 addition & 1 deletion simln-lib/src/latency_interceptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ mod tests {
use crate::sim_node::{CustomRecords, HtlcRef, InterceptRequest};
use crate::test_utils::get_random_keypair;
use crate::ShortChannelID;
use lightning::ln::PaymentHash;
use lightning::types::payment::PaymentHash;
use ntest::assert_true;
use rand::distributions::Distribution;
use rand::Rng;
Expand Down
Loading