@@ -25,8 +25,6 @@ use crate::types::{Decision, ProposalCommitment, Round, ValidatorId};
2525use crate :: votes_threshold:: QuorumType ;
2626
2727const HEIGHT_0 : BlockNumber = BlockNumber ( 0 ) ;
28- const TOTAL_NODES : usize = 100 ;
29- const THRESHOLD : usize = ( 2 * TOTAL_NODES / 3 ) + 1 ;
3028const NODE_0_LEADER_PROBABILITY : f64 = 0.1 ;
3129const NODE_UNDER_TEST : usize = 0 ;
3230
@@ -128,12 +126,16 @@ struct DiscreteEventSimulation {
128126 rng : StdRng ,
129127 /// The seed used to initialize the simulation.
130128 seed : u64 ,
129+ /// Total number of nodes in the network.
130+ total_nodes : usize ,
131+ /// Number of honest nodes (the rest are faulty).
132+ honest_nodes : usize ,
133+ /// Quorum threshold for reaching consensus (2/3 + 1 of total nodes).
134+ quorum_threshold : usize ,
131135 /// The single height consensus instance.
132136 shc : SingleHeightConsensus ,
133137 /// All validators in the network.
134138 validators : Vec < ValidatorId > ,
135- /// Number of honest nodes (the rest are faulty).
136- honest_nodes : usize ,
137139 /// Priority queue of pending events that have yet to be processed (min-heap by tick).
138140 pending_events : BinaryHeap < TimedEvent > ,
139141 /// Current simulation tick.
@@ -178,12 +180,16 @@ impl DiscreteEventSimulation {
178180 TimeoutsConfig :: default ( ) ,
179181 ) ;
180182
183+ let quorum_threshold = ( 2 * total_nodes / 3 ) + 1 ;
184+
181185 Self {
182186 rng,
183187 seed,
188+ total_nodes,
189+ honest_nodes,
190+ quorum_threshold,
184191 shc,
185192 validators,
186- honest_nodes,
187193 pending_events : BinaryHeap :: new ( ) ,
188194 current_tick : 0 ,
189195 processed_history : Vec :: new ( ) ,
@@ -219,17 +225,17 @@ impl DiscreteEventSimulation {
219225 /// Other nodes share the remaining probability (1 - NODE_0_LEADER_PROBABILITY) uniformly.
220226 /// The selection is deterministic per round - the same round will always return the same
221227 /// leader index.
222- fn get_leader_index ( seed : u64 , round : Round ) -> usize {
228+ fn get_leader_index ( & self , round : Round ) -> usize {
223229 let round_u64 = u64:: from ( round) ;
224- let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
230+ let round_seed = self . seed . wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
225231 let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
226232
227233 let random_value: f64 = round_rng. gen ( ) ;
228234
229235 if random_value < NODE_0_LEADER_PROBABILITY {
230236 NODE_UNDER_TEST
231237 } else {
232- round_rng. gen_range ( 1 ..TOTAL_NODES )
238+ round_rng. gen_range ( 1 ..self . total_nodes )
233239 }
234240 }
235241
@@ -292,7 +298,7 @@ impl DiscreteEventSimulation {
292298 fn pre_generate_all_rounds ( & mut self ) {
293299 for round_idx in 0 ..self . num_rounds {
294300 let round = Round :: from ( u32:: try_from ( round_idx) . unwrap ( ) ) ;
295- let leader_idx = Self :: get_leader_index ( self . seed , round) ;
301+ let leader_idx = self . get_leader_index ( round) ;
296302 let leader_id = self . validators [ leader_idx] ;
297303 // Track rounds where NODE_0 is the proposer.
298304 // We will schedule peer votes for these rounds after the build finish event.
@@ -415,7 +421,7 @@ impl DiscreteEventSimulation {
415421 }
416422 FaultType :: NonValidator => {
417423 // Send votes with a voter ID that is outside the validator set
418- let non_validator_id = ValidatorId :: from ( u64:: try_from ( TOTAL_NODES ) . unwrap ( ) ) ;
424+ let non_validator_id = ValidatorId :: from ( u64:: try_from ( self . total_nodes ) . unwrap ( ) ) ;
419425 self . schedule_prevote_and_precommit (
420426 non_validator_id,
421427 round,
@@ -468,8 +474,17 @@ impl DiscreteEventSimulation {
468474
469475 let validators = self . validators . clone ( ) ;
470476 let seed = self . seed ;
477+ let total_nodes = self . total_nodes ;
471478 let leader_fn = move |r : Round | {
472- let idx = Self :: get_leader_index ( seed, r) ;
479+ let round_u64 = u64:: from ( r) ;
480+ let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
481+ let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
482+ let random_value: f64 = round_rng. gen ( ) ;
483+ let idx = if random_value < NODE_0_LEADER_PROBABILITY {
484+ NODE_UNDER_TEST
485+ } else {
486+ round_rng. gen_range ( 1 ..total_nodes)
487+ } ;
473488 validators[ idx]
474489 } ;
475490
@@ -613,7 +628,7 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
613628 } ) ;
614629 let total_precommits = peer_precommits + self_vote;
615630
616- if total_precommits >= THRESHOLD {
631+ if total_precommits >= sim . quorum_threshold {
617632 Some ( ( * r, * commitment, precommits. clone ( ) ) )
618633 } else {
619634 None
@@ -667,10 +682,10 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
667682
668683 // Verify quorum threshold is met
669684 assert ! (
670- actual. precommits. len( ) >= THRESHOLD ,
685+ actual. precommits. len( ) >= sim . quorum_threshold ,
671686 "Insufficient precommits in decision: {}/{}. Decision: {:?}, History: {:?}" ,
672687 actual. precommits. len( ) ,
673- THRESHOLD ,
688+ sim . quorum_threshold ,
674689 actual,
675690 sim. processed_history
676691 ) ;
@@ -696,13 +711,14 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
696711fn test_consensus_simulation ( keep_ratio : f64 , honest_nodes : usize ) {
697712 let seed = rand:: thread_rng ( ) . gen ( ) ;
698713 let num_rounds = 5 ; // Number of rounds to pre-generate
714+ let total_nodes = 100 ;
699715 println ! (
700- "Running consensus simulation with total nodes {TOTAL_NODES }, {num_rounds} rounds, keep \
716+ "Running consensus simulation with total nodes {total_nodes }, {num_rounds} rounds, keep \
701717 ratio {keep_ratio}, honest nodes {honest_nodes} and seed: {seed}"
702718 ) ;
703719
704720 let mut sim =
705- DiscreteEventSimulation :: new ( TOTAL_NODES , honest_nodes, seed, num_rounds, keep_ratio) ;
721+ DiscreteEventSimulation :: new ( total_nodes , honest_nodes, seed, num_rounds, keep_ratio) ;
706722
707723 let deadline_ticks = u64:: try_from ( num_rounds) . unwrap ( ) * ROUND_DURATION ;
708724 let result = sim. run ( deadline_ticks) ;
0 commit comments