diff --git a/Code/common/src/validator_set.rs b/Code/common/src/validator_set.rs index 0c21dccf9..cbc89b315 100644 --- a/Code/common/src/validator_set.rs +++ b/Code/common/src/validator_set.rs @@ -42,9 +42,6 @@ where /// The total voting power of the validator set. fn total_voting_power(&self) -> VotingPower; - /// The proposer in the validator set. - fn get_proposer(&self) -> &Ctx::Validator; - /// Get the validator with the given public key. fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&Ctx::Validator>; diff --git a/Code/driver/src/driver.rs b/Code/driver/src/driver.rs index 7720b219b..74be929bf 100644 --- a/Code/driver/src/driver.rs +++ b/Code/driver/src/driver.rs @@ -15,17 +15,22 @@ use malachite_vote::keeper::Message as VoteMessage; use malachite_vote::keeper::VoteKeeper; use malachite_vote::Threshold; +use crate::client::Client; use crate::event::Event; use crate::message::Message; +use crate::ProposerSelector; /// Driver for the state machine of the Malachite consensus engine. #[derive(Clone, Debug)] -pub struct Driver +pub struct Driver where Ctx: Context, - Client: crate::client::Client, + Klient: Client, + PSel: ProposerSelector, { - pub client: Client, + pub client: Klient, + pub proposer_selector: PSel, + pub height: Ctx::Height, pub private_key: Secret>, pub address: Ctx::Address, @@ -35,13 +40,15 @@ where pub round_states: BTreeMap>, } -impl Driver +impl Driver where Ctx: Context, - Client: crate::client::Client, + Klient: Client, + PSel: ProposerSelector, { pub fn new( - client: Client, + client: Klient, + proposer_selector: PSel, height: Ctx::Height, validator_set: Ctx::ValidatorSet, private_key: PrivateKey, @@ -51,6 +58,7 @@ where Self { client, + proposer_selector, height, private_key: Secret::new(private_key), address, @@ -113,8 +121,16 @@ where } fn apply_new_round(&mut self, round: Round) -> Option> { - let proposer = self.validator_set.get_proposer(); + let proposer_address = self + .proposer_selector + .select_proposer(round, &self.validator_set); + + let proposer = self + .validator_set + .get_by_address(&proposer_address) + .expect("proposer not found"); // FIXME: expect + // TODO: Write this check differently, maybe just based on the address let event = if proposer.public_key() == &self.private_key.expose_secret().verifying_key() { let value = self.get_value(); RoundEvent::NewRoundProposer(value) diff --git a/Code/driver/src/lib.rs b/Code/driver/src/lib.rs index ce115e1e7..78d20b665 100644 --- a/Code/driver/src/lib.rs +++ b/Code/driver/src/lib.rs @@ -14,8 +14,10 @@ mod client; mod driver; mod event; mod message; +mod proposer; pub use client::Client; pub use driver::Driver; pub use event::Event; pub use message::Message; +pub use proposer::ProposerSelector; diff --git a/Code/driver/src/proposer.rs b/Code/driver/src/proposer.rs new file mode 100644 index 000000000..47a0b4a75 --- /dev/null +++ b/Code/driver/src/proposer.rs @@ -0,0 +1,8 @@ +use malachite_common::{Context, Round}; + +pub trait ProposerSelector +where + Ctx: Context, +{ + fn select_proposer(&mut self, round: Round, validator_set: &Ctx::ValidatorSet) -> Ctx::Address; +} diff --git a/Code/test/src/validator_set.rs b/Code/test/src/validator_set.rs index a5cd18e81..96096870c 100644 --- a/Code/test/src/validator_set.rs +++ b/Code/test/src/validator_set.rs @@ -1,5 +1,3 @@ -use std::sync::atomic::{AtomicUsize, Ordering}; - use malachite_common::VotingPower; use crate::{signing::PublicKey, TestContext}; @@ -58,8 +56,7 @@ impl malachite_common::Validator for Validator { /// A validator set contains a list of validators sorted by address. pub struct ValidatorSet { - validators: Vec, - proposer: AtomicUsize, + pub validators: Vec, } impl ValidatorSet { @@ -69,10 +66,7 @@ impl ValidatorSet { assert!(!validators.is_empty()); - Self { - validators, - proposer: AtomicUsize::new(0), - } + Self { validators } } /// The total voting power of the validator set @@ -132,16 +126,6 @@ impl ValidatorSet { vals.dedup(); } - - pub fn get_proposer(&self) -> &Validator { - // TODO: Proper implementation - assert!(!self.validators.is_empty()); - - let idx = self.proposer.load(Ordering::Relaxed) % self.validators.len(); - self.proposer.fetch_add(1, Ordering::Relaxed); - - &self.validators[idx] - } } impl malachite_common::ValidatorSet for ValidatorSet { @@ -153,10 +137,6 @@ impl malachite_common::ValidatorSet for ValidatorSet { self.get_by_public_key(public_key) } - fn get_proposer(&self) -> &Validator { - self.get_proposer() - } - fn get_by_address(&self, address: &Address) -> Option<&Validator> { self.get_by_address(address) } diff --git a/Code/test/tests/driver.rs b/Code/test/tests/driver.rs index 267fe1a1e..f098aa1e3 100644 --- a/Code/test/tests/driver.rs +++ b/Code/test/tests/driver.rs @@ -1,5 +1,5 @@ use malachite_common::{Context, Round, Timeout}; -use malachite_driver::{Driver, Event, Message}; +use malachite_driver::{Driver, Event, Message, ProposerSelector}; use malachite_round::state::{RoundValue, State, Step}; use malachite_test::{ @@ -26,11 +26,30 @@ fn to_input_msg(output: Message) -> Option> { } } +pub struct RotateProposer { + proposer_index: usize, +} + +impl Default for RotateProposer { + fn default() -> Self { + Self { proposer_index: 0 } + } +} + +impl ProposerSelector for RotateProposer { + fn select_proposer(&mut self, _round: Round, validator_set: &ValidatorSet) -> Address { + let proposer = &validator_set.validators[self.proposer_index]; + self.proposer_index = (self.proposer_index + 1) % validator_set.validators.len(); + proposer.address + } +} + #[test] fn driver_steps_proposer() { let value = TestContext::DUMMY_VALUE; let value_id = value.id(); + let sel = RotateProposer::default(); let client = TestClient::new(value.clone(), |_| true); let mut rng = StdRng::seed_from_u64(0x42); @@ -50,7 +69,7 @@ fn driver_steps_proposer() { let (my_sk, my_addr) = (sk1, addr1); let vs = ValidatorSet::new(vec![v1, v2.clone(), v3.clone()]); - let mut driver = Driver::new(client, Height::new(1), vs, my_sk.clone(), my_addr); + let mut driver = Driver::new(client, sel, Height::new(1), vs, my_sk.clone(), my_addr); let proposal = Proposal::new(Height::new(1), Round::new(0), value.clone(), Round::new(-1)); @@ -223,6 +242,7 @@ fn driver_steps_not_proposer_valid() { let value = TestContext::DUMMY_VALUE; let value_id = value.id(); + let sel = RotateProposer::default(); let client = TestClient::new(value.clone(), |_| true); let mut rng = StdRng::seed_from_u64(0x42); @@ -243,7 +263,7 @@ fn driver_steps_not_proposer_valid() { let (my_sk, my_addr) = (sk2, addr2); let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]); - let mut driver = Driver::new(client, Height::new(1), vs, my_sk.clone(), my_addr); + let mut driver = Driver::new(client, sel, Height::new(1), vs, my_sk.clone(), my_addr); let proposal = Proposal::new(Height::new(1), Round::new(0), value.clone(), Round::new(-1)); @@ -416,6 +436,7 @@ fn driver_steps_not_proposer_invalid() { let value = TestContext::DUMMY_VALUE; let value_id = value.id(); + let sel = RotateProposer::default(); let client = TestClient::new(value.clone(), |_| false); let mut rng = StdRng::seed_from_u64(0x42); @@ -436,7 +457,7 @@ fn driver_steps_not_proposer_invalid() { let (my_sk, my_addr) = (sk2, addr2); let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]); - let mut driver = Driver::new(client, Height::new(1), vs, my_sk.clone(), my_addr); + let mut driver = Driver::new(client, sel, Height::new(1), vs, my_sk.clone(), my_addr); let proposal = Proposal::new(Height::new(1), Round::new(0), value.clone(), Round::new(-1)); @@ -555,6 +576,9 @@ fn driver_steps_not_proposer_timeout_multiple_rounds() { let value = TestContext::DUMMY_VALUE; let value_id = value.id(); + let sel = RotateProposer::default(); + let client = TestClient::new(value.clone(), |_| true); + let mut rng = StdRng::seed_from_u64(0x42); let sk1 = PrivateKey::generate(&mut rng); @@ -573,8 +597,7 @@ fn driver_steps_not_proposer_timeout_multiple_rounds() { let (my_sk, my_addr) = (sk3, addr3); let vs = ValidatorSet::new(vec![v1.clone(), v2.clone(), v3.clone()]); - let client = TestClient::new(value.clone(), |_| true); - let mut driver = Driver::new(client, Height::new(1), vs, my_sk.clone(), my_addr); + let mut driver = Driver::new(client, sel, Height::new(1), vs, my_sk.clone(), my_addr); let steps = vec![ // Start round 0, we, v3, are not the proposer