@@ -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
298304 // Determine time range for this round
@@ -434,7 +440,7 @@ impl DiscreteEventSimulation {
434440 }
435441 FaultType :: NonValidator => {
436442 // Send votes with a voter ID that is outside the validator set
437- let non_validator_id = ValidatorId :: from ( u64:: try_from ( TOTAL_NODES ) . unwrap ( ) ) ;
443+ let non_validator_id = ValidatorId :: from ( u64:: try_from ( self . total_nodes ) . unwrap ( ) ) ;
438444 self . schedule_prevote_and_precommit (
439445 non_validator_id,
440446 round,
@@ -510,8 +516,17 @@ impl DiscreteEventSimulation {
510516
511517 let validators = self . validators . clone ( ) ;
512518 let seed = self . seed ;
519+ let total_nodes = self . total_nodes ;
513520 let leader_fn = move |r : Round | {
514- let idx = Self :: get_leader_index ( seed, r) ;
521+ let round_u64 = u64:: from ( r) ;
522+ let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
523+ let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
524+ let random_value: f64 = round_rng. gen ( ) ;
525+ let idx = if random_value < NODE_0_LEADER_PROBABILITY {
526+ NODE_UNDER_TEST
527+ } else {
528+ round_rng. gen_range ( 1 ..total_nodes)
529+ } ;
515530 validators[ idx]
516531 } ;
517532
@@ -659,7 +674,7 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
659674 } ) ;
660675 let total_precommits = peer_precommits + self_vote;
661676
662- if total_precommits >= THRESHOLD {
677+ if total_precommits >= sim . quorum_threshold {
663678 Some ( ( * r, * commitment, precommits. clone ( ) ) )
664679 } else {
665680 None
@@ -713,10 +728,10 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
713728
714729 // Verify quorum threshold is met
715730 assert ! (
716- actual. precommits. len( ) >= THRESHOLD ,
731+ actual. precommits. len( ) >= sim . quorum_threshold ,
717732 "Insufficient precommits in decision: {}/{}. Decision: {:?}, History: {:?}" ,
718733 actual. precommits. len( ) ,
719- THRESHOLD ,
734+ sim . quorum_threshold ,
720735 actual,
721736 sim. processed_history
722737 ) ;
@@ -742,13 +757,14 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
742757fn test_consensus_simulation ( keep_ratio : f64 , honest_nodes : usize ) {
743758 let seed = rand:: thread_rng ( ) . gen ( ) ;
744759 let num_rounds = 5 ; // Number of rounds to pre-generate
760+ let total_nodes = 100 ;
745761 println ! (
746- "Running consensus simulation with total nodes {TOTAL_NODES }, {num_rounds} rounds, keep \
762+ "Running consensus simulation with total nodes {total_nodes }, {num_rounds} rounds, keep \
747763 ratio {keep_ratio}, honest nodes {honest_nodes} and seed: {seed}"
748764 ) ;
749765
750766 let mut sim =
751- DiscreteEventSimulation :: new ( TOTAL_NODES , honest_nodes, seed, num_rounds, keep_ratio) ;
767+ DiscreteEventSimulation :: new ( total_nodes , honest_nodes, seed, num_rounds, keep_ratio) ;
752768
753769 let deadline_ticks = u64:: try_from ( num_rounds) . unwrap ( ) * ROUND_DURATION ;
754770 let result = sim. run ( deadline_ticks) ;
0 commit comments