Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move tests and associated data types into their own crate #10

Merged
merged 5 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# macOS Finder and Windows Thumbs.db files
.DS_Store
Thumbs.db

# Generated by Cargo
# will have compiled files and executables
debug/
Expand Down
1 change: 1 addition & 0 deletions Code/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ members = [
"consensus",
"round",
"vote",
"test",
]
39 changes: 0 additions & 39 deletions Code/common/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,42 +40,3 @@ where
address: Self::Address,
) -> Self::Vote;
}

pub mod test {
use crate::height::test::*;
use crate::proposal::test::*;
use crate::validator_set::test::*;
use crate::value::test::*;
use crate::vote::test::*;
use crate::Round;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct TestConsensus;

impl super::Consensus for TestConsensus {
type Address = Address;
type Height = Height;
type Proposal = Proposal;
type PublicKey = PublicKey;
type ValidatorSet = ValidatorSet;
type Validator = Validator;
type Value = Value;
type Vote = Vote;

const DUMMY_ADDRESS: Address = Address::new(42);

const DUMMY_VALUE: Self::Value = Value::new(9999);

fn new_proposal(height: Height, round: Round, value: Value, pol_round: Round) -> Proposal {
Proposal::new(height, round, value, pol_round)
}

fn new_prevote(round: Round, value_id: Option<ValueId>, address: Address) -> Vote {
Vote::new_prevote(round, value_id, address)
}

fn new_precommit(round: Round, value_id: Option<ValueId>, address: Address) -> Vote {
Vote::new_precommit(round, value_id, address)
}
}
}
18 changes: 0 additions & 18 deletions Code/common/src/height.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,3 @@ where
Self: Clone + Debug + PartialEq + Eq + PartialOrd + Ord,
{
}

pub mod test {
/// A blockchain height
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Height(u64);

impl Height {
pub fn new(height: u64) -> Self {
Self(height)
}

pub fn as_u64(&self) -> u64 {
self.0
}
}

impl super::Height for Height {}
}
11 changes: 1 addition & 10 deletions Code/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,6 @@ pub use height::Height;
pub use proposal::Proposal;
pub use round::Round;
pub use timeout::{Timeout, TimeoutStep};
pub use validator_set::{Address, PublicKey, Validator, ValidatorSet};
pub use validator_set::{Address, PublicKey, Validator, ValidatorSet, VotingPower};
pub use value::Value;
pub use vote::{Vote, VoteType};

pub mod test {
pub use crate::consensus::test::*;
pub use crate::height::test::*;
pub use crate::proposal::test::*;
pub use crate::validator_set::test::*;
pub use crate::value::test::*;
pub use crate::vote::test::*;
}
43 changes: 0 additions & 43 deletions Code/common/src/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,3 @@ where
fn value(&self) -> &C::Value;
fn pol_round(&self) -> Round;
}

pub mod test {
use crate::test::{Height, TestConsensus, Value};
use crate::Round;

/// A proposal for a value in a round
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Proposal {
pub height: Height,
pub round: Round,
pub value: Value,
pub pol_round: Round,
}

impl Proposal {
pub fn new(height: Height, round: Round, value: Value, pol_round: Round) -> Self {
Self {
height,
round,
value,
pol_round,
}
}
}

impl super::Proposal<TestConsensus> for Proposal {
fn height(&self) -> Height {
self.height
}

fn round(&self) -> Round {
self.round
}

fn value(&self) -> &Value {
&self.value
}

fn pol_round(&self) -> Round {
self.pol_round
}
}
}
212 changes: 0 additions & 212 deletions Code/common/src/validator_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,215 +38,3 @@ where
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)]
pub struct PublicKey(Vec<u8>);

impl PublicKey {
pub const fn new(value: Vec<u8>) -> Self {
Self(value)
}

pub fn hash(&self) -> u64 {
self.0.iter().fold(0, |acc, x| acc ^ *x as u64)
}
}

impl super::PublicKey for PublicKey {
fn hash(&self) -> u64 {
self.hash()
}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Address(u64);

impl Address {
pub const fn new(value: u64) -> Self {
Self(value)
}
}

impl super::Address for Address {}

/// 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) -> u64 {
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
}

fn voting_power(&self) -> VotingPower {
self.voting_power
}
}

/// A validator set contains a list of validators sorted by address.
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);

assert!(!validators.is_empty());

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

/// The total voting power of the validator set
pub fn total_voting_power(&self) -> VotingPower {
// TODO: Cache this?
self.validators.iter().map(|v| v.voting_power).sum()
}

/// Add a validator to the set
pub fn add(&mut self, validator: Validator) {
self.validators.push(validator);

ValidatorSet::sort_validators(&mut self.validators);
}

/// Update the voting power of the given validator
pub fn update(&mut self, val: Validator) {
if let Some(v) = self
.validators
.iter_mut()
.find(|v| v.address == val.address)
{
v.voting_power = val.voting_power;
}

dbg!(self.total_voting_power());
Self::sort_validators(&mut self.validators);
dbg!(self.total_voting_power());
}

/// Remove a validator from the set
pub fn remove(&mut self, 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)
}

pub fn get_by_public_key(&self, public_key: &PublicKey) -> Option<&Validator> {
self.validators.iter().find(|v| &v.public_key == public_key)
}

/// In place sort and deduplication of a list of validators
fn sort_validators(vals: &mut Vec<Validator>) {
use core::cmp::Reverse;

// 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.dedup();
}

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

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)]
mod tests {
use super::*;

#[test]
fn add_update_remove() {
let v1 = Validator::new(PublicKey(vec![1]), 1);
let v2 = Validator::new(PublicKey(vec![2]), 2);
let v3 = Validator::new(PublicKey(vec![3]), 3);

let mut vs = ValidatorSet::new(vec![v1, v2, v3]);
assert_eq!(vs.total_voting_power(), 6);

let v4 = Validator::new(PublicKey(vec![4]), 4);
vs.add(v4);
assert_eq!(vs.total_voting_power(), 10);

let mut v5 = Validator::new(PublicKey(vec![5]), 5);
vs.update(v5.clone()); // no effect
assert_eq!(vs.total_voting_power(), 10);

vs.add(v5.clone());
assert_eq!(vs.total_voting_power(), 15);

v5.voting_power = 100;
vs.update(v5.clone());
assert_eq!(vs.total_voting_power(), 110);

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
assert_eq!(vs.total_voting_power(), 10);
}
}
}
Loading
Loading