Skip to content

Commit 3145c74

Browse files
authored
Linear leios tests (#533)
* sim-rs: implement mock clock * sim-rs: support mocking lottery runs * sim-rs: add a simple tx propagation test * sim-rs: fix bug with conflicting TXs * sim-rs: test vote generation
1 parent eff4824 commit 3145c74

File tree

11 files changed

+776
-25
lines changed

11 files changed

+776
-25
lines changed

sim-rs/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Linear Leios
6+
- Add some protocol-level tests
7+
- Fix bug; transactions with conflicts referenced by EBs did not propagate far enough
8+
39
## v1.3.0
410

511
### Linear Leios

sim-rs/Cargo.lock

Lines changed: 29 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sim-rs/sim-core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ rust-version = "1.88"
77
[dependencies]
88
anyhow = "1"
99
async-stream = "0.3"
10+
dashmap = "6"
1011
futures = "0.3"
1112
netsim-async = { git = "https://github.com/input-output-hk/ce-netsim.git", rev = "9d1e26c" }
1213
num-traits = "0.2"
@@ -20,4 +21,5 @@ tokio-util = "0.7"
2021
tracing = "0.1"
2122

2223
[dev-dependencies]
24+
serde_yaml = "0.9"
2325
tokio = { version = "1", features = ["macros", "rt"] }

sim-rs/sim-core/src/clock.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ use std::{
1010
pub use coordinator::ClockCoordinator;
1111
use coordinator::ClockEvent;
1212
use futures::FutureExt;
13+
pub use mock::MockClockCoordinator;
1314
use timestamp::AtomicTimestamp;
1415
pub use timestamp::Timestamp;
1516
use tokio::sync::{mpsc, oneshot};
1617

1718
mod coordinator;
19+
mod mock;
1820
mod timestamp;
1921

2022
// wrapper struct which holds a SimulationEvent,

sim-rs/sim-core/src/clock/mock.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
use std::{
2+
collections::HashMap,
3+
sync::{Arc, atomic::AtomicUsize},
4+
time::Duration,
5+
};
6+
7+
use tokio::sync::{mpsc, oneshot};
8+
9+
use crate::clock::{
10+
Clock, TaskInitiator, Timestamp, coordinator::ClockEvent, timestamp::AtomicTimestamp,
11+
};
12+
13+
pub struct MockClockCoordinator {
14+
time: Arc<AtomicTimestamp>,
15+
tx: mpsc::UnboundedSender<ClockEvent>,
16+
rx: mpsc::UnboundedReceiver<ClockEvent>,
17+
waiter_count: Arc<AtomicUsize>,
18+
tasks: Arc<AtomicUsize>,
19+
waiters: HashMap<usize, Waiter>,
20+
}
21+
22+
impl Default for MockClockCoordinator {
23+
fn default() -> Self {
24+
Self::new()
25+
}
26+
}
27+
28+
impl MockClockCoordinator {
29+
pub fn new() -> Self {
30+
let time = Arc::new(AtomicTimestamp::new(Timestamp::zero()));
31+
let (tx, rx) = mpsc::unbounded_channel();
32+
let waiter_count = Arc::new(AtomicUsize::new(0));
33+
let tasks = Arc::new(AtomicUsize::new(0));
34+
Self {
35+
time,
36+
tx,
37+
rx,
38+
waiter_count,
39+
tasks,
40+
waiters: HashMap::new(),
41+
}
42+
}
43+
44+
pub fn clock(&self) -> Clock {
45+
Clock::new(
46+
Duration::from_nanos(1),
47+
self.time.clone(),
48+
self.waiter_count.clone(),
49+
TaskInitiator::new(self.tasks.clone()),
50+
self.tx.clone(),
51+
)
52+
}
53+
54+
pub fn now(&self) -> Timestamp {
55+
self.time.load(std::sync::atomic::Ordering::Acquire)
56+
}
57+
58+
pub fn advance_time(&mut self, until: Timestamp) {
59+
while let Ok(event) = self.rx.try_recv() {
60+
match event {
61+
ClockEvent::Wait { actor, until, done } => {
62+
if self.waiters.insert(actor, Waiter { until, done }).is_some() {
63+
panic!("waiter {actor} waited twice");
64+
}
65+
}
66+
ClockEvent::CancelWait { actor } => {
67+
if self.waiters.remove(&actor).is_none() {
68+
panic!("waiter {actor} cancelled a wait twice");
69+
}
70+
}
71+
ClockEvent::FinishTask => {
72+
if self.tasks.fetch_sub(1, std::sync::atomic::Ordering::AcqRel) == 0 {
73+
panic!("cancelled too many tasks");
74+
}
75+
}
76+
}
77+
}
78+
assert_eq!(
79+
self.waiters.len(),
80+
self.waiter_count.load(std::sync::atomic::Ordering::Acquire),
81+
"not every worker is waiting for time to pass"
82+
);
83+
84+
self.time.store(until, std::sync::atomic::Ordering::Release);
85+
self.waiters = std::mem::take(&mut self.waiters)
86+
.into_iter()
87+
.filter_map(|(actor, waiter)| {
88+
if let Some(t) = &waiter.until {
89+
if *t < until {
90+
panic!("advanced time too far (waited for {until:?}, next event at {t:?})");
91+
}
92+
if *t == until {
93+
let _ = waiter.done.send(());
94+
return None;
95+
}
96+
}
97+
Some((actor, waiter))
98+
})
99+
.collect();
100+
}
101+
}
102+
103+
struct Waiter {
104+
until: Option<Timestamp>,
105+
done: oneshot::Sender<()>,
106+
}

sim-rs/sim-core/src/model.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ impl Block {
8484
}
8585
}
8686

87-
#[derive(Clone, Debug)]
87+
#[derive(Clone, Debug, PartialEq, Eq)]
8888
pub struct LinearRankingBlockHeader {
8989
pub id: BlockId,
9090
pub vrf: u64,
@@ -93,7 +93,7 @@ pub struct LinearRankingBlockHeader {
9393
pub eb_announcement: Option<EndorserBlockId>,
9494
}
9595

96-
#[derive(Clone, Debug)]
96+
#[derive(Clone, Debug, PartialEq, Eq)]
9797
pub struct LinearRankingBlock {
9898
pub header: LinearRankingBlockHeader,
9999
pub transactions: Vec<Arc<Transaction>>,
@@ -227,7 +227,7 @@ impl StracciatellaEndorserBlock {
227227
}
228228
}
229229

230-
#[derive(Debug)]
230+
#[derive(Debug, Clone, PartialEq, Eq)]
231231
pub struct LinearEndorserBlock {
232232
pub slot: u64,
233233
pub producer: NodeId,
@@ -293,7 +293,7 @@ pub enum TransactionLostReason {
293293
EBExpired,
294294
}
295295

296-
#[derive(Clone, Debug, Serialize)]
296+
#[derive(Clone, Debug, Serialize, PartialEq, Eq)]
297297
pub struct Endorsement<Node: Display = NodeId> {
298298
pub eb: EndorserBlockId<Node>,
299299
pub size_bytes: u64,

sim-rs/sim-core/src/sim.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ mod linear_leios;
2828
mod lottery;
2929
mod slot;
3030
mod stracciatella;
31+
#[cfg(test)]
32+
mod tests;
3133
mod tx;
3234

3335
enum NetworkWrapper {
@@ -304,6 +306,13 @@ impl<N: NodeImpl> Default for EventResult<N> {
304306
}
305307

306308
impl<N: NodeImpl> EventResult<N> {
309+
#[cfg(test)]
310+
pub fn merge(&mut self, mut other: EventResult<N>) {
311+
self.messages.append(&mut other.messages);
312+
self.tasks.append(&mut other.tasks);
313+
self.timed_events.append(&mut other.timed_events);
314+
}
315+
307316
pub fn send_to(&mut self, to: NodeId, msg: N::Message) {
308317
self.messages.push((to, msg));
309318
}

0 commit comments

Comments
 (0)