Skip to content

Commit f155904

Browse files
committed
sim_node: add helper functions to produce simulation graph and nodes
1 parent 6ea47bb commit f155904

File tree

1 file changed

+96
-11
lines changed

1 file changed

+96
-11
lines changed

sim-lib/src/sim_node.rs

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,24 @@ use crate::{
33
};
44
use async_trait::async_trait;
55
use bitcoin::constants::ChainHash;
6-
use bitcoin::Network;
7-
use bitcoin::{
8-
hashes::{sha256::Hash as Sha256, Hash},
9-
secp256k1::PublicKey,
6+
use bitcoin::hashes::{sha256::Hash as Sha256, Hash};
7+
use bitcoin::secp256k1::PublicKey;
8+
use bitcoin::{Network, ScriptBuf, TxOut};
9+
use lightning::ln::chan_utils::make_funding_redeemscript;
10+
use std::collections::{hash_map::Entry, HashMap};
11+
use std::sync::Arc;
12+
use std::time::{SystemTime, UNIX_EPOCH};
13+
14+
use lightning::ln::features::{ChannelFeatures, NodeFeatures};
15+
use lightning::ln::msgs::{
16+
LightningError as LdkError, UnsignedChannelAnnouncement, UnsignedChannelUpdate,
1017
};
11-
use bitcoin::{ScriptBuf, TxOut};
12-
use lightning::ln::features::NodeFeatures;
13-
use lightning::ln::msgs::LightningError as LdkError;
1418
use lightning::ln::{PaymentHash, PaymentPreimage};
15-
use lightning::routing::gossip::NetworkGraph;
19+
use lightning::routing::gossip::{NetworkGraph, NodeId};
1620
use lightning::routing::router::{find_route, Path, PaymentParameters, Route, RouteParameters};
1721
use lightning::routing::scoring::ProbabilisticScorer;
1822
use lightning::routing::utxo::{UtxoLookup, UtxoResult};
1923
use lightning::util::logger::{Level, Logger, Record};
20-
use std::collections::hash_map::Entry;
21-
use std::collections::HashMap;
22-
use std::sync::Arc;
2324
use thiserror::Error;
2425
use tokio::select;
2526
use tokio::sync::oneshot::{channel, Receiver, Sender};
@@ -660,6 +661,90 @@ impl SimGraph {
660661
}
661662
}
662663

664+
/// Produces a map of node public key to lightning node implementation to be used for simulations.
665+
pub async fn ln_node_from_graph<'a>(
666+
graph: Arc<Mutex<SimGraph>>,
667+
routing_graph: Arc<NetworkGraph<&'_ WrappedLog>>,
668+
) -> HashMap<PublicKey, Arc<Mutex<dyn LightningNode + '_>>> {
669+
let mut nodes: HashMap<PublicKey, Arc<Mutex<dyn LightningNode>>> = HashMap::new();
670+
671+
for pk in graph.lock().await.nodes.keys() {
672+
nodes.insert(
673+
*pk,
674+
Arc::new(Mutex::new(SimNode::new(
675+
*pk,
676+
graph.clone(),
677+
routing_graph.clone(),
678+
))),
679+
);
680+
}
681+
682+
nodes
683+
}
684+
685+
/// Populates a network graph based on the set of simulated channels provided. This function *only* applies channel
686+
/// announcements, which has the effect of adding the nodes in each channel to the graph, because LDK does not export
687+
/// all of the fields required to apply node announcements. This means that we will not have node-level information
688+
/// (such as features) available in the routing graph.
689+
pub fn populate_network_graph<'a>(
690+
channels: Vec<SimulatedChannel>,
691+
) -> Result<NetworkGraph<&'a WrappedLog>, LdkError> {
692+
let graph = NetworkGraph::new(Network::Regtest, &WrappedLog {});
693+
694+
let chain_hash = ChainHash::using_genesis_block(Network::Regtest);
695+
696+
for channel in channels {
697+
let announcement = UnsignedChannelAnnouncement {
698+
// For our purposes we don't currently need any channel level features.
699+
features: ChannelFeatures::empty(),
700+
chain_hash,
701+
short_channel_id: channel.short_channel_id.into(),
702+
node_id_1: NodeId::from_pubkey(&channel.node_1.policy.pubkey),
703+
node_id_2: NodeId::from_pubkey(&channel.node_2.policy.pubkey),
704+
// Note: we don't need bitcoin keys for our purposes, so we just copy them *but* remember that we do use
705+
// this for our fake utxo validation so they do matter for producing the script that we mock validate.
706+
bitcoin_key_1: NodeId::from_pubkey(&channel.node_1.policy.pubkey),
707+
bitcoin_key_2: NodeId::from_pubkey(&channel.node_2.policy.pubkey),
708+
// Internal field used by LDK, we don't need it.
709+
excess_data: Vec::new(),
710+
};
711+
712+
let utxo_validator = UtxoValidator {
713+
amount_sat: channel.capacity_msat / 1000,
714+
script: make_funding_redeemscript(
715+
&channel.node_1.policy.pubkey,
716+
&channel.node_2.policy.pubkey,
717+
)
718+
.to_v0_p2wsh(),
719+
};
720+
721+
graph.update_channel_from_unsigned_announcement(&announcement, &Some(&utxo_validator))?;
722+
723+
// The least significant bit of the channel flag field represents the direction that the channel update
724+
// applies to. This value is interpreted as node_1 if it is zero, and node_2 otherwise.
725+
for (i, node) in [channel.node_1, channel.node_2].iter().enumerate() {
726+
let update = UnsignedChannelUpdate {
727+
chain_hash,
728+
short_channel_id: channel.short_channel_id.into(),
729+
timestamp: SystemTime::now()
730+
.duration_since(UNIX_EPOCH)
731+
.unwrap()
732+
.as_secs() as u32,
733+
flags: i as u8,
734+
cltv_expiry_delta: node.policy.cltv_expiry_delta as u16,
735+
htlc_minimum_msat: node.policy.min_htlc_size_msat,
736+
htlc_maximum_msat: node.policy.max_htlc_size_msat,
737+
fee_base_msat: node.policy.base_fee as u32,
738+
fee_proportional_millionths: node.policy.fee_rate_prop as u32,
739+
excess_data: Vec::new(),
740+
};
741+
graph.update_channel_unsigned(&update)?;
742+
}
743+
}
744+
745+
Ok(graph)
746+
}
747+
663748
#[async_trait]
664749
impl SimNetwork for SimGraph {
665750
/// dispatch_payment asynchronously propagates a payment through the simulated network, returning a tracking

0 commit comments

Comments
 (0)