Skip to content

Commit

Permalink
SQUASH-ME: Splits data structures into parsers and internals
Browse files Browse the repository at this point in the history
Adds `ActivityParser`, `LndConnectionParser` and `ClnConnectionParser` to
directly interface with the config file, rolls back `ActivityDefinition`,
`LndConnectionParser` and `ClnConnection` to use PublicKeys.
  • Loading branch information
sr-gi committed Sep 23, 2023
1 parent cd1315a commit 75795ca
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 65 deletions.
8 changes: 5 additions & 3 deletions sim-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use tokio::sync::Mutex;
use clap::Parser;
use log::LevelFilter;
use sim_lib::{
cln::ClnNode, lnd::LndNode, Config, LightningError, LightningNode, NodeConnection, NodeId,
Simulation,
cln::ClnNode, lnd::LndNode, ActivityDefinition, Config, LightningError, LightningNode,
NodeConnection, NodeId, Simulation,
};
use simple_logger::SimpleLogger;

Expand Down Expand Up @@ -81,6 +81,7 @@ async fn main() -> anyhow::Result<()> {
clients.insert(node_info.pubkey, node);
}

let mut activities = vec![];
// Make all the activities identifiable by PK internally
for act in activity.iter_mut() {
// We can only map aliases to nodes we control, so if either the source or destination alias
Expand All @@ -105,9 +106,10 @@ async fn main() -> anyhow::Result<()> {
)));
}
}
activities.push(ActivityDefinition::try_from(act)?);
}

let sim = Simulation::new(clients, activity, cli.total_time, cli.print_batch_size);
let sim = Simulation::new(clients, activities, cli.total_time, cli.print_batch_size);
let sim2 = sim.clone();

ctrlc::set_handler(move || {
Expand Down
27 changes: 25 additions & 2 deletions sim-lib/src/cln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,46 @@ use cln_grpc::pb::{
use lightning::ln::features::NodeFeatures;
use lightning::ln::PaymentHash;

use serde::{Deserialize, Serialize};
use tokio::fs::File;
use tokio::io::{AsyncReadExt, Error};
use tokio::time::{self, Duration};
use tonic::transport::{Certificate, Channel, ClientTlsConfig, Identity};
use triggered::Listener;

use crate::{
ClnConnection, LightningError, LightningNode, NodeInfo, PaymentOutcome, PaymentResult,
serializers, LightningError, LightningNode, NodeId, NodeInfo, PaymentOutcome, PaymentResult,
};

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ClnConnectionParser {
#[serde(with = "serializers::serde_node_id")]
pub id: NodeId,
pub address: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub ca_cert: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub client_cert: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub client_key: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ClnConnection {
pub id: PublicKey,
pub address: String,
pub ca_cert: String,
pub client_cert: String,
pub client_key: String,
}

pub struct ClnNode {
pub client: NodeClient<Channel>,
info: NodeInfo,
}

impl ClnNode {
pub async fn new(connection: ClnConnection) -> Result<Self, LightningError> {
pub async fn new(connection: ClnConnectionParser) -> Result<Self, LightningError> {
let tls = ClientTlsConfig::new()
.domain_name("cln")
.identity(Identity::from_pem(
Expand Down
110 changes: 52 additions & 58 deletions sim-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ mod serializers;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum NodeConnection {
#[serde(alias = "lnd", alias = "Lnd")]
LND(LndConnection),
LND(lnd::LndConnectionParser),
#[serde(alias = "cln", alias = "Cln")]
CLN(ClnConnection),
CLN(cln::ClnConnectionParser),
}

#[derive(Serialize, Debug, Clone)]
Expand Down Expand Up @@ -58,51 +58,57 @@ impl std::fmt::Display for NodeId {
}
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LndConnection {
#[serde(with = "serializers::serde_node_id")]
pub id: NodeId,
pub address: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub macaroon: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub cert: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct ClnConnection {
#[serde(with = "serializers::serde_node_id")]
pub id: NodeId,
pub address: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub ca_cert: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub client_cert: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub client_key: String,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Config {
pub nodes: Vec<NodeConnection>,
pub activity: Vec<ActivityDefinition>,
pub activity: Vec<ActivityParser>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActivityDefinition {
pub struct ActivityParser {
// The source of the payment.
#[serde(with = "serializers::serde_node_id")]
pub source: NodeId,
// The destination of the payment.
#[serde(with = "serializers::serde_node_id")]
pub destination: NodeId,
// The interval of the event, as in every how many seconds the payment is performed.
#[serde(alias = "interval_secs")]
pub interval: u16,
pub interval_secs: u16,
// The amount of m_sat to used in this payment.
pub amount_msat: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ActivityDefinition {
// The source of the payment.
pub source: PublicKey,
// The destination of the payment.
pub destination: PublicKey,
// The interval of the event, as in every how many seconds the payment is performed.
pub interval: u16,
// The amount of m_sat to used in this payment.
pub amount: u64,
}

impl TryFrom<&mut ActivityParser> for ActivityDefinition {
type Error = LightningError;

fn try_from(a: &mut ActivityParser) -> Result<Self, Self::Error> {
let source = *a.source.get_pk().map_err(Self::Error::ValidationError)?;
let destination = *a
.destination
.get_pk()
.map_err(Self::Error::ValidationError)?;

Ok(Self {
source,
destination,
interval: a.interval_secs,
amount: a.amount_msat,
})
}
}

#[derive(Debug, Error)]
pub enum SimulationError {
#[error("Lightning Error: {0:?}")]
Expand Down Expand Up @@ -275,29 +281,20 @@ impl Simulation {
for payment_flow in self.activity.iter() {
// We need every source node that is configured to execute some activity to be included in our set of
// nodes so that we can execute events on it.
let src_id = payment_flow
.source
.get_pk()
.map_err(LightningError::ValidationError)?;
let src_node = self
.nodes
.get(src_id)
.ok_or(LightningError::ValidationError(format!(
"Source node not found, {}",
src_id,
)))?;

let dest_id = payment_flow
.destination
.get_pk()
.map_err(LightningError::ValidationError)?;
let src_node =
self.nodes
.get(&payment_flow.source)
.ok_or(LightningError::ValidationError(format!(
"Source node not found, {}",
payment_flow.source,
)))?;

// Destinations must support keysend to be able to receive payments.
// Note: validation should be update with a different check if an event is not a payment.
let features = src_node
.lock()
.await
.get_node_features(dest_id)
.get_node_features(&payment_flow.destination)
.await
.map_err(|e| {
log::debug!("{}", e);
Expand All @@ -310,7 +307,7 @@ impl Simulation {
if !features.supports_keysend() {
return Err(LightningError::ValidationError(format!(
"Destination node does not support keysend, {}",
dest_id
payment_flow.destination,
)));
}
}
Expand Down Expand Up @@ -426,8 +423,8 @@ impl Simulation {
for (id, node) in self.nodes.iter().filter(|(pk, _)| {
self.activity
.iter()
.map(|a| a.source.get_pk().unwrap())
.collect::<HashSet<&PublicKey>>()
.map(|a| a.source)
.collect::<HashSet<PublicKey>>()
.contains(pk)
}) {
// For each active node, we'll create a sender and receiver channel to produce and consumer
Expand All @@ -448,9 +445,7 @@ impl Simulation {
}

for description in self.activity.iter() {
let sender_chan = producer_channels
.get(&description.source.get_pk().unwrap())
.unwrap();
let sender_chan = producer_channels.get(&description.source).unwrap();
tasks.spawn(produce_events(
description.clone(),
sender_chan.clone(),
Expand Down Expand Up @@ -531,13 +526,12 @@ async fn produce_events(
shutdown: Trigger,
listener: Listener,
) {
let e: SimulationEvent =
SimulationEvent::SendPayment(*act.destination.get_pk().unwrap(), act.amount_msat);
let e: SimulationEvent = SimulationEvent::SendPayment(act.destination, act.amount);
let interval = time::Duration::from_secs(act.interval as u64);

log::debug!(
"Started producer for {} every {}s: {} -> {}.",
act.amount_msat,
act.amount,
act.interval,
act.source,
act.destination
Expand All @@ -551,7 +545,7 @@ async fn produce_events(
if sender.send(e).await.is_err() {
log::debug!(
"Stopped producer for {}: {} -> {}. Consumer cannot be reached.",
act.amount_msat,
act.amount,
act.source,
act.destination
);
Expand All @@ -562,7 +556,7 @@ async fn produce_events(
// Shutdown was signaled
log::debug!(
"Stopped producer for {}: {} -> {}. Received shutdown signal.",
act.amount_msat,
act.amount,
act.source,
act.destination
);
Expand Down
24 changes: 22 additions & 2 deletions sim-lib/src/lnd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ use std::collections::HashSet;
use std::{collections::HashMap, str::FromStr};

use crate::{
LightningError, LightningNode, LndConnection, NodeInfo, PaymentOutcome, PaymentResult,
serializers, LightningError, LightningNode, NodeId, NodeInfo, PaymentOutcome, PaymentResult,
};
use async_trait::async_trait;
use bitcoin::hashes::{sha256, Hash};
use bitcoin::secp256k1::PublicKey;
use lightning::ln::features::NodeFeatures;
use lightning::ln::{PaymentHash, PaymentPreimage};
use serde::{Deserialize, Serialize};
use tonic_lnd::lnrpc::{payment::PaymentStatus, GetInfoRequest, GetInfoResponse};
use tonic_lnd::lnrpc::{NodeInfoRequest, PaymentFailureReason};
use tonic_lnd::routerrpc::TrackPaymentRequest;
Expand All @@ -18,6 +19,25 @@ use triggered::Listener;
const KEYSEND_KEY: u64 = 5482373484;
const SEND_PAYMENT_TIMEOUT_SECS: i32 = 300;

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LndConnectionParser {
#[serde(with = "serializers::serde_node_id")]
pub id: NodeId,
pub address: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub macaroon: String,
#[serde(deserialize_with = "serializers::deserialize_path")]
pub cert: String,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct LndConnection {
pub id: PublicKey,
pub address: String,
pub macaroon: String,
pub cert: String,
}

pub struct LndNode {
client: Client,
info: NodeInfo,
Expand All @@ -42,7 +62,7 @@ fn parse_node_features(features: HashSet<u32>) -> NodeFeatures {
}

impl LndNode {
pub async fn new(connection: LndConnection) -> Result<Self, LightningError> {
pub async fn new(connection: LndConnectionParser) -> Result<Self, LightningError> {
let mut client =
tonic_lnd::connect(connection.address, connection.cert, connection.macaroon)
.await
Expand Down

0 comments on commit 75795ca

Please sign in to comment.