Skip to content

Commit

Permalink
Move ValidatorSet::hash method over the HeaderHasher trait (renamed t…
Browse files Browse the repository at this point in the history
…o Hasher) (#360)
  • Loading branch information
romac committed Jun 23, 2020
1 parent 03ddcec commit 864bb4a
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 45 deletions.
14 changes: 7 additions & 7 deletions light-client/src/components/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use crate::{
errors::ErrorExt,
light_client::Options,
operations::{
CommitValidator, HeaderHasher, ProdCommitValidator, ProdHeaderHasher,
ProdVotingPowerCalculator, VotingPowerCalculator,
CommitValidator, Hasher, ProdCommitValidator, ProdHasher, ProdVotingPowerCalculator,
VotingPowerCalculator,
},
types::LightBlock,
};
Expand Down Expand Up @@ -60,21 +60,21 @@ pub struct ProdVerifier {
predicates: Box<dyn VerificationPredicates>,
voting_power_calculator: Box<dyn VotingPowerCalculator>,
commit_validator: Box<dyn CommitValidator>,
header_hasher: Box<dyn HeaderHasher>,
hasher: Box<dyn Hasher>,
}

impl ProdVerifier {
pub fn new(
predicates: impl VerificationPredicates + 'static,
voting_power_calculator: impl VotingPowerCalculator + 'static,
commit_validator: impl CommitValidator + 'static,
header_hasher: impl HeaderHasher + 'static,
hasher: impl Hasher + 'static,
) -> Self {
Self {
predicates: Box::new(predicates),
voting_power_calculator: Box::new(voting_power_calculator),
commit_validator: Box::new(commit_validator),
header_hasher: Box::new(header_hasher),
hasher: Box::new(hasher),
}
}
}
Expand All @@ -85,7 +85,7 @@ impl Default for ProdVerifier {
ProdPredicates,
ProdVotingPowerCalculator,
ProdCommitValidator,
ProdHeaderHasher,
ProdHasher,
)
}
}
Expand All @@ -96,7 +96,7 @@ impl Verifier for ProdVerifier {
&*self.predicates,
&*self.voting_power_calculator,
&*self.commit_validator,
&*self.header_hasher,
&*self.hasher,
&trusted,
&untrusted,
options,
Expand Down
14 changes: 7 additions & 7 deletions light-client/src/fork_detector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize};

use crate::{
errors::{Error, ErrorExt, ErrorKind},
operations::{HeaderHasher, ProdHeaderHasher},
operations::{Hasher, ProdHasher},
state::State,
store::{memory::MemoryStore, VerifiedStatus},
supervisor::Instance,
Expand Down Expand Up @@ -55,21 +55,21 @@ pub trait ForkDetector: Send {
/// - If verification fails for any other reason, the
/// witness is deemed faulty.
pub struct ProdForkDetector {
header_hasher: Box<dyn HeaderHasher>,
hasher: Box<dyn Hasher>,
}

impl ProdForkDetector {
/// Construct a new fork detector that will use the given header hasher.
pub fn new(header_hasher: impl HeaderHasher + 'static) -> Self {
pub fn new(hasher: impl Hasher + 'static) -> Self {
Self {
header_hasher: Box::new(header_hasher),
hasher: Box::new(hasher),
}
}
}

impl Default for ProdForkDetector {
fn default() -> Self {
Self::new(ProdHeaderHasher)
Self::new(ProdHasher)
}
}

Expand All @@ -81,7 +81,7 @@ impl ForkDetector for ProdForkDetector {
trusted_state: &LightBlock,
witnesses: Vec<&Instance>,
) -> Result<ForkDetection, Error> {
let primary_hash = self.header_hasher.hash(&light_block.signed_header.header);
let primary_hash = self.hasher.hash_header(&light_block.signed_header.header);

let mut forks = Vec::with_capacity(witnesses.len());

Expand All @@ -92,7 +92,7 @@ impl ForkDetector for ProdForkDetector {
.light_client
.get_or_fetch_block(light_block.height(), &mut state)?;

let witness_hash = self.header_hasher.hash(&witness_block.signed_header.header);
let witness_hash = self.hasher.hash_header(&witness_block.signed_header.header);

if primary_hash == witness_hash {
// Hashes match, continue with next witness, if any.
Expand Down
4 changes: 2 additions & 2 deletions light-client/src/operations.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Crypto function traits allowing mocking out during testing

pub mod header_hasher;
pub use self::header_hasher::*;
pub mod hasher;
pub use self::hasher::*;

pub mod voting_power;
pub use self::voting_power::*;
Expand Down
1 change: 1 addition & 0 deletions light-client/src/operations/commit_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl CommitValidator for ProdCommitValidator {
"no signatures for commit".to_string()
));
}

if signed_header.commit.signatures.len() != validator_set.validators().len() {
bail!(VerificationError::ImplementationSpecific(format!(
"pre-commit length: {} doesn't match validator length: {}",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
use crate::types::Header;
use crate::types::{Header, ValidatorSet};

use tendermint::amino_types::{message::AminoMessage, BlockId, ConsensusVersion, TimeMsg};
use tendermint::merkle::simple_hash_from_byte_vectors;
use tendermint::merkle;
use tendermint::Hash;

pub trait HeaderHasher: Send {
fn hash(&self, header: &Header) -> Hash; // Or Error?
pub trait Hasher: Send {
fn hash_header(&self, header: &Header) -> Hash;
fn hash_validator_set(&self, validator_set: &ValidatorSet) -> Hash;
}

#[derive(Copy, Clone, Debug)]
pub struct ProdHeaderHasher;
pub struct ProdHasher;

impl HeaderHasher for ProdHeaderHasher {
fn hash(&self, header: &Header) -> Hash {
impl Hasher for ProdHasher {
fn hash_header(&self, header: &Header) -> Hash {
amino_hash(header)
}

/// Compute the Merkle root of the validator set
fn hash_validator_set(&self, validator_set: &ValidatorSet) -> Hash {
let validator_bytes: Vec<Vec<u8>> = validator_set
.validators()
.iter()
.map(|validator| validator.hash_bytes())
.collect();

Hash::Sha256(merkle::simple_hash_from_byte_vectors(validator_bytes))
}
}

fn amino_hash(header: &Header) -> Hash {
Expand Down Expand Up @@ -51,7 +63,7 @@ fn amino_hash(header: &Header) -> Hash {
fields_bytes.push(header.evidence_hash.as_ref().map_or(vec![], encode_hash));
fields_bytes.push(bytes_enc(header.proposer_address.as_bytes()));

Hash::Sha256(simple_hash_from_byte_vectors(fields_bytes))
Hash::Sha256(merkle::simple_hash_from_byte_vectors(fields_bytes))
}

fn bytes_enc(bytes: &[u8]) -> Vec<u8> {
Expand Down
14 changes: 8 additions & 6 deletions light-client/src/operations/voting_power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use std::fmt;

use tendermint::block::CommitSig;
use tendermint::lite::types::TrustThreshold as _;
use tendermint::lite::types::ValidatorSet as _;
use tendermint::vote::{SignedVote, Vote};

#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
Expand All @@ -31,7 +30,14 @@ impl fmt::Display for VotingPowerTally {
}

pub trait VotingPowerCalculator: Send {
fn total_power_of(&self, validators: &ValidatorSet) -> u64;
fn total_power_of(&self, validator_set: &ValidatorSet) -> u64 {
validator_set
.validators()
.iter()
.fold(0u64, |total, val_info| {
total + val_info.voting_power.value()
})
}

fn check_enough_trust(
&self,
Expand Down Expand Up @@ -77,10 +83,6 @@ pub trait VotingPowerCalculator: Send {
pub struct ProdVotingPowerCalculator;

impl VotingPowerCalculator for ProdVotingPowerCalculator {
fn total_power_of(&self, validators: &ValidatorSet) -> u64 {
validators.total_power()
}

fn voting_power_in(
&self,
signed_header: &SignedHeader,
Expand Down
40 changes: 25 additions & 15 deletions light-client/src/predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@
use crate::{
ensure,
light_client::Options,
operations::{CommitValidator, HeaderHasher, VotingPowerCalculator},
operations::{CommitValidator, Hasher, VotingPowerCalculator},
types::{Header, Height, LightBlock, SignedHeader, Time, TrustThreshold, ValidatorSet},
};

use errors::VerificationError;
use std::time::Duration;
use tendermint::lite::ValidatorSet as _;

pub mod errors;

Expand All @@ -26,25 +25,36 @@ impl VerificationPredicates for ProdPredicates {}
/// This enables test implementations to only override a single method rather than
/// have to re-define every predicate.
pub trait VerificationPredicates: Send {
fn validator_sets_match(&self, light_block: &LightBlock) -> Result<(), VerificationError> {
fn validator_sets_match(
&self,
light_block: &LightBlock,
hasher: &dyn Hasher,
) -> Result<(), VerificationError> {
let validators_hash = hasher.hash_validator_set(&light_block.validators);

ensure!(
light_block.signed_header.header.validators_hash == light_block.validators.hash(),
light_block.signed_header.header.validators_hash == validators_hash,
VerificationError::InvalidValidatorSet {
header_validators_hash: light_block.signed_header.header.validators_hash,
validators_hash: light_block.validators.hash(),
validators_hash,
}
);

Ok(())
}

fn next_validators_match(&self, light_block: &LightBlock) -> Result<(), VerificationError> {
fn next_validators_match(
&self,
light_block: &LightBlock,
hasher: &dyn Hasher,
) -> Result<(), VerificationError> {
let next_validators_hash = hasher.hash_validator_set(&light_block.next_validators);

ensure!(
light_block.signed_header.header.next_validators_hash
== light_block.next_validators.hash(),
light_block.signed_header.header.next_validators_hash == next_validators_hash,
VerificationError::InvalidNextValidatorSet {
header_next_validators_hash: light_block.signed_header.header.next_validators_hash,
next_validators_hash: light_block.next_validators.hash(),
next_validators_hash: next_validators_hash
}
);

Expand All @@ -54,9 +64,9 @@ pub trait VerificationPredicates: Send {
fn header_matches_commit(
&self,
signed_header: &SignedHeader,
header_hasher: &dyn HeaderHasher,
hasher: &dyn Hasher,
) -> Result<(), VerificationError> {
let header_hash = header_hasher.hash(&signed_header.header);
let header_hash = hasher.hash_header(&signed_header.header);

ensure!(
header_hash == signed_header.commit.block_id.hash,
Expand Down Expand Up @@ -198,7 +208,7 @@ pub fn verify(
vp: &dyn VerificationPredicates,
voting_power_calculator: &dyn VotingPowerCalculator,
commit_validator: &dyn CommitValidator,
header_hasher: &dyn HeaderHasher,
hasher: &dyn Hasher,
trusted: &LightBlock,
untrusted: &LightBlock,
options: &Options,
Expand All @@ -212,13 +222,13 @@ pub fn verify(
)?;

// Ensure the header validator hashes match the given validators
vp.validator_sets_match(&untrusted)?;
vp.validator_sets_match(&untrusted, &*hasher)?;

// Ensure the header next validator hashes match the given next validators
vp.next_validators_match(&untrusted)?;
vp.next_validators_match(&untrusted, &*hasher)?;

// Ensure the header matches the commit
vp.header_matches_commit(&untrusted.signed_header, header_hasher)?;
vp.header_matches_commit(&untrusted.signed_header, hasher)?;

// Additional implementation specific validation
vp.valid_commit(
Expand Down

0 comments on commit 864bb4a

Please sign in to comment.