From cd438e51a84f5d026e75456122deee485bb14641 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 1 Jan 2018 20:00:44 +0100 Subject: [PATCH] more type-safe justifications --- .../src/bft/accumulator.rs | 75 ++++++++++++------- substrate/candidate-agreement/src/bft/mod.rs | 2 +- .../candidate-agreement/src/bft/tests.rs | 4 +- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/substrate/candidate-agreement/src/bft/accumulator.rs b/substrate/candidate-agreement/src/bft/accumulator.rs index e457bef859..8999a9f29b 100644 --- a/substrate/candidate-agreement/src/bft/accumulator.rs +++ b/substrate/candidate-agreement/src/bft/accumulator.rs @@ -23,8 +23,8 @@ use std::hash::Hash; use super::{Message, LocalizedMessage}; /// Justification for some state at a given round. -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Justification { +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct UncheckedJustification { /// The round. pub round_number: usize, /// The digest prepared for. @@ -33,36 +33,61 @@ pub struct Justification { pub signatures: Vec, } -impl Justification { +impl UncheckedJustification { /// Fails if there are duplicate signatures or invalid. /// /// Provide a closure for checking whether the signature is valid on a /// digest. /// - /// The closure should return true iff the round number, digest, and signature + /// The closure should returns a checked justification iff the round number, digest, and signature /// represent a valid message and the signer was authorized to issue /// it. /// /// The `check_message` closure may vary based on context. - pub fn check(&self, threshold: usize, check_message: F) -> bool + pub fn check(self, threshold: usize, mut check_message: F) + -> Result, Self> where - F: Fn(usize, &D, &S) -> Option, + F: FnMut(usize, &D, &S) -> Option, V: Hash + Eq, { - let mut voted = HashSet::new(); + let checks_out = { + let mut checks_out = || { + let mut voted = HashSet::new(); - for signature in &self.signatures { - match check_message(self.round_number, &self.digest, signature) { - None => return false, - Some(v) => { - if !voted.insert(v) { - return false; + for signature in &self.signatures { + match check_message(self.round_number, &self.digest, signature) { + None => return false, + Some(v) => { + if !voted.insert(v) { + return false; + } + } } } - } - } - voted.len() >= threshold + voted.len() >= threshold + }; + + checks_out() + }; + + if checks_out { + Ok(Justification(self)) + } else { + Err(self) + } + } +} + +/// A checked justification. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Justification(UncheckedJustification); + +impl ::std::ops::Deref for Justification { + type Target = UncheckedJustification; + + fn deref(&self) -> &Self::Target { + &self.0 } } @@ -228,11 +253,11 @@ impl Accumulator Accumulator