@@ -26,8 +26,6 @@ use crate::types::{Decision, ProposalCommitment, Round, ValidatorId};
2626use crate :: votes_threshold:: QuorumType ;
2727
2828const HEIGHT_0 : BlockNumber = BlockNumber ( 0 ) ;
29- const TOTAL_NODES : usize = 100 ;
30- const THRESHOLD : usize = ( 2 * TOTAL_NODES / 3 ) + 1 ;
3129const NODE_0_LEADER_PROBABILITY : f64 = 0.1 ;
3230const NODE_UNDER_TEST : usize = 0 ;
3331
@@ -137,12 +135,16 @@ struct DiscreteEventSimulation {
137135 rng : StdRng ,
138136 /// The seed used to initialize the simulation.
139137 seed : u64 ,
138+ /// Total number of nodes in the network.
139+ total_nodes : usize ,
140+ /// Number of honest nodes (the rest are faulty).
141+ honest_nodes : usize ,
142+ /// Quorum threshold for reaching consensus (2/3 + 1 of total nodes).
143+ quorum_threshold : usize ,
140144 /// The single height consensus instance.
141145 shc : SingleHeightConsensus ,
142146 /// All validators in the network.
143147 validators : Vec < ValidatorId > ,
144- /// Number of honest nodes (the rest are faulty).
145- honest_nodes : usize ,
146148 /// Priority queue of pending events that have yet to be processed (min-heap by tick).
147149 pending_events : BinaryHeap < TimedEvent > ,
148150 /// Current simulation tick.
@@ -187,12 +189,16 @@ impl DiscreteEventSimulation {
187189 TimeoutsConfig :: default ( ) ,
188190 ) ;
189191
192+ let quorum_threshold = ( 2 * total_nodes / 3 ) + 1 ;
193+
190194 Self {
191195 rng,
192196 seed,
197+ total_nodes,
198+ honest_nodes,
199+ quorum_threshold,
193200 shc,
194201 validators,
195- honest_nodes,
196202 pending_events : BinaryHeap :: new ( ) ,
197203 current_tick : 0 ,
198204 processed_history : Vec :: new ( ) ,
@@ -228,17 +234,17 @@ impl DiscreteEventSimulation {
228234 /// Other nodes share the remaining probability (1 - NODE_0_LEADER_PROBABILITY) uniformly.
229235 /// The selection is deterministic per round - the same round will always return the same
230236 /// leader index.
231- fn get_leader_index ( seed : u64 , round : Round ) -> usize {
237+ fn get_leader_index ( & self , round : Round ) -> usize {
232238 let round_u64 = u64:: from ( round) ;
233- let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
239+ let round_seed = self . seed . wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
234240 let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
235241
236242 let random_value: f64 = round_rng. gen ( ) ;
237243
238244 if random_value < NODE_0_LEADER_PROBABILITY {
239245 NODE_UNDER_TEST
240246 } else {
241- round_rng. gen_range ( 1 ..TOTAL_NODES )
247+ round_rng. gen_range ( 1 ..self . total_nodes )
242248 }
243249 }
244250
@@ -300,7 +306,7 @@ impl DiscreteEventSimulation {
300306 fn pre_generate_all_rounds ( & mut self ) {
301307 for round_idx in 0 ..self . num_rounds {
302308 let round = Round :: from ( u32:: try_from ( round_idx) . unwrap ( ) ) ;
303- let leader_idx = Self :: get_leader_index ( self . seed , round) ;
309+ let leader_idx = self . get_leader_index ( round) ;
304310 let leader_id = self . validators [ leader_idx] ;
305311 // Track rounds where NODE_0 is the proposer.
306312 // We will schedule peer votes for these rounds after the build finish event.
@@ -407,7 +413,7 @@ impl DiscreteEventSimulation {
407413 }
408414 FaultType :: NonValidator => {
409415 // Send votes with a voter ID that is outside the validator set
410- let non_validator_id = ValidatorId :: from ( u64:: try_from ( TOTAL_NODES ) . unwrap ( ) ) ;
416+ let non_validator_id = ValidatorId :: from ( u64:: try_from ( self . total_nodes ) . unwrap ( ) ) ;
411417 self . schedule_prevote_and_precommit (
412418 non_validator_id,
413419 round,
@@ -460,8 +466,17 @@ impl DiscreteEventSimulation {
460466
461467 let validators = self . validators . clone ( ) ;
462468 let seed = self . seed ;
469+ let total_nodes = self . total_nodes ;
463470 let leader_fn = move |r : Round | {
464- let idx = Self :: get_leader_index ( seed, r) ;
471+ let round_u64 = u64:: from ( r) ;
472+ let round_seed = seed. wrapping_mul ( 31 ) . wrapping_add ( round_u64) ;
473+ let mut round_rng = StdRng :: seed_from_u64 ( round_seed) ;
474+ let random_value: f64 = round_rng. gen ( ) ;
475+ let idx = if random_value < NODE_0_LEADER_PROBABILITY {
476+ NODE_UNDER_TEST
477+ } else {
478+ round_rng. gen_range ( 1 ..total_nodes)
479+ } ;
465480 validators[ idx]
466481 } ;
467482
@@ -603,7 +618,7 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
603618 . count ( ) ;
604619 let total_precommits = peer_precommits + self_vote;
605620
606- if total_precommits >= THRESHOLD {
621+ if total_precommits >= sim . quorum_threshold {
607622 Some ( ( * r, * commitment, precommits. clone ( ) ) )
608623 } else {
609624 None
@@ -657,10 +672,10 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
657672
658673 // Verify quorum threshold is met
659674 assert ! (
660- actual. precommits. len( ) >= THRESHOLD ,
675+ actual. precommits. len( ) >= sim . quorum_threshold ,
661676 "Insufficient precommits in decision: {}/{}. Decision: {:?}, History: {:?}" ,
662677 actual. precommits. len( ) ,
663- THRESHOLD ,
678+ sim . quorum_threshold ,
664679 actual,
665680 sim. processed_history
666681 ) ;
@@ -686,13 +701,14 @@ fn verify_result(sim: &DiscreteEventSimulation, result: Option<&Decision>) {
686701fn test_consensus_simulation ( keep_ratio : f64 , honest_nodes : usize ) {
687702 let seed = rand:: thread_rng ( ) . gen ( ) ;
688703 let num_rounds = 5 ; // Number of rounds to pre-generate
704+ let total_nodes = 100 ;
689705 println ! (
690- "Running consensus simulation with total nodes {TOTAL_NODES }, {num_rounds} rounds, keep \
706+ "Running consensus simulation with total nodes {total_nodes }, {num_rounds} rounds, keep \
691707 ratio {keep_ratio}, honest nodes {honest_nodes} and seed: {seed}"
692708 ) ;
693709
694710 let mut sim =
695- DiscreteEventSimulation :: new ( TOTAL_NODES , honest_nodes, seed, num_rounds, keep_ratio) ;
711+ DiscreteEventSimulation :: new ( total_nodes , honest_nodes, seed, num_rounds, keep_ratio) ;
696712
697713 let deadline_ticks = u64:: try_from ( num_rounds) . unwrap ( ) * ROUND_DURATION ;
698714 let result = sim. run ( deadline_ticks) ;
0 commit comments