Skip to content

Commit 66daf69

Browse files
authored
Merge pull request #306 from elnosh/fix-excluded-nodes
return all `SimNode`s from `ln_node_from_graph`
2 parents ec1aa36 + bfb24fd commit 66daf69

7 files changed

Lines changed: 89 additions & 70 deletions

File tree

sim-cli/src/parsing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ pub async fn create_simulation_with_network(
301301
));
302302

303303
// Copy all simulated channels into a read-only routing graph, allowing to pathfind for
304-
// individual payments without locking th simulation graph (this is a duplication of the channels,
304+
// individual payments without locking the simulation graph (this is a duplication of the channels,
305305
// but the performance tradeoff is worthwhile for concurrent pathfinding).
306306
let routing_graph = Arc::new(
307307
populate_network_graph(channels, clock.clone())
@@ -312,7 +312,7 @@ pub async fn create_simulation_with_network(
312312
// custom actions on the simulated network. For the nodes we'll pass our simulation, cast them
313313
// to a dyn trait and exclude any nodes that shouldn't be included in random activity
314314
// generation.
315-
let nodes = ln_node_from_graph(simulation_graph.clone(), routing_graph, clock.clone()).await?;
315+
let nodes = ln_node_from_graph(simulation_graph, routing_graph, clock.clone()).await?;
316316
let mut nodes_dyn: HashMap<_, Arc<Mutex<dyn LightningNode>>> = nodes
317317
.iter()
318318
.map(|(pk, node)| (*pk, Arc::clone(node) as Arc<Mutex<dyn LightningNode>>))

simln-lib/src/cln.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,10 +264,10 @@ impl LightningNode for ClnNode {
264264
}
265265
}
266266

267-
async fn list_channels(&self) -> Result<Vec<u64>, LightningError> {
267+
async fn channel_capacities(&self) -> Result<u64, LightningError> {
268268
let mut node_channels = self.node_channels(true).await?;
269269
node_channels.extend(self.node_channels(false).await?);
270-
Ok(node_channels)
270+
Ok(node_channels.iter().sum())
271271
}
272272

273273
async fn get_graph(&self) -> Result<Graph, LightningError> {

simln-lib/src/eclair.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ impl LightningNode for EclairNode {
222222
})
223223
}
224224

225-
async fn list_channels(&self) -> Result<Vec<u64>, LightningError> {
225+
async fn channel_capacities(&self) -> Result<u64, LightningError> {
226226
let client = self.client.lock().await;
227227
let channels: ChannelsResponse = client
228228
.request("channels", None)
@@ -242,7 +242,7 @@ impl LightningNode for EclairNode {
242242
})
243243
.collect();
244244

245-
Ok(capacities_msat)
245+
Ok(capacities_msat.iter().sum())
246246
}
247247

248248
async fn get_graph(&self) -> Result<Graph, LightningError> {

simln-lib/src/lib.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,9 @@ pub trait LightningNode: Send {
343343
) -> Result<PaymentResult, LightningError>;
344344
/// Gets information on a specific node.
345345
async fn get_node_info(&self, node_id: &PublicKey) -> Result<NodeInfo, LightningError>;
346-
/// Lists all channels, at present only returns a vector of channel capacities in msat because no further
347-
/// information is required.
348-
async fn list_channels(&self) -> Result<Vec<u64>, LightningError>;
346+
/// Sum of channel capacities. This is used when running with random activity generation to
347+
/// determine how much the node will send per month.
348+
async fn channel_capacities(&self) -> Result<u64, LightningError>;
349349
/// Get the network graph from the point of view of a given node.
350350
async fn get_graph(&self) -> Result<Graph, LightningError>;
351351
}
@@ -1003,7 +1003,7 @@ impl<C: Clock + 'static> Simulation<C> {
10031003
// While we're at it, we get the node info and store it with capacity to create activity generators in our
10041004
// second pass.
10051005
for (pk, node) in self.nodes.iter() {
1006-
let chan_capacity = node.lock().await.list_channels().await?.iter().sum::<u64>();
1006+
let chan_capacity = node.lock().await.channel_capacities().await?;
10071007

10081008
if let Err(e) = RandomPaymentActivity::validate_capacity(
10091009
chan_capacity,
@@ -1935,8 +1935,8 @@ mod tests {
19351935
.expect_get_network()
19361936
.returning(|| Network::Regtest);
19371937
mock_node
1938-
.expect_list_channels()
1939-
.returning(|| Ok(vec![100_000_000]));
1938+
.expect_channel_capacities()
1939+
.returning(|| Ok(100_000_000));
19401940
mock_node
19411941
.expect_get_node_info()
19421942
.returning(move |_| Ok(node_info.clone()));

simln-lib/src/lnd.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ impl LightningNode for LndNode {
252252
}
253253
}
254254

255-
async fn list_channels(&self) -> Result<Vec<u64>, LightningError> {
255+
async fn channel_capacities(&self) -> Result<u64, LightningError> {
256256
let mut client = self.client.lock().await;
257257
let channels = client
258258
.lightning()
@@ -268,7 +268,7 @@ impl LightningNode for LndNode {
268268
.channels
269269
.iter()
270270
.map(|channel| 1000 * channel.capacity as u64)
271-
.collect())
271+
.sum())
272272
}
273273

274274
async fn get_graph(&self) -> Result<Graph, LightningError> {

simln-lib/src/sim_node.rs

Lines changed: 74 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ impl SimulatedChannel {
477477

478478
/// SimNetwork represents a high level network coordinator that is responsible for the task of actually propagating
479479
/// payments through the simulated network.
480+
#[async_trait]
480481
pub trait SimNetwork: Send + Sync {
481482
/// Sends payments over the route provided through the network, reporting the final payment outcome to the sender
482483
/// channel provided.
@@ -490,7 +491,7 @@ pub trait SimNetwork: Send + Sync {
490491
);
491492

492493
/// Looks up a node in the simulated network and a list of its channel capacities.
493-
fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError>;
494+
async fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError>;
494495
/// Lists all nodes in the simulated network.
495496
fn list_nodes(&self) -> Vec<NodeInfo>;
496497
}
@@ -794,11 +795,17 @@ impl<T: SimNetwork, C: Clock> LightningNode for SimNode<T, C> {
794795
}
795796

796797
async fn get_node_info(&self, node_id: &PublicKey) -> Result<NodeInfo, LightningError> {
797-
Ok(self.network.lock().await.lookup_node(node_id)?.0)
798+
Ok(self.network.lock().await.lookup_node(node_id).await?.0)
798799
}
799800

800-
async fn list_channels(&self) -> Result<Vec<u64>, LightningError> {
801-
Ok(self.network.lock().await.lookup_node(&self.info.pubkey)?.1)
801+
async fn channel_capacities(&self) -> Result<u64, LightningError> {
802+
let channels = self
803+
.network
804+
.lock()
805+
.await
806+
.lookup_node(&self.info.pubkey)
807+
.await?;
808+
Ok(channels.1.iter().sum())
802809
}
803810

804811
async fn get_graph(&self) -> Result<Graph, LightningError> {
@@ -1017,9 +1024,9 @@ async fn handle_intercepted_htlc(
10171024

10181025
/// Graph is the top level struct that is used to coordinate simulation of lightning nodes.
10191026
pub struct SimGraph {
1020-
/// nodes caches the list of nodes in the network with a vector of their channel capacities, only used for quick
1027+
/// nodes caches the list of nodes in the network with a vector of their channel ids, only used for quick
10211028
/// lookup.
1022-
nodes: HashMap<PublicKey, (NodeInfo, Vec<u64>)>,
1029+
nodes: HashMap<PublicKey, (NodeInfo, Vec<ShortChannelID>)>,
10231030

10241031
/// channels maps the scid of a channel to its current simulation state.
10251032
channels: Arc<Mutex<HashMap<ShortChannelID, SimulatedChannel>>>,
@@ -1051,7 +1058,7 @@ impl SimGraph {
10511058
default_custom_records: CustomRecords,
10521059
shutdown_signal: (Trigger, Listener),
10531060
) -> Result<Self, SimulationError> {
1054-
let mut nodes: HashMap<PublicKey, (NodeInfo, Vec<u64>)> = HashMap::new();
1061+
let mut nodes: HashMap<PublicKey, (NodeInfo, Vec<ShortChannelID>)> = HashMap::new();
10551062
let mut channels = HashMap::new();
10561063

10571064
for channel in graph_channels.iter() {
@@ -1068,18 +1075,16 @@ impl SimGraph {
10681075
Entry::Vacant(v) => v.insert(channel.clone()),
10691076
};
10701077

1071-
if !channel.exclude_capacity {
1072-
// It's okay to have duplicate pubkeys because one node can have many channels.
1073-
for info in [&channel.node_1.policy, &channel.node_2.policy] {
1074-
match nodes.entry(info.pubkey) {
1075-
Entry::Occupied(o) => o.into_mut().1.push(channel.capacity_msat),
1076-
Entry::Vacant(v) => {
1077-
v.insert((
1078-
node_info(info.pubkey, info.alias.clone()),
1079-
vec![channel.capacity_msat],
1080-
));
1081-
},
1082-
}
1078+
// It's okay to have duplicate pubkeys because one node can have many channels.
1079+
for info in [&channel.node_1.policy, &channel.node_2.policy] {
1080+
match nodes.entry(info.pubkey) {
1081+
Entry::Occupied(o) => o.into_mut().1.push(channel.short_channel_id),
1082+
Entry::Vacant(v) => {
1083+
v.insert((
1084+
node_info(info.pubkey, info.alias.clone()),
1085+
vec![channel.short_channel_id],
1086+
));
1087+
},
10831088
}
10841089
}
10851090
}
@@ -1101,9 +1106,11 @@ pub async fn ln_node_from_graph<C: Clock>(
11011106
routing_graph: Arc<LdkNetworkGraph>,
11021107
clock: Arc<C>,
11031108
) -> Result<HashMap<PublicKey, Arc<Mutex<SimNode<SimGraph, C>>>>, LightningError> {
1104-
let mut nodes: HashMap<PublicKey, Arc<Mutex<SimNode<SimGraph, C>>>> = HashMap::new();
1109+
let sim_graph = graph.lock().await;
1110+
let mut nodes: HashMap<PublicKey, Arc<Mutex<SimNode<SimGraph, C>>>> =
1111+
HashMap::with_capacity(sim_graph.nodes.len());
11051112

1106-
for node in graph.lock().await.nodes.iter() {
1113+
for node in sim_graph.nodes.iter() {
11071114
nodes.insert(
11081115
*node.0,
11091116
Arc::new(Mutex::new(SimNode::new(
@@ -1182,6 +1189,7 @@ pub fn populate_network_graph<C: Clock>(
11821189
Ok(graph)
11831190
}
11841191

1192+
#[async_trait]
11851193
impl SimNetwork for SimGraph {
11861194
/// dispatch_payment asynchronously propagates a payment through the simulated network, returning a tracking
11871195
/// channel that can be used to obtain the result of the payment. At present, MPP payments are not supported.
@@ -1231,13 +1239,27 @@ impl SimNetwork for SimGraph {
12311239
}
12321240

12331241
/// lookup_node fetches a node's information and channel capacities.
1234-
fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError> {
1235-
match self.nodes.get(node) {
1236-
Some(node) => Ok(node.clone()),
1237-
None => Err(LightningError::GetNodeInfoError(
1238-
"Node not found".to_string(),
1239-
)),
1240-
}
1242+
async fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError> {
1243+
let node_info = match self.nodes.get(node) {
1244+
Some(node) => node.clone(),
1245+
None => {
1246+
return Err(LightningError::GetNodeInfoError(format!(
1247+
"Node {} not found",
1248+
node
1249+
)))
1250+
},
1251+
};
1252+
1253+
let channels = self.channels.lock().await;
1254+
let capacities: Vec<u64> = node_info
1255+
.1
1256+
.iter()
1257+
.filter_map(|scid| channels.get(scid))
1258+
.filter(|channel| !channel.exclude_capacity)
1259+
.map(|channel| channel.capacity_msat)
1260+
.collect();
1261+
1262+
Ok((node_info.0, capacities))
12411263
}
12421264

12431265
fn list_nodes(&self) -> Vec<NodeInfo> {
@@ -1965,34 +1987,25 @@ mod tests {
19651987
.await
19661988
.unwrap();
19671989

1968-
let node_1_channels = nodes
1969-
.get(&pk1)
1970-
.unwrap()
1971-
.lock()
1972-
.await
1973-
.list_channels()
1974-
.await
1975-
.unwrap();
1990+
assert!(nodes.len() == 3);
19761991

1977-
// Node 1 has 2 channels but one was excluded so here we should only have the one that was
1978-
// not excluded.
1979-
assert!(node_1_channels.len() == 1);
1980-
assert!(node_1_channels[0] == capacity_1);
1992+
let node_1 = nodes.get(&pk1).unwrap().lock().await;
1993+
let node_1_capacity = node_1.channel_capacities().await.unwrap();
19811994

1982-
let node_2_channels = nodes
1983-
.get(&pk2)
1984-
.unwrap()
1985-
.lock()
1986-
.await
1987-
.list_channels()
1988-
.await
1989-
.unwrap();
1995+
// Node 1 has 2 channels but one was excluded so here we should only have the capacity of
1996+
// the channel that was not excluded.
1997+
assert!(node_1_capacity == capacity_1);
19901998

1991-
assert!(node_2_channels.len() == 1);
1992-
assert!(node_2_channels[0] == capacity_1);
1999+
let node_2 = nodes.get(&pk2).unwrap().lock().await;
2000+
let node_2_capacity = node_2.channel_capacities().await.unwrap();
2001+
assert!(node_2_capacity == capacity_1);
19932002

1994-
// Node 3's only channel was excluded so it won't be present here.
1995-
assert!(!nodes.contains_key(&pk3));
2003+
// Node 3 should be returned from ln_node_from_graph but it won't have any channel capacity
2004+
// present because its only channel was excluded.
2005+
let node_3 = nodes.get(&pk3);
2006+
assert!(node_3.is_some());
2007+
let node_3 = node_3.unwrap().lock().await;
2008+
assert!(node_3.channel_capacities().await.unwrap() == 0);
19962009
}
19972010

19982011
/// Tests basic functionality of a `SimulatedChannel` but does no endeavor to test the underlying
@@ -2062,6 +2075,7 @@ mod tests {
20622075
mock! {
20632076
Network{}
20642077

2078+
#[async_trait]
20652079
impl SimNetwork for Network{
20662080
fn dispatch_payment(
20672081
&mut self,
@@ -2072,7 +2086,7 @@ mod tests {
20722086
sender: Sender<Result<PaymentResult, LightningError>>,
20732087
);
20742088

2075-
fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError>;
2089+
async fn lookup_node(&self, node: &PublicKey) -> Result<(NodeInfo, Vec<u64>), LightningError>;
20762090
fn list_nodes(&self) -> Vec<NodeInfo>;
20772091
}
20782092
}
@@ -2103,12 +2117,17 @@ mod tests {
21032117
.lock()
21042118
.await
21052119
.expect_lookup_node()
2106-
.returning(move |_| Ok((node_info(lookup_pk, String::default()), vec![1, 2, 3])));
2120+
.returning(move |_| {
2121+
Ok((
2122+
node_info(lookup_pk, String::default()),
2123+
vec![10_000, 20_000, 10_000],
2124+
))
2125+
});
21072126

21082127
// Assert that we get three channels from the mock.
21092128
let node_info = node.get_node_info(&lookup_pk).await.unwrap();
21102129
assert_eq!(lookup_pk, node_info.pubkey);
2111-
assert_eq!(node.list_channels().await.unwrap().len(), 3);
2130+
assert_eq!(node.channel_capacities().await.unwrap(), 40_000);
21122131

21132132
// Next, we're going to test handling of in-flight payments. To do this, we'll mock out calls to our dispatch
21142133
// function to send different results depending on the destination.

simln-lib/src/test_utils.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ mock! {
8989
shutdown: triggered::Listener,
9090
) -> Result<crate::PaymentResult, LightningError>;
9191
async fn get_node_info(&self, node_id: &PublicKey) -> Result<NodeInfo, LightningError>;
92-
async fn list_channels(&self) -> Result<Vec<u64>, LightningError>;
92+
async fn channel_capacities(&self) -> Result<u64, LightningError>;
9393
async fn get_graph(&self) -> Result<Graph, LightningError>;
9494
}
9595
}

0 commit comments

Comments
 (0)