Skip to content

Commit edb88e6

Browse files
authored
Merge pull request #190 from carlaKC/189-paymentdelay
sim-lib: only use start delay if explicitly specified
2 parents f5c8430 + d53c5d7 commit edb88e6

File tree

3 files changed

+119
-29
lines changed

3 files changed

+119
-29
lines changed

sim-lib/src/defined_activity.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use tokio::time::Duration;
88
#[derive(Clone)]
99
pub struct DefinedPaymentActivity {
1010
destination: NodeInfo,
11-
start: Duration,
11+
start: Option<Duration>,
1212
count: Option<u64>,
1313
wait: ValueOrRange<u16>,
1414
amount: ValueOrRange<u64>,
@@ -17,7 +17,7 @@ pub struct DefinedPaymentActivity {
1717
impl DefinedPaymentActivity {
1818
pub fn new(
1919
destination: NodeInfo,
20-
start: Duration,
20+
start: Option<Duration>,
2121
count: Option<u64>,
2222
wait: ValueOrRange<u16>,
2323
amount: ValueOrRange<u64>,
@@ -52,7 +52,7 @@ impl DestinationGenerator for DefinedPaymentActivity {
5252
}
5353

5454
impl PaymentGenerator for DefinedPaymentActivity {
55-
fn payment_start(&self) -> Duration {
55+
fn payment_start(&self) -> Option<Duration> {
5656
self.start
5757
}
5858

@@ -81,7 +81,6 @@ impl PaymentGenerator for DefinedPaymentActivity {
8181
#[cfg(test)]
8282
mod tests {
8383
use super::DefinedPaymentActivity;
84-
use super::*;
8584
use crate::test_utils::{create_nodes, get_random_keypair};
8685
use crate::{DestinationGenerator, PaymentGenerationError, PaymentGenerator};
8786

@@ -95,7 +94,7 @@ mod tests {
9594

9695
let generator = DefinedPaymentActivity::new(
9796
node.clone(),
98-
Duration::from_secs(0),
97+
None,
9998
None,
10099
crate::ValueOrRange::Value(60),
101100
crate::ValueOrRange::Value(payment_amt),

sim-lib/src/lib.rs

Lines changed: 113 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,7 @@ pub struct ActivityParser {
185185
#[serde(with = "serializers::serde_node_id")]
186186
pub destination: NodeId,
187187
/// The time in the simulation to start the payment.
188-
#[serde(default)]
189-
pub start_secs: u16,
188+
pub start_secs: Option<u16>,
190189
/// The number of payments to send over the course of the simulation.
191190
#[serde(default)]
192191
pub count: Option<u64>,
@@ -207,7 +206,7 @@ pub struct ActivityDefinition {
207206
/// The destination of the payment.
208207
pub destination: NodeInfo,
209208
/// The time in the simulation to start the payment.
210-
pub start_secs: u16,
209+
pub start_secs: Option<u16>,
211210
/// The number of payments to send over the course of the simulation.
212211
pub count: Option<u64>,
213212
/// The interval of the event, as in every how many seconds the payment is performed.
@@ -328,7 +327,7 @@ pub struct PaymentGenerationError(String);
328327

329328
pub trait PaymentGenerator: Display + Send {
330329
/// Returns the time that the payments should start
331-
fn payment_start(&self) -> Duration;
330+
fn payment_start(&self) -> Option<Duration>;
332331

333332
/// Returns the number of payments that should be made
334333
fn payment_count(&self) -> Option<u64>;
@@ -819,7 +818,9 @@ impl Simulation {
819818
for description in self.activity.iter() {
820819
let activity_generator = DefinedPaymentActivity::new(
821820
description.destination.clone(),
822-
Duration::from_secs(description.start_secs.into()),
821+
description
822+
.start_secs
823+
.map(|start| Duration::from_secs(start.into())),
823824
description.count,
824825
description.interval_secs,
825826
description.amount_msat,
@@ -1087,22 +1088,7 @@ async fn produce_events<N: DestinationGenerator + ?Sized, A: PaymentGenerator +
10871088
}
10881089
}
10891090

1090-
let wait: Duration = if current_count == 0 {
1091-
let start = node_generator.payment_start();
1092-
if start != Duration::from_secs(0) {
1093-
log::debug!(
1094-
"Using a start delay. The first payment for {source} will be at {:?}.",
1095-
start
1096-
);
1097-
}
1098-
start
1099-
} else {
1100-
let wait = node_generator
1101-
.next_payment_wait()
1102-
.map_err(SimulationError::PaymentGenerationError)?;
1103-
log::debug!("Next payment for {source} in {:?}.", wait);
1104-
wait
1105-
};
1091+
let wait = get_payment_delay(current_count, &source, node_generator.as_ref())?;
11061092

11071093
select! {
11081094
biased;
@@ -1144,6 +1130,38 @@ async fn produce_events<N: DestinationGenerator + ?Sized, A: PaymentGenerator +
11441130
}
11451131
}
11461132

1133+
/// Gets the wait time for the next payment. If this is the first payment being generated, and a specific start delay
1134+
/// was set we return a once-off delay. Otherwise, the interval between payments is used.
1135+
fn get_payment_delay<A: PaymentGenerator + ?Sized>(
1136+
call_count: u64,
1137+
source: &NodeInfo,
1138+
node_generator: &A,
1139+
) -> Result<Duration, SimulationError> {
1140+
// Note: we can't check if let Some() && call_count (syntax not allowed) so we add an additional branch in here.
1141+
// The alternative is to call payment_start twice (which is _technically_ fine because it always returns the same
1142+
// value), but this approach only costs us a few extra lines so we go for the more verbose approach so that we
1143+
// don't have to make any assumptions about the underlying operation of payment_start.
1144+
if call_count != 0 {
1145+
let wait = node_generator
1146+
.next_payment_wait()
1147+
.map_err(SimulationError::PaymentGenerationError)?;
1148+
log::debug!("Next payment for {source} in {:?}.", wait);
1149+
Ok(wait)
1150+
} else if let Some(start) = node_generator.payment_start() {
1151+
log::debug!(
1152+
"First payment for {source} will be after a start delay of {:?}.",
1153+
start
1154+
);
1155+
Ok(start)
1156+
} else {
1157+
let wait = node_generator
1158+
.next_payment_wait()
1159+
.map_err(SimulationError::PaymentGenerationError)?;
1160+
log::debug!("First payment for {source} in {:?}.", wait);
1161+
Ok(wait)
1162+
}
1163+
}
1164+
11471165
async fn consume_simulation_results(
11481166
logger: Arc<Mutex<PaymentResultLogger>>,
11491167
mut receiver: Receiver<(Payment, PaymentResult)>,
@@ -1380,7 +1398,10 @@ async fn track_payment_result(
13801398

13811399
#[cfg(test)]
13821400
mod tests {
1383-
use crate::MutRng;
1401+
use crate::{get_payment_delay, test_utils, MutRng, PaymentGenerationError, PaymentGenerator};
1402+
use mockall::mock;
1403+
use std::fmt;
1404+
use std::time::Duration;
13841405

13851406
#[test]
13861407
fn create_seeded_mut_rng() {
@@ -1407,4 +1428,74 @@ mod tests {
14071428

14081429
assert_ne!(rng_1.next_u64(), rng_2.next_u64())
14091430
}
1431+
1432+
mock! {
1433+
pub Generator {}
1434+
1435+
impl fmt::Display for Generator {
1436+
fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result;
1437+
}
1438+
1439+
impl PaymentGenerator for Generator {
1440+
fn payment_start(&self) -> Option<Duration>;
1441+
fn payment_count(&self) -> Option<u64>;
1442+
fn next_payment_wait(&self) -> Result<Duration, PaymentGenerationError>;
1443+
fn payment_amount(&self, destination_capacity: Option<u64>) -> Result<u64, PaymentGenerationError>;
1444+
}
1445+
}
1446+
1447+
#[test]
1448+
fn test_no_payment_delay() {
1449+
let node = test_utils::create_nodes(1, 100_000)
1450+
.first()
1451+
.unwrap()
1452+
.0
1453+
.clone();
1454+
1455+
// Setup mocked generator to have no start time and send payments every 5 seconds.
1456+
let mut mock_generator = MockGenerator::new();
1457+
mock_generator.expect_payment_start().return_once(|| None);
1458+
let payment_interval = Duration::from_secs(5);
1459+
mock_generator
1460+
.expect_next_payment_wait()
1461+
.returning(move || Ok(payment_interval));
1462+
1463+
assert_eq!(
1464+
get_payment_delay(0, &node, &mock_generator).unwrap(),
1465+
payment_interval
1466+
);
1467+
assert_eq!(
1468+
get_payment_delay(1, &node, &mock_generator).unwrap(),
1469+
payment_interval
1470+
);
1471+
}
1472+
1473+
#[test]
1474+
fn test_payment_delay() {
1475+
let node = test_utils::create_nodes(1, 100_000)
1476+
.first()
1477+
.unwrap()
1478+
.0
1479+
.clone();
1480+
1481+
// Setup mocked generator to have a start delay and payment interval with different values.
1482+
let mut mock_generator = MockGenerator::new();
1483+
let start_delay = Duration::from_secs(10);
1484+
mock_generator
1485+
.expect_payment_start()
1486+
.return_once(move || Some(start_delay));
1487+
let payment_interval = Duration::from_secs(5);
1488+
mock_generator
1489+
.expect_next_payment_wait()
1490+
.returning(move || Ok(payment_interval));
1491+
1492+
assert_eq!(
1493+
get_payment_delay(0, &node, &mock_generator).unwrap(),
1494+
start_delay
1495+
);
1496+
assert_eq!(
1497+
get_payment_delay(1, &node, &mock_generator).unwrap(),
1498+
payment_interval
1499+
);
1500+
}
14101501
}

sim-lib/src/random_activity.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,8 @@ fn events_per_month(source_capacity_msat: u64, multiplier: f64, expected_payment
214214

215215
impl PaymentGenerator for RandomPaymentActivity {
216216
/// Returns the time that the payments should start. This will always be 0 for the RandomPaymentActivity type.
217-
fn payment_start(&self) -> Duration {
218-
Duration::from_secs(0)
217+
fn payment_start(&self) -> Option<Duration> {
218+
None
219219
}
220220

221221
/// Returns the number of payments that should be made. This will always be None for the RandomPaymentActivity type.

0 commit comments

Comments
 (0)