Skip to content

Commit

Permalink
Add TrustLevel as a trait; default behaviour is as before:
Browse files Browse the repository at this point in the history
accept iff +1/3 of the voting power signed
  • Loading branch information
liamsi committed Dec 8, 2019
1 parent 63e0928 commit bd26e74
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 9 deletions.
13 changes: 13 additions & 0 deletions tendermint/src/lite/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,19 @@ pub trait Vote {
fn signature(&self) -> &[u8];
}

/// TrustLevel defines what fraction of the total voting power of a known
/// and trusted validator set is sufficient for a commit to be
/// accepted going forward.
/// The default implementation returns true, iff at least a third of the trusted
/// voting power signed (in other words at least one "trusted" validator signed).
/// Some clients might require more than +1/3 and can implement their own
/// TrustLevel which can be passed into all relevant methods.
pub trait TrustLevel {
fn is_enough_power(&self, signed_voting_power: u64, total_voting_power: u64) -> bool {
signed_voting_power * 3 > total_voting_power
}
}

#[derive(Debug)]
pub enum Error {
Expired,
Expand Down
22 changes: 13 additions & 9 deletions tendermint/src/lite/verifier.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#[allow(clippy::all)]
use crate::lite::{Commit, Error, Header, Validator, ValidatorSet, ValidatorSetLookup, Vote};
use crate::lite::{
Commit, Error, Header, TrustLevel, Validator, ValidatorSet, ValidatorSetLookup, Vote,
};
use crate::Time;
use std::time::Duration;

Expand Down Expand Up @@ -71,23 +73,25 @@ where

/// Verify the commit is trusted according to the last validators and is valid
/// from the current validators for the header.
pub fn verify_trusting<H, V, C>(
pub fn verify_trusting<H, V, C, L>(
header: H,
commit: C,
last_validators: V,
validators: V,
trust_level: L,
) -> Result<(), Error>
where
H: Header,
V: ValidatorSetLookup,
C: Commit,
L: TrustLevel,
{
// NOTE it might be more prudent to do the cheap validations first
// before we even call verify_commit_trusting, but not doing that
// makes the code cleaner and allows us to just call verify directly.

// ensure that +1/3 of last trusted validators signed correctly
if let Err(e) = verify_commit_trusting(&last_validators, &commit) {
if let Err(e) = verify_commit_trusting(&last_validators, &commit, trust_level) {
return Err(e);
}

Expand Down Expand Up @@ -144,14 +148,13 @@ where

/// Verify that +1/3 of the given validator set signed this commit.
/// NOTE the given validators do not necessarily correspond to the validator set for this commit,
/// but there may be some intersection.
/// TODO: this should take a "trust_level" param to allow clients to require more
/// than +1/3. How should this be defined semantically? Probably shouldn't be a float, maybe
/// and enum of options, eg. 1/3, 1/2, 2/3, 1 ?
fn verify_commit_trusting<V, C>(validators: &V, commit: &C) -> Result<(), Error>
/// but there may be some intersection. The trust_level parameter allows clients to require more
/// than +1/3 by implementing the TrustLevel trait accordingly.
fn verify_commit_trusting<V, C, L>(validators: &V, commit: &C, trust_level: L) -> Result<(), Error>
where
V: ValidatorSetLookup,
C: Commit,
L: TrustLevel,
{
let total_power = validators.total_power();
let mut signed_power: u64 = 0;
Expand Down Expand Up @@ -188,7 +191,8 @@ where
// check the signers account for +1/3 of the voting power
// TODO: incorporate "trust_level" in here to possibly increase
// beyond 1/3.
if signed_power * 3 <= total_power {

if !trust_level.is_enough_power(signed_power, total_power) {
return Err(Error::InsufficientVotingPower);
}

Expand Down
4 changes: 4 additions & 0 deletions tendermint/tests/lite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ fn read_json_fixture(name: &str) -> String {

#[test]
fn check_verifier_with_mock_data() {
pub struct DefaultTrustLevel {}
impl lite::TrustLevel for DefaultTrustLevel {}

let suite: TestSuite = serde_json::from_str(&read_json_fixture("basic")).unwrap();
lite::verify_trusting(
suite.signed_header.header.clone(),
suite.signed_header,
validator::Set::new(suite.last_validators),
validator::Set::new(suite.validators),
DefaultTrustLevel {},
)
.expect("verify_trusting failed");
}

0 comments on commit bd26e74

Please sign in to comment.