test context for full agreement protocol

This commit is contained in:
Robert Habermeier
2018-01-14 23:44:19 +01:00
parent 5a369064a4
commit f87893cd87
2 changed files with 164 additions and 20 deletions
+1 -18
View File
@@ -701,6 +701,7 @@ impl<C: Context> Table<C> {
#[cfg(test)]
mod tests {
use super::*;
use ::tests::VecBatch;
use std::collections::HashMap;
fn create<C: Context>() -> Table<C> {
@@ -733,24 +734,6 @@ mod tests {
validators: HashMap<ValidatorId, (GroupId, GroupId)>
}
struct VecBatch<V, T> {
max_len: usize,
targets: Vec<V>,
items: Vec<T>,
}
impl<V, T> ::StatementBatch<V, T> for VecBatch<V, T> {
fn targets(&self) -> &[V] { &self.targets }
fn push(&mut self, item: T) -> bool {
if self.items.len() == self.max_len {
false
} else {
self.items.push(item);
true
}
}
}
impl Context for TestContext {
type ValidatorId = ValidatorId;
type Digest = Digest;
+163 -2
View File
@@ -16,7 +16,168 @@
//! Tests and test helpers for the candidate agreement.
const VALIDITY_CHECK_DELAY_MS: isize = 400;
const AVAILABILITY_CHECK_DELAY_MS: isize = 200;
const VALIDITY_CHECK_DELAY_MS: u64 = 400;
const AVAILABILITY_CHECK_DELAY_MS: u64 = 200;
use tokio_timer::Timer;
use super::*;
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
struct ValidatorId(usize);
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
struct Digest(usize);
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
struct GroupId(usize);
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Clone)]
struct ParachainCandidate {
group: GroupId,
data: usize,
}
#[derive(PartialEq, Eq, Debug, Clone)]
struct Proposal {
candidates: Vec<ParachainCandidate>,
}
#[derive(PartialEq, Eq, Debug, Clone)]
enum Signature {
Table(ValidatorId, table::Statement<ParachainCandidate, Digest>),
Bft(ValidatorId, bft::Message<Proposal, Digest>),
}
struct TestAuthority {
id: ValidatorId,
}
enum Error {
Timer(tokio_timer::TimerError),
}
#[derive(Clone)]
struct SharedTestContext {
n_authorities: usize,
n_groups: usize,
timer: Timer,
}
#[derive(Clone)]
struct TestContext {
shared: Arc<SharedTestContext>,
local_id: ValidatorId,
}
impl Context for TestContext {
type ValidatorId = ValidatorId;
type Digest = Digest;
type GroupId = GroupId;
type Signature = Signature;
type Proposal = Proposal;
type ParachainCandidate = ParachainCandidate;
type CheckCandidate = Box<Future<Item=bool,Error=Error>>;
type CheckAvailability = Box<Future<Item=bool,Error=Error>>;
type StatementBatch = VecBatch<
ValidatorId,
table::SignedStatement<ParachainCandidate, Digest, ValidatorId, Signature>
>;
fn candidate_digest(candidate: &ParachainCandidate) -> Digest {
Digest(!candidate.data & candidate.group.0)
}
fn proposal_digest(candidate: &Proposal) -> Digest {
Digest(candidate.candidates.iter().fold(0, |mut acc, c| {
acc = acc.wrapping_shl(2);
acc ^= Self::candidate_digest(c).0;
acc
}))
}
fn candidate_group(candidate: &ParachainCandidate) -> GroupId {
candidate.group.clone()
}
fn round_proposer(&self, round: usize) -> ValidatorId {
ValidatorId(round % self.shared.n_authorities)
}
fn check_validity(&self, _candidate: &ParachainCandidate) -> Self::CheckCandidate {
let future = self.shared.timer
.sleep(::std::time::Duration::from_millis(VALIDITY_CHECK_DELAY_MS))
.map_err(Error::Timer)
.map(|_| true);
Box::new(future)
}
fn check_availability(&self, _candidate: &ParachainCandidate) -> Self::CheckAvailability {
let future = self.shared.timer
.sleep(::std::time::Duration::from_millis(AVAILABILITY_CHECK_DELAY_MS))
.map_err(Error::Timer)
.map(|_| true);
Box::new(future)
}
fn create_proposal(&self, candidates: Vec<&ParachainCandidate>)
-> Option<Proposal>
{
// only if it has at least than 2/3 of all groups.
if candidates.len() >= self.shared.n_groups * 2 / 3 {
Some(Proposal {
candidates: candidates.iter().map(|x| (&**x).clone()).collect()
})
} else {
None
}
}
fn proposal_valid<F>(&self, proposal: &Proposal, check_candidate: F) -> bool
where F: FnMut(&ParachainCandidate) -> bool
{
// only if it has more than 2/3 of groups.
if proposal.candidates.len() >= self.shared.n_groups * 2 / 3 {
proposal.candidates.iter().all(check_candidate)
} else {
false
}
}
fn local_id(&self) -> ValidatorId {
self.local_id.clone()
}
fn sign_table_statement(
&self,
statement: &table::Statement<ParachainCandidate, Digest>
) -> Signature {
Signature::Table(self.local_id(), statement.clone())
}
fn sign_bft_message(&self, message: &bft::Message<Proposal, Digest>) -> Signature {
Signature::Bft(self.local_id(), message.clone())
}
}
pub struct VecBatch<V, T> {
pub max_len: usize,
pub targets: Vec<V>,
pub items: Vec<T>,
}
impl<V, T> ::StatementBatch<V, T> for VecBatch<V, T> {
fn targets(&self) -> &[V] { &self.targets }
fn push(&mut self, item: T) -> bool {
if self.items.len() == self.max_len {
false
} else {
self.items.push(item);
true
}
}
}