Skip to content

Commit

Permalink
Consolidate and delete old implementation of the light client (#500)
Browse files Browse the repository at this point in the history
* Rip out outdated lite and lite_impl modules from tendermint crate

* Move light client test fixtures to light-client crate

* Fix deserialization for LatestStatus

* Update changelog

* Formatting

* Remove outdated comment

* Re-order derived traits

Co-authored-by: Alexander Simmerl <a.simmerl@gmail.com>

Co-authored-by: Alexander Simmerl <a.simmerl@gmail.com>
  • Loading branch information
romac and xla authored Aug 5, 2020
1 parent 99e8b9d commit 5e29872
Show file tree
Hide file tree
Showing 87 changed files with 220 additions and 2,340 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

- Add missing documentation to all items ([#472])
- Add major contributors as authors of the `light-client`, `light-node`, and `rpc` crate ([#472])
- Remove and consolidate deprecated [lite] and [lite_impl] modules from the `tendermint` crate ([#500])

[#472]: https://github.com/informalsystems/tendermint-rs/pull/472
[lite_impl]: https://github.com/informalsystems/tendermint-rs/tree/master/tendermint/src/lite_impl

## [0.15.0] (2020-07-17)

Expand Down
6 changes: 3 additions & 3 deletions light-client/src/components/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ pub enum AtHeight {

impl From<Height> for AtHeight {
fn from(height: Height) -> Self {
if height == 0 {
if height.value() == 0 {
Self::Highest
} else {
Self::At(height)
Expand Down Expand Up @@ -93,10 +93,10 @@ pub struct ProdIo {
impl Io for ProdIo {
fn fetch_light_block(&self, peer: PeerId, height: AtHeight) -> Result<LightBlock, IoError> {
let signed_header = self.fetch_signed_header(peer, height)?;
let height: Height = signed_header.header.height.into();
let height = signed_header.header.height;

let validator_set = self.fetch_validator_set(peer, height.into())?;
let next_validator_set = self.fetch_validator_set(peer, (height + 1).into())?;
let next_validator_set = self.fetch_validator_set(peer, height.increment().into())?;

let light_block = LightBlock::new(signed_header, validator_set, next_validator_set, peer);

Expand Down
2 changes: 1 addition & 1 deletion light-client/src/components/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,5 @@ pub fn valid_schedule(
#[pre(low <= high)]
#[post(low <= ret && ret <= high)]
fn midpoint(low: Height, high: Height) -> Height {
low + (high + 1 - low) / 2
(low.value() + (high.value() + 1 - low.value()) / 2).into()
}
8 changes: 4 additions & 4 deletions light-client/src/components/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,10 @@ impl ProdVerifier {
impl Default for ProdVerifier {
fn default() -> Self {
Self::new(
ProdPredicates,
ProdVotingPowerCalculator,
ProdCommitValidator,
ProdHasher,
ProdPredicates::default(),
ProdVotingPowerCalculator::default(),
ProdCommitValidator::default(),
ProdHasher::default(),
)
}
}
Expand Down
25 changes: 21 additions & 4 deletions light-client/src/operations/commit_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

use crate::{
bail,
operations::{Hasher, ProdHasher},
predicates::errors::VerificationError,
types::{SignedHeader, ValidatorSet},
};

use tendermint::block::CommitSig;
use tendermint::lite::types::ValidatorSet as _;

/// Validates the commit associated with a header against a validator set
pub trait CommitValidator: Send {
Expand All @@ -27,8 +27,25 @@ pub trait CommitValidator: Send {
}

/// Production-ready implementation of a commit validator
#[derive(Copy, Clone)]
pub struct ProdCommitValidator;
pub struct ProdCommitValidator {
hasher: Box<dyn Hasher>,
}

impl ProdCommitValidator {
/// Create a new commit validator using the given [`Hasher`]
/// to compute the hash of headers and validator sets.
pub fn new(hasher: impl Hasher + 'static) -> Self {
Self {
hasher: Box::new(hasher),
}
}
}

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

impl CommitValidator for ProdCommitValidator {
fn validate(
Expand Down Expand Up @@ -81,7 +98,7 @@ impl CommitValidator for ProdCommitValidator {
bail!(VerificationError::ImplementationSpecific(format!(
"Found a faulty signer ({}) not present in the validator set ({})",
validator_address,
validator_set.hash()
self.hasher.hash_validator_set(validator_set)
)));
}
}
Expand Down
6 changes: 2 additions & 4 deletions light-client/src/operations/hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

use crate::types::{Header, ValidatorSet};

use tendermint::lite::types::Header as _;
use tendermint::merkle;
use tendermint::Hash;
use tendermint::{merkle, Hash};

/// Hashing for headers and validator sets
pub trait Hasher: Send {
Expand All @@ -16,7 +14,7 @@ pub trait Hasher: Send {
}

/// Default implementation of a hasher
#[derive(Copy, Clone, Debug)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ProdHasher;

impl Hasher for ProdHasher {
Expand Down
2 changes: 1 addition & 1 deletion light-client/src/operations/voting_power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::collections::HashSet;
use std::fmt;

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

/// Tally for the voting power computed by the `VotingPowerCalculator`
Expand Down
12 changes: 6 additions & 6 deletions light-client/src/predicates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
ensure,
light_client::Options,
operations::{CommitValidator, Hasher, VotingPowerCalculator},
types::{Header, Height, LightBlock, SignedHeader, Time, TrustThreshold, ValidatorSet},
types::{Header, LightBlock, SignedHeader, Time, TrustThreshold, ValidatorSet},
};

use errors::VerificationError;
Expand All @@ -14,7 +14,7 @@ pub mod errors;

/// Production predicates, using the default implementation
/// of the `VerificationPredicates` trait.
#[derive(Copy, Clone, Debug)]
#[derive(Clone, Copy, Debug, Default)]
pub struct ProdPredicates;
impl VerificationPredicates for ProdPredicates {}

Expand Down Expand Up @@ -152,13 +152,13 @@ pub trait VerificationPredicates: Send {
untrusted_header: &Header,
trusted_header: &Header,
) -> Result<(), VerificationError> {
let trusted_height: Height = trusted_header.height.into();
let trusted_height = trusted_header.height;

ensure!(
untrusted_header.height > trusted_header.height,
VerificationError::NonIncreasingHeight {
got: untrusted_header.height.into(),
expected: trusted_height + 1,
got: untrusted_header.height,
expected: trusted_height.increment(),
}
);

Expand Down Expand Up @@ -260,7 +260,7 @@ pub fn verify(
&trusted.signed_header.header,
)?;

let trusted_next_height = trusted.height().checked_add(1).expect("height overflow");
let trusted_next_height = trusted.height().increment();

if untrusted.height() == trusted_next_height {
// If the untrusted block is the very next block after the trusted block,
Expand Down
3 changes: 1 addition & 2 deletions light-client/src/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use crate::light_client::LightClient;
use crate::peer_list::PeerList;
use crate::state::State;
use crate::types::{Height, LatestStatus, LightBlock, PeerId, Status};
use tendermint::lite::{Header, ValidatorSet};

/// Provides an interface to the supervisor for use in downstream code.
pub trait Handle {
Expand Down Expand Up @@ -189,7 +188,7 @@ impl Supervisor {

match latest_trusted {
Some(trusted) => LatestStatus::new(
Some(trusted.signed_header.header.height()),
Some(trusted.signed_header.header.height.value()),
Some(trusted.signed_header.header.hash()),
Some(trusted.next_validators.hash()),
connected_nodes,
Expand Down
12 changes: 6 additions & 6 deletions light-client/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ use tendermint::{
header::Header as TMHeader, signed_header::SignedHeader as TMSignedHeader,
Commit as TMCommit,
},
lite::TrustThresholdFraction,
trust_threshold::TrustThresholdFraction,
validator::Info as TMValidatorInfo,
validator::Set as TMValidatorSet,
};

pub use tendermint::{hash::Hash, lite::Height, time::Time};
pub use tendermint::{block::Height, hash::Hash, time::Time};

/// Peer ID (public key) of a full node
pub type PeerId = tendermint::node::Id;
Expand Down Expand Up @@ -113,9 +113,9 @@ impl LightBlock {
/// Returns the height of this block.
///
/// ## Note
/// This is a shorthand for `block.signed_header.header.height.into()`.
/// This is a shorthand for `block.signed_header.header.height`.
pub fn height(&self) -> Height {
self.signed_header.header.height.into()
self.signed_header.header.height
}
}

Expand All @@ -125,7 +125,7 @@ impl LightBlock {
#[display(fmt = "{:?}", self)]
pub struct LatestStatus {
/// The latest height we are trusting.
pub height: Option<Height>,
pub height: Option<u64>,
/// The latest block hash we are trusting.
pub block_hash: Option<Hash>,
/// The latest validator set we are trusting.
Expand All @@ -143,7 +143,7 @@ impl LatestStatus {
valset_hash: Option<Hash>,
connected_nodes: Vec<PeerId>,
) -> Self {
LatestStatus {
Self {
height,
block_hash,
valset_hash,
Expand Down
10 changes: 5 additions & 5 deletions light-client/tests/light_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,19 +247,19 @@ fn run_bisection_tests(dir: &str) {
/// the bisection test as normal. We then assert that we get the expected error.
fn run_bisection_lower_tests(dir: &str) {
foreach_bisection_test(dir, |file, mut tc| {
let mut trusted_height: Height = tc.trust_options.height.into();
let mut trusted_height = tc.trust_options.height;

if trusted_height <= 1 {
tc.trust_options.height = (trusted_height + 1).into();
trusted_height += 1;
if trusted_height.value() <= 1 {
tc.trust_options.height = trusted_height.increment();
trusted_height = trusted_height.increment();
}

println!(
"Running light client against bisection test file with target height too low: {}",
file
);

tc.height_to_verify = (trusted_height - 1).into();
tc.height_to_verify = (trusted_height.value() - 1).into();

let test_result = run_bisection_test(tc);
match test_result.new_states {
Expand Down
2 changes: 1 addition & 1 deletion light-client/tests/supervisor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn load_multi_peer_testcases(dir: &str) -> Vec<TestBisection<LightBlock>> {
}

fn make_instance(peer_id: PeerId, trust_options: TrustOptions, io: MockIo, now: Time) -> Instance {
let trusted_height = trust_options.height.value();
let trusted_height = trust_options.height;
let trusted_state = io
.fetch_light_block(peer_id, AtHeight::At(trusted_height))
.expect("could not 'request' light block");
Expand Down
1 change: 0 additions & 1 deletion light-client/tests/support

This file was deleted.

10 changes: 4 additions & 6 deletions light-node/src/commands/initialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,14 @@ use abscissa_core::Command;
use abscissa_core::Options;
use abscissa_core::Runnable;

use tendermint::hash;
use tendermint::lite::Header;
use tendermint::Hash;
use tendermint::{hash, Hash};

use tendermint_light_client::components::io::{AtHeight, Io, ProdIo};
use tendermint_light_client::operations::ProdHasher;
use tendermint_light_client::predicates::{ProdPredicates, VerificationPredicates};
use tendermint_light_client::store::sled::SledStore;
use tendermint_light_client::store::LightStore;
use tendermint_light_client::types::Status;
use tendermint_light_client::types::{Height, Status};

/// `initialize` subcommand
#[derive(Command, Debug, Default, Options)]
Expand Down Expand Up @@ -51,7 +49,7 @@ impl Runnable for InitCmd {

let io = ProdIo::new(peer_map, Some(app_cfg.rpc_config.request_timeout));

initialize_subjectively(self.height, subjective_header_hash, &lc, &io);
initialize_subjectively(self.height.into(), subjective_header_hash, &lc, &io);
}
}

Expand All @@ -60,7 +58,7 @@ impl Runnable for InitCmd {
// TODO(ismail): additionally here and everywhere else, we should return errors
// instead of std::process::exit because no destructors will be run.
fn initialize_subjectively(
height: u64,
height: Height,
subjective_header_hash: Hash,
l_conf: &LightClientConfig,
io: &ProdIo,
Expand Down
1 change: 0 additions & 1 deletion rpc/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
mod endpoints {
use std::{fs, path::PathBuf};
use tendermint::abci::Code;
use tendermint::lite::Header;

use tendermint_rpc::{self as rpc, endpoint, Response};

Expand Down
58 changes: 58 additions & 0 deletions tendermint/src/block/header.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Block headers

use crate::amino_types::{message::AminoMessage, BlockId, ConsensusVersion, TimeMsg};
use crate::merkle::simple_hash_from_byte_vectors;
use crate::serializers;
use crate::{account, block, chain, Hash, Time};
use serde::{Deserialize, Serialize};
Expand Down Expand Up @@ -60,6 +62,62 @@ pub struct Header {
pub proposer_address: account::Id,
}

impl Header {
/// Hash this header
pub fn hash(&self) -> Hash {
// Note that if there is an encoding problem this will
// panic (as the golang code would):
// https://github.com/tendermint/tendermint/blob/134fe2896275bb926b49743c1e25493f6b24cc31/types/block.go#L393
// https://github.com/tendermint/tendermint/blob/134fe2896275bb926b49743c1e25493f6b24cc31/types/encoding_helper.go#L9:6

let mut fields_bytes: Vec<Vec<u8>> = Vec::with_capacity(16);
fields_bytes.push(AminoMessage::bytes_vec(&ConsensusVersion::from(
&self.version,
)));
fields_bytes.push(encode_bytes(self.chain_id.as_bytes()));
fields_bytes.push(encode_varint(self.height.value()));
fields_bytes.push(AminoMessage::bytes_vec(&TimeMsg::from(self.time)));
fields_bytes.push(
self.last_block_id
.as_ref()
.map_or(vec![], |id| AminoMessage::bytes_vec(&BlockId::from(id))),
);
fields_bytes.push(self.last_commit_hash.as_ref().map_or(vec![], encode_hash));
fields_bytes.push(self.data_hash.as_ref().map_or(vec![], encode_hash));
fields_bytes.push(encode_hash(&self.validators_hash));
fields_bytes.push(encode_hash(&self.next_validators_hash));
fields_bytes.push(encode_hash(&self.consensus_hash));
fields_bytes.push(encode_bytes(&self.app_hash));
fields_bytes.push(self.last_results_hash.as_ref().map_or(vec![], encode_hash));
fields_bytes.push(self.evidence_hash.as_ref().map_or(vec![], encode_hash));
fields_bytes.push(encode_bytes(self.proposer_address.as_bytes()));

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

fn encode_bytes(bytes: &[u8]) -> Vec<u8> {
let bytes_len = bytes.len();
if bytes_len > 0 {
let mut encoded = vec![];
prost_amino::encode_length_delimiter(bytes_len, &mut encoded).unwrap();
encoded.append(&mut bytes.to_vec());
encoded
} else {
vec![]
}
}

fn encode_hash(hash: &Hash) -> Vec<u8> {
encode_bytes(hash.as_bytes())
}

fn encode_varint(val: u64) -> Vec<u8> {
let mut val_enc = vec![];
prost_amino::encoding::encode_varint(val, &mut val_enc);
val_enc
}

/// `Version` contains the protocol version for the blockchain and the
/// application.
///
Expand Down
Loading

0 comments on commit 5e29872

Please sign in to comment.