@@ -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 DEADLINE_TICKS : u64 = 200 ;
3129const NODE_0_LEADER_PROBABILITY : f64 = 0.1 ;
3230const NODE_UNDER_TEST : usize = 0 ;
@@ -111,12 +109,16 @@ struct DiscreteEventSimulation {
111109 rng : StdRng ,
112110 /// The seed used to initialize the simulation.
113111 seed : u64 ,
112+ /// Total number of nodes in the network.
113+ total_nodes : usize ,
114+ /// Number of honest nodes (the rest are faulty).
115+ honest_nodes : usize ,
116+ /// Threshold for reaching consensus (2/3 + 1 of total nodes).
117+ threshold : usize ,
114118 /// The single height consensus instance.
115119 shc : SingleHeightConsensus ,
116120 /// All validators in the network.
117121 validators : Vec < ValidatorId > ,
118- /// Number of honest nodes (the rest are faulty).
119- honest_nodes : usize ,
120122 /// The current maximum round being processed.
121123 current_max_round : Round ,
122124 /// Priority queue of pending events that have yet to be processed (min-heap by tick).
@@ -153,12 +155,16 @@ impl DiscreteEventSimulation {
153155 TimeoutsConfig :: default ( ) ,
154156 ) ;
155157
158+ let threshold = ( 2 * total_nodes / 3 ) + 1 ;
159+
156160 Self {
157161 rng,
158162 seed,
163+ total_nodes,
164+ honest_nodes,
165+ threshold,
159166 shc,
160167 validators,
161- honest_nodes,
162168 current_max_round : 0 ,
163169 pending_events : BinaryHeap :: new ( ) ,
164170 current_tick : 0 ,
@@ -193,17 +199,17 @@ impl DiscreteEventSimulation {
193199 /// Other nodes share the remaining probability (1 - NODE_0_LEADER_PROBABILITY) uniformly.
194200 /// The selection is deterministic per round - the same round will always return the same
195201 /// leader index.
196- fn get_leader_index ( seed : u64 , round : Round ) -> usize {
202+ fn get_leader_index ( & self , round : Round ) -> usize {
197203 let round_u64 = u64:: from ( round) ;
198- let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
204+ let round_seed = self . seed . wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
199205 let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
200206
201207 let random_value: f64 = round_rng. gen ( ) ;
202208
203209 if random_value < NODE_0_LEADER_PROBABILITY {
204210 NODE_UNDER_TEST
205211 } else {
206- round_rng. gen_range ( 1 ..TOTAL_NODES )
212+ round_rng. gen_range ( 1 ..self . total_nodes )
207213 }
208214 }
209215
@@ -261,7 +267,7 @@ impl DiscreteEventSimulation {
261267 ///
262268 /// Honest nodes behave correctly, while faulty nodes exhibit various fault behaviors.
263269 fn generate_round_traffic ( & mut self , round : Round ) {
264- let leader_idx = Self :: get_leader_index ( self . seed , round) ;
270+ let leader_idx = self . get_leader_index ( round) ;
265271 let leader_id = self . validators [ leader_idx] ;
266272 let proposal_commitment = Some ( proposal_commitment_for_round ( round, false ) ) ;
267273
@@ -328,7 +334,7 @@ impl DiscreteEventSimulation {
328334 }
329335 FaultType :: NonValidator => {
330336 // Send votes with a voter ID that is outside the validator set
331- let non_validator_id = ValidatorId :: from ( u64:: try_from ( TOTAL_NODES ) . unwrap ( ) ) ;
337+ let non_validator_id = ValidatorId :: from ( u64:: try_from ( self . total_nodes ) . unwrap ( ) ) ;
332338 self . schedule_prevote_and_precommit ( non_validator_id, round, proposal_commitment) ;
333339 }
334340 }
@@ -380,8 +386,17 @@ impl DiscreteEventSimulation {
380386 fn run ( & mut self , deadline_ticks : u64 ) -> Option < Decision > {
381387 let validators = self . validators . clone ( ) ;
382388 let seed = self . seed ;
389+ let total_nodes = self . total_nodes ;
383390 let leader_fn = move |r : Round | {
384- let idx = Self :: get_leader_index ( seed, r) ;
391+ let round_u64 = u64:: from ( r) ;
392+ let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
393+ let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
394+ let random_value: f64 = round_rng. gen ( ) ;
395+ let idx = if random_value < NODE_0_LEADER_PROBABILITY {
396+ NODE_UNDER_TEST
397+ } else {
398+ round_rng. gen_range ( 1 ..total_nodes)
399+ } ;
385400 validators[ idx]
386401 } ;
387402
@@ -512,7 +527,7 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
512527 } ) ;
513528 let total_precommits = peer_precommits + self_vote;
514529
515- if total_precommits >= THRESHOLD {
530+ if total_precommits >= sim . threshold {
516531 Some ( ( * r, * commitment, precommits. clone ( ) ) )
517532 } else {
518533 None
@@ -558,10 +573,10 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
558573
559574 // Verify quorum threshold is met
560575 assert ! (
561- actual. precommits. len( ) >= THRESHOLD ,
576+ actual. precommits. len( ) >= sim . threshold ,
562577 "Insufficient precommits in decision: {}/{}. Decision: {:?}, History: {:?}" ,
563578 actual. precommits. len( ) ,
564- THRESHOLD ,
579+ sim . threshold ,
565580 actual,
566581 sim. processed_history
567582 ) ;
@@ -586,12 +601,13 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
586601#[ test_case( 0.9 , 80 ; "keep_90%_80_honest" ) ]
587602fn test_consensus_simulation ( keep_ratio : f64 , honest_nodes : usize ) {
588603 let seed = rand:: thread_rng ( ) . gen ( ) ;
604+ let total_nodes = 100 ;
589605 println ! (
590- "Running consensus simulation with total nodes {TOTAL_NODES }, keep ratio {keep_ratio}, \
606+ "Running consensus simulation with total nodes {total_nodes }, keep ratio {keep_ratio}, \
591607 honest nodes {honest_nodes} and seed: {seed}"
592608 ) ;
593609
594- let mut sim = DiscreteEventSimulation :: new ( TOTAL_NODES , honest_nodes, seed, keep_ratio) ;
610+ let mut sim = DiscreteEventSimulation :: new ( total_nodes , honest_nodes, seed, keep_ratio) ;
595611
596612 sim. generate_round_traffic ( 0 ) ;
597613
0 commit comments