@@ -3,23 +3,24 @@ use crate::{
3
3
} ;
4
4
use async_trait:: async_trait;
5
5
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 ,
10
17
} ;
11
- use bitcoin:: { ScriptBuf , TxOut } ;
12
- use lightning:: ln:: features:: NodeFeatures ;
13
- use lightning:: ln:: msgs:: LightningError as LdkError ;
14
18
use lightning:: ln:: { PaymentHash , PaymentPreimage } ;
15
- use lightning:: routing:: gossip:: NetworkGraph ;
19
+ use lightning:: routing:: gossip:: { NetworkGraph , NodeId } ;
16
20
use lightning:: routing:: router:: { find_route, Path , PaymentParameters , Route , RouteParameters } ;
17
21
use lightning:: routing:: scoring:: ProbabilisticScorer ;
18
22
use lightning:: routing:: utxo:: { UtxoLookup , UtxoResult } ;
19
23
use lightning:: util:: logger:: { Level , Logger , Record } ;
20
- use std:: collections:: hash_map:: Entry ;
21
- use std:: collections:: HashMap ;
22
- use std:: sync:: Arc ;
23
24
use thiserror:: Error ;
24
25
use tokio:: select;
25
26
use tokio:: sync:: oneshot:: { channel, Receiver , Sender } ;
@@ -660,6 +661,90 @@ impl SimGraph {
660
661
}
661
662
}
662
663
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
+
663
748
#[ async_trait]
664
749
impl SimNetwork for SimGraph {
665
750
/// dispatch_payment asynchronously propagates a payment through the simulated network, returning a tracking
0 commit comments