@@ -4,6 +4,7 @@ use bitcoin::Network;
4
4
use csv:: WriterBuilder ;
5
5
use lightning:: ln:: features:: NodeFeatures ;
6
6
use lightning:: ln:: PaymentHash ;
7
+ use rand:: Rng ;
7
8
use serde:: { Deserialize , Serialize } ;
8
9
use std:: collections:: HashSet ;
9
10
use std:: fmt:: { Display , Formatter } ;
@@ -86,6 +87,52 @@ pub struct SimParams {
86
87
pub activity : Vec < ActivityParser > ,
87
88
}
88
89
90
+ /// Either a value or a range parsed from the simulation file.
91
+ #[ derive( Debug , Clone , Serialize , Deserialize ) ]
92
+ #[ serde( untagged) ]
93
+ pub enum ValueOrRange < T > {
94
+ Value ( T ) ,
95
+ Range ( T , T ) ,
96
+ }
97
+
98
+ impl < T > ValueOrRange < T >
99
+ where
100
+ T : std:: cmp:: PartialOrd + rand_distr:: uniform:: SampleUniform + Copy ,
101
+ {
102
+ /// Get the enclosed value. If value is defined aa a range, sample from it uniformly at random.
103
+ pub fn value ( & self ) -> T {
104
+ match self {
105
+ ValueOrRange :: Value ( x) => * x,
106
+ ValueOrRange :: Range ( x, y) => {
107
+ let mut rng = rand:: thread_rng ( ) ;
108
+ rng. gen_range ( * x..* y)
109
+ }
110
+ }
111
+ }
112
+
113
+ /// Whether this is a range or not
114
+ pub fn is_range ( & self ) -> bool {
115
+ matches ! ( self , ValueOrRange :: Range ( ..) )
116
+ }
117
+ }
118
+
119
+ impl < T > Display for ValueOrRange < T >
120
+ where
121
+ T : Display ,
122
+ {
123
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> std:: fmt:: Result {
124
+ match self {
125
+ ValueOrRange :: Value ( x) => write ! ( f, "{x}" ) ,
126
+ ValueOrRange :: Range ( x, y) => write ! ( f, "({x}-{y})" ) ,
127
+ }
128
+ }
129
+ }
130
+
131
+ /// The payment amount in msat. Either a value or a range.
132
+ type Amount = ValueOrRange < u64 > ;
133
+ /// The interval of seconds between payments. Either a value or a range.
134
+ type Interval = ValueOrRange < u16 > ;
135
+
89
136
/// Data structure used to parse information from the simulation file. It allows source and destination to be
90
137
/// [NodeId], which enables the use of public keys and aliases in the simulation description.
91
138
#[ derive( Debug , Clone , Serialize , Deserialize ) ]
@@ -97,9 +144,10 @@ pub struct ActivityParser {
97
144
#[ serde( with = "serializers::serde_node_id" ) ]
98
145
pub destination : NodeId ,
99
146
// The interval of the event, as in every how many seconds the payment is performed.
100
- pub interval_secs : u16 ,
147
+ pub interval_secs : Interval ,
101
148
// The amount of m_sat to used in this payment.
102
- pub amount_msat : u64 ,
149
+ #[ serde( with = "serializers::serde_value_or_range" ) ]
150
+ pub amount_msat : Amount ,
103
151
}
104
152
105
153
/// Data structure used internally by the simulator. Both source and destination are represented as [PublicKey] here.
@@ -111,9 +159,9 @@ pub struct ActivityDefinition {
111
159
// The destination of the payment.
112
160
pub destination : NodeInfo ,
113
161
// The interval of the event, as in every how many seconds the payment is performed.
114
- pub interval_secs : u16 ,
162
+ pub interval_secs : Interval ,
115
163
// The amount of m_sat to used in this payment.
116
- pub amount_msat : u64 ,
164
+ pub amount_msat : Amount ,
117
165
}
118
166
119
167
#[ derive( Debug , Error ) ]
@@ -762,7 +810,8 @@ async fn produce_events(
762
810
shutdown : Trigger ,
763
811
listener : Listener ,
764
812
) {
765
- let interval = time:: Duration :: from_secs ( act. interval_secs as u64 ) ;
813
+ let mut interval = time:: Duration :: from_secs ( act. interval_secs . value ( ) as u64 ) ;
814
+ let mut amt = act. amount_msat . value ( ) ;
766
815
767
816
log:: debug!(
768
817
"Started producer for {} every {}s: {} -> {}." ,
@@ -776,8 +825,17 @@ async fn produce_events(
776
825
tokio:: select! {
777
826
biased;
778
827
_ = time:: sleep( interval) => {
779
- // Consumer was dropped
780
- if sender. send( SimulationEvent :: SendPayment ( act. destination. clone( ) , act. amount_msat) ) . await . is_err( ) {
828
+ // Resample if needed
829
+ if act. interval_secs. is_range( ) {
830
+ interval = time:: Duration :: from_secs( act. interval_secs. value( ) as u64 ) ;
831
+ log:: debug!( "Resampling interval. New value: {}" , interval. as_secs( ) ) ;
832
+ }
833
+ if act. amount_msat. is_range( ) {
834
+ amt = act. amount_msat. value( ) ;
835
+ log:: debug!( "Resampling payment amount. New value: {}" , amt) ;
836
+ }
837
+ if sender. send( SimulationEvent :: SendPayment ( act. destination. clone( ) , amt) ) . await . is_err( ) {
838
+ // Consumer was dropped
781
839
log:: debug!(
782
840
"Stopped producer for {}: {} -> {}. Consumer cannot be reached." ,
783
841
act. amount_msat,
0 commit comments