Skip to content

Commit 7fc0e7b

Browse files
committed
sim-rs: support mocking lottery runs
1 parent 37dd4af commit 7fc0e7b

File tree

4 files changed

+103
-19
lines changed

4 files changed

+103
-19
lines changed

sim-rs/Cargo.lock

Lines changed: 28 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: 1 addition & 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"

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

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::{
2828
sim::{
2929
MiniProtocol, NodeImpl, SimCpuTask, SimMessage,
3030
linear_leios::attackers::{EBWithholdingEvent, EBWithholdingSender},
31-
lottery,
31+
lottery::{LotteryConfig, LotteryKind, MockLotteryResults, vrf_probabilities},
3232
},
3333
};
3434

@@ -306,7 +306,7 @@ pub struct LinearLeiosNode {
306306
tracker: EventTracker,
307307
rng: ChaChaRng,
308308
clock: Clock,
309-
stake: u64,
309+
lottery: LotteryConfig,
310310
consumers: Vec<NodeId>,
311311
txs: HashMap<TransactionId, TransactionView>,
312312
ledger_states: BTreeMap<BlockId, Arc<LedgerState>>,
@@ -333,14 +333,19 @@ impl NodeImpl for LinearLeiosNode {
333333
rng: ChaChaRng,
334334
clock: Clock,
335335
) -> Self {
336+
let lottery = LotteryConfig::Random {
337+
stake: config.stake,
338+
total_stake: sim_config.total_stake,
339+
};
340+
336341
Self {
337342
id: config.id,
338343
sim_config,
339344
queued: EventResult::default(),
340345
tracker,
341346
rng,
342347
clock,
343-
stake: config.stake,
348+
lottery,
344349
consumers: config.consumers.clone(),
345350
txs: HashMap::new(),
346351
ledger_states: BTreeMap::new(),
@@ -512,7 +517,10 @@ impl LinearLeiosNode {
512517
// Ranking block propagation
513518
impl LinearLeiosNode {
514519
fn try_generate_rb(&mut self, slot: u64) {
515-
let Some(vrf) = self.run_vrf(self.sim_config.block_generation_probability) else {
520+
let Some(vrf) = self.run_vrf(
521+
LotteryKind::GenerateRB,
522+
self.sim_config.block_generation_probability,
523+
) else {
516524
return;
517525
};
518526

@@ -1204,8 +1212,8 @@ impl LinearLeiosNode {
12041212
}
12051213

12061214
fn try_vote_for_endorser_block(&mut self, eb: &Arc<EndorserBlock>, seen: Timestamp) -> bool {
1207-
let vrf_wins = lottery::vrf_probabilities(self.sim_config.vote_probability)
1208-
.filter_map(|f| self.run_vrf(f))
1215+
let vrf_wins = vrf_probabilities(self.sim_config.vote_probability)
1216+
.filter_map(|f| self.run_vrf(LotteryKind::GenerateVote, f))
12091217
.count();
12101218
if vrf_wins == 0 {
12111219
return false;
@@ -1487,18 +1495,12 @@ impl LinearLeiosNode {
14871495

14881496
// Common utilities
14891497
impl LinearLeiosNode {
1498+
#[allow(unused)]
1499+
pub fn mock_lottery(&mut self, results: Arc<MockLotteryResults>) {
1500+
self.lottery = LotteryConfig::Mock { results };
1501+
}
14901502
// Simulates the output of a VRF using this node's stake (if any).
1491-
fn run_vrf(&mut self, success_rate: f64) -> Option<u64> {
1492-
let target_vrf_stake = lottery::compute_target_vrf_stake(
1493-
self.stake,
1494-
self.sim_config.total_stake,
1495-
success_rate,
1496-
);
1497-
let result = self.rng.random_range(0..self.sim_config.total_stake);
1498-
if result < target_vrf_stake {
1499-
Some(result)
1500-
} else {
1501-
None
1502-
}
1503+
fn run_vrf(&mut self, kind: LotteryKind, success_rate: f64) -> Option<u64> {
1504+
self.lottery.run(kind, success_rate, &mut self.rng)
15031505
}
15041506
}

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

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use std::{collections::VecDeque, sync::Arc};
2+
3+
use dashmap::DashMap;
4+
use rand::Rng;
5+
use rand_chacha::ChaChaRng;
6+
17
pub fn compute_target_vrf_stake(stake: u64, total_stake: u64, success_rate: f64) -> u64 {
28
let ratio = stake as f64 / total_stake as f64;
39
(total_stake as f64 * ratio * success_rate) as u64
@@ -7,3 +13,51 @@ pub fn vrf_probabilities(probability: f64) -> impl Iterator<Item = f64> {
713
let final_success_rate = Some(probability.fract()).filter(|f| *f > 0.0);
814
std::iter::repeat_n(1.0, probability.trunc() as usize).chain(final_success_rate)
915
}
16+
17+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
18+
pub enum LotteryKind {
19+
GenerateRB,
20+
GenerateVote,
21+
}
22+
23+
#[derive(Default)]
24+
pub struct MockLotteryResults {
25+
results: DashMap<LotteryKind, VecDeque<u64>>,
26+
}
27+
impl MockLotteryResults {
28+
pub fn run(&self, kind: LotteryKind) -> Option<u64> {
29+
self.results.entry(kind).or_default().pop_front()
30+
}
31+
#[allow(unused)]
32+
pub fn configure_win(&self, kind: LotteryKind, result: u64) {
33+
self.results.entry(kind).or_default().push_back(result);
34+
}
35+
}
36+
37+
pub enum LotteryConfig {
38+
Random {
39+
stake: u64,
40+
total_stake: u64,
41+
},
42+
#[allow(unused)]
43+
Mock {
44+
results: Arc<MockLotteryResults>,
45+
},
46+
}
47+
48+
impl LotteryConfig {
49+
pub fn run(&self, kind: LotteryKind, success_rate: f64, rng: &mut ChaChaRng) -> Option<u64> {
50+
match self {
51+
Self::Random { stake, total_stake } => {
52+
let target_vrf_stake = compute_target_vrf_stake(*stake, *total_stake, success_rate);
53+
let result = rng.random_range(0..*total_stake);
54+
if result < target_vrf_stake {
55+
Some(result)
56+
} else {
57+
None
58+
}
59+
}
60+
Self::Mock { results } => results.run(kind),
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)