Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
romac committed Oct 23, 2023
1 parent 89d886f commit 290f819
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 45 deletions.
10 changes: 7 additions & 3 deletions Code/common/src/consensus.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
use crate::{Height, Proposal, PublicKey, Round, ValidatorSet, Value, ValueId, Vote};
use crate::{
Address, Height, Proposal, PublicKey, Round, Validator, ValidatorSet, Value, ValueId, Vote,
};

pub trait Consensus
where
Self: Sized,
{
type Address;
type Address: Address;
type Height: Height;
type Proposal: Proposal<Self>;
type PublicKey: PublicKey;
type ValidatorSet: ValidatorSet;
type ValidatorSet: ValidatorSet<Self>;
type Validator: Validator<Self>;
type Value: Value;
type Vote: Vote<Self>;

Expand Down Expand Up @@ -55,6 +58,7 @@ pub mod test {
type Proposal = Proposal;
type PublicKey = PublicKey;
type ValidatorSet = ValidatorSet;
type Validator = Validator;
type Value = Value;
type Vote = Vote;

Expand Down
89 changes: 66 additions & 23 deletions Code/common/src/validator_set.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use core::fmt::Debug;

use crate::Consensus;

// TODO: Do we need to abstract over this as well?
pub type VotingPower = u64;

Expand All @@ -10,26 +12,38 @@ where
fn hash(&self) -> u64; // FIXME: Make the hash type generic
}

// TODO: Keep this trait or just add the bounds to Consensus::Address?
pub trait Address
where
Self: Clone + Debug + PartialEq + Eq,
{
}

pub trait Validator
pub trait Validator<C>
where
Self: Clone + Debug + PartialEq + Eq,
C: Consensus,
{
fn address(&self) -> &C::Address;
fn public_key(&self) -> &C::PublicKey;
fn voting_power(&self) -> VotingPower;
}

pub trait ValidatorSet
pub trait ValidatorSet<C>
where
Self: Clone + Debug + PartialEq + Eq,
C: Consensus,
{
type Validator: Validator;
fn total_voting_power(&self) -> VotingPower;
fn get_proposer(&self) -> C::Validator;
fn get_by_public_key(&self, public_key: &C::PublicKey) -> Option<&C::Validator>;
fn get_by_address(&self, address: &C::Address) -> Option<&C::Validator>;
}

pub mod test {
use std::sync::atomic::{AtomicUsize, Ordering};

use crate::test::TestConsensus;

use super::VotingPower;

#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
Expand Down Expand Up @@ -65,41 +79,56 @@ pub mod test {
/// A validator is a public key and voting power
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Validator {
pub address: Address,
pub public_key: PublicKey,
pub voting_power: VotingPower,
}

impl Validator {
pub fn new(public_key: PublicKey, voting_power: VotingPower) -> Self {
Self {
address: Address(public_key.hash()),
public_key,
voting_power,
}
}

pub fn hash(&self) -> Vec<u8> {
self.public_key.0.clone() // TODO
pub fn hash(&self) -> u64 {
self.public_key.hash() // TODO
}
}

pub fn address(&self) -> Address {
Address(self.public_key.hash()) // TODO
impl super::Validator<TestConsensus> for Validator {
fn address(&self) -> &Address {
&self.address
}

fn public_key(&self) -> &PublicKey {
&self.public_key
}
}

impl super::Validator for Validator {}
fn voting_power(&self) -> VotingPower {
self.voting_power
}
}

/// A validator set contains a list of validators sorted by address.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ValidatorSet {
validators: Vec<Validator>,
proposer: AtomicUsize,
}

impl ValidatorSet {
pub fn new(validators: impl IntoIterator<Item = Validator>) -> Self {
let mut validators: Vec<_> = validators.into_iter().collect();
ValidatorSet::sort_validators(&mut validators);

Self { validators }
assert!(!validators.is_empty());

Self {
validators,
proposer: AtomicUsize::new(0),
}
}

/// The total voting power of the validator set
Expand All @@ -120,7 +149,7 @@ pub mod test {
if let Some(v) = self
.validators
.iter_mut()
.find(|v| v.address() == val.address())
.find(|v| v.address == val.address)
{
v.voting_power = val.voting_power;
}
Expand All @@ -132,14 +161,14 @@ pub mod test {

/// Remove a validator from the set
pub fn remove(&mut self, address: &Address) {
self.validators.retain(|v| &v.address() != address);
self.validators.retain(|v| &v.address != address);

Self::sort_validators(&mut self.validators); // TODO: Not needed
}

/// Get a validator by its address
pub fn get_by_address(&self, address: &Address) -> Option<&Validator> {
self.validators.iter().find(|v| &v.address() == address)
self.validators.iter().find(|v| &v.address == address)
}

pub fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&Validator> {
Expand All @@ -152,22 +181,36 @@ pub mod test {

// Sort the validators according to the current Tendermint requirements
// (v. 0.34 -> first by validator power, descending, then by address, ascending)
vals.sort_unstable_by_key(|v| (Reverse(v.voting_power), v.address()));
vals.sort_unstable_by_key(|v| (Reverse(v.voting_power), v.address));

vals.dedup();
}

pub fn get_proposer(&mut self) -> Validator {
pub fn get_proposer(&self) -> Validator {
// TODO: Proper implementation
assert!(!self.validators.is_empty());
let proposer = self.validators[0].clone();
self.validators.rotate_left(1);
let proposer = self.validators[self.proposer.load(Ordering::Relaxed)].clone();
self.proposer.fetch_add(1, Ordering::Relaxed);
proposer
}
}

impl super::ValidatorSet for ValidatorSet {
type Validator = Validator;
impl super::ValidatorSet<TestConsensus> for ValidatorSet {
fn total_voting_power(&self) -> VotingPower {
self.total_voting_power()
}

fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&Validator> {
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)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -198,11 +241,11 @@ pub mod test {
vs.update(v5.clone());
assert_eq!(vs.total_voting_power(), 110);

vs.remove(&v5.address());
vs.remove(&v5.address);
assert_eq!(vs.total_voting_power(), 10);

let v6 = Validator::new(PublicKey(vec![6]), 6);
vs.remove(&v6.address()); // no effect
vs.remove(&v6.address); // no effect
assert_eq!(vs.total_voting_power(), 10);
}
}
Expand Down
13 changes: 10 additions & 3 deletions Code/common/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@ where
{
fn round(&self) -> Round;
fn value(&self) -> Option<&<C::Value as Value>::Id>;
fn address(&self) -> &C::Address;
fn vote_type(&self) -> VoteType;

// FIXME: round message votes should not include address
fn address(&self) -> &C::Address;
fn set_address(&mut self, address: C::Address);
}

pub mod test {
Expand Down Expand Up @@ -62,12 +65,16 @@ pub mod test {
self.value.as_ref()
}

fn vote_type(&self) -> VoteType {
self.typ
}

fn address(&self) -> &Address {
&self.address
}

fn vote_type(&self) -> VoteType {
self.typ
fn set_address(&mut self, address: Address) {
self.address = address;
}
}
}
Loading

0 comments on commit 290f819

Please sign in to comment.