Skip to content

Commit

Permalink
Add interface for selecting proposer each round
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed Nov 9, 2023
1 parent c236fad commit cebbda9
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 38 deletions.
3 changes: 0 additions & 3 deletions Code/common/src/validator_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ctx>) -> Option<&Ctx::Validator>;

Expand Down
30 changes: 23 additions & 7 deletions Code/driver/src/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Ctx, Client>
pub struct Driver<Ctx, Klient, PSel>
where
Ctx: Context,
Client: crate::client::Client<Ctx>,
Klient: Client<Ctx>,
PSel: ProposerSelector<Ctx>,
{
pub client: Client,
pub client: Klient,
pub proposer_selector: PSel,

pub height: Ctx::Height,
pub private_key: Secret<PrivateKey<Ctx>>,
pub address: Ctx::Address,
Expand All @@ -35,13 +40,15 @@ where
pub round_states: BTreeMap<Round, RoundState<Ctx>>,
}

impl<Ctx, Client> Driver<Ctx, Client>
impl<Ctx, Klient, PSel> Driver<Ctx, Klient, PSel>
where
Ctx: Context,
Client: crate::client::Client<Ctx>,
Klient: Client<Ctx>,
PSel: ProposerSelector<Ctx>,
{
pub fn new(
client: Client,
client: Klient,
proposer_selector: PSel,
height: Ctx::Height,
validator_set: Ctx::ValidatorSet,
private_key: PrivateKey<Ctx>,
Expand All @@ -51,6 +58,7 @@ where

Self {
client,
proposer_selector,
height,
private_key: Secret::new(private_key),
address,
Expand Down Expand Up @@ -113,8 +121,16 @@ where
}

fn apply_new_round(&mut self, round: Round) -> Option<RoundMessage<Ctx>> {
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)
Expand Down
2 changes: 2 additions & 0 deletions Code/driver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
8 changes: 8 additions & 0 deletions Code/driver/src/proposer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use malachite_common::{Context, Round};

pub trait ProposerSelector<Ctx>
where
Ctx: Context,
{
fn select_proposer(&mut self, round: Round, validator_set: &Ctx::ValidatorSet) -> Ctx::Address;
}
24 changes: 2 additions & 22 deletions Code/test/src/validator_set.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use std::sync::atomic::{AtomicUsize, Ordering};

use malachite_common::VotingPower;

use crate::{signing::PublicKey, TestContext};
Expand Down Expand Up @@ -58,8 +56,7 @@ impl malachite_common::Validator<TestContext> for Validator {

/// A validator set contains a list of validators sorted by address.
pub struct ValidatorSet {
validators: Vec<Validator>,
proposer: AtomicUsize,
pub validators: Vec<Validator>,
}

impl ValidatorSet {
Expand All @@ -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
Expand Down Expand Up @@ -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<TestContext> for ValidatorSet {
Expand All @@ -153,10 +137,6 @@ impl malachite_common::ValidatorSet<TestContext> 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)
}
Expand Down
35 changes: 29 additions & 6 deletions Code/test/tests/driver.rs
Original file line number Diff line number Diff line change
@@ -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::{
Expand All @@ -26,11 +26,30 @@ fn to_input_msg(output: Message<TestContext>) -> Option<Event<TestContext>> {
}
}

pub struct RotateProposer {
proposer_index: usize,
}

impl Default for RotateProposer {
fn default() -> Self {
Self { proposer_index: 0 }
}
}

impl ProposerSelector<TestContext> 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);
Expand All @@ -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));

Expand Down Expand Up @@ -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);
Expand All @@ -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));

Expand Down Expand Up @@ -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);
Expand All @@ -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));

Expand Down Expand Up @@ -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);
Expand All @@ -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
Expand Down

0 comments on commit cebbda9

Please sign in to comment.