Skip to content

Commit

Permalink
Simplify some light client types and testing (#132)
Browse files Browse the repository at this point in the history
* Differentiate error from verify_commit_(trusting vs full)

 - use same names as in current spec

* Fix failing test :-)

* Refactoring and simplifications: param struct for TrustedState, SignedHeader

- as a result of parametrarizing `TrustedState<C, H>` and `SignedHeader<C, H>`
(instead of trait with assoc. types) a few things have to be (re)parametrarized and
other can be completely deleted as they are redundant and consumers can use the
param structs instead of the trait impls:
 - parametrarize Store<C, H> too
 - delete mocks: MockSignedHeader, MockState
 - delete impl for block::signed_header::SignedHeader
 - delete impl for lite::TrustedState in JSON tests
 - remove `State` and state.rs module from implementation completely
 - adapt params in verifier to match generic params of TrustedState & SignedHeader

- remove dep on block::Height by making lite::Height a u64 alias

* Remove obsolete TODO: we don't take a ref anymore

* some checked arithmetic for height

* type alias Mock types

* Add TrustThresholdFraction and a default for it

 - remove `DefaultTrustLevel` from tests
 - remove TrustThresholdOneThird and TrustThresholdTwoThirds from tendermint-lite
 (the latter was not used and the first duplicates the default impl)
 - use TrustThresholdFraction::default() instead

* remove obsolete clone

* remove unused lifetime (initially introduced to get rid of `clone`s
in constructor)

* improve doc

* remove TestSuite struct from JSON tests

* Add tests for TrustThresholdFraction

* add test-case for `is_within_trust_period` to increase test-coverage

* remove `votes_len` from commit; add a validate method to commit

- rename `validate_untrusted` -> `validate` which calls the new method on Commit
- simplify tests (`Option`s are not longer needed)
- move length matches check to impl of `validate`

* unexport `verify_single` and use `verify_and_update_single` in tests instead

- use MemStore of light crate in tests as a Mock

* type alias doesn't need to be `pub` here

* update doc comment and revert to making State  public in tendermint-lite

* Remove len & is_empty() from ValidatSet trait

* add some very simple unit tests for basic types

* update comments and move mock types into a mock module (only accessible in the super module)

 - mocks can be used in both types.rs and verifier.rs without decreasing codecov

* add missing #[cfg(test)] attribute (saves some compile time)

* remove store from inner recursion function

 - rename _verify_and_update_bisection -> verify_and_update_bisection_inner

* remove store from `verify_and_update_bisection` too

* rename some public methods of the verifier to be more aligned with the spec

- verify_and_update_single -> verify_single
- verify_and_update_bisection -> verify_bisection
- remove store from public facing functions

* make trust_level satisfy Copy + Clone and don't pass by reference

* refactor bisection to return a list of intermediate states (using memoization)

* use Vec instead of HashMap to memoize / return the interm. sates

* rename test helpers the assert_single_*

* WIP: quick first test for bisection

* WIP: add debug output to mocks & modify init_trusted_state to take next_vals too

* WIP: minor refactoring: intro method to ensure uniqueness in the returned states

* Add some comments and clean-up the code to be slightly more consistent for @Shivani912 to take over :-)

* fix accidentally broken test
  • Loading branch information
liamsi committed Feb 2, 2020
1 parent a02ffa5 commit d0e99f9
Show file tree
Hide file tree
Showing 14 changed files with 709 additions and 558 deletions.
2 changes: 0 additions & 2 deletions tendermint-lite/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
pub mod requester;
pub mod state;
pub mod store;
pub mod threshold;
46 changes: 21 additions & 25 deletions tendermint-lite/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
use tendermint::hash;
use tendermint::lite;
use tendermint::lite::Error;
use tendermint::lite::{
Header as _, Requester as _, SignedHeader as _, Store as _, TrustedState as _,
ValidatorSet as _,
};
use tendermint::lite::{Error, TrustThresholdFraction};
use tendermint::lite::{Header as _, Requester as _, Store as _, ValidatorSet as _};
use tendermint::rpc;
use tendermint::{block::Height, Hash};

use tendermint_lite::{
requester::RPCRequester, state::State, store::MemStore, threshold::TrustThresholdOneThird,
};
use tendermint_lite::{requester::RPCRequester, store::MemStore};

use core::future::Future;
use std::time::{Duration, SystemTime};
use tendermint_lite::store::State;
use tokio::runtime::Builder;

// TODO: these should be config/args
Expand All @@ -22,9 +18,6 @@ static SUBJECTIVE_VALS_HASH_HEX: &str =
"A5A7DEA707ADE6156F8A981777CA093F178FC790475F6EC659B6617E704871DD";
static RPC_ADDR: &str = "localhost:26657";

// TODO: this should somehow be configurable ...
static THRESHOLD: &TrustThresholdOneThird = &TrustThresholdOneThird {};

pub fn block_on<F: Future>(future: F) -> F::Output {
Builder::new()
.basic_scheduler()
Expand Down Expand Up @@ -52,7 +45,7 @@ fn main() {
let latest = (&req).signed_header(0).unwrap();
let latest_peer_height = latest.header().height();

let latest = store.get(Height::from(0)).unwrap();
let latest = store.get(0).unwrap();
let latest_height = latest.last_header().header().height();

// only bisect to higher heights
Expand All @@ -63,26 +56,29 @@ fn main() {

println!(
"attempting bisection from height {:?} to height {:?}",
store
.get(Height::from(0))
.unwrap()
.last_header()
.header()
.height(),
store.get(0).unwrap().last_header().header().height(),
latest_peer_height,
);

let now = &SystemTime::now();
lite::verify_and_update_bisection(
let trusted_state = store.get(0).expect("can not read trusted state");

let new_states = lite::verify_bisection(
trusted_state.clone(),
latest_peer_height,
THRESHOLD,
TrustThresholdFraction::default(),
&trusting_period,
now,
&req,
&mut store,
)
.unwrap();

for new_state in new_states {
store
.add(new_state)
.expect("couldn't store new trusted state");
}

println!("Succeeded bisecting!");

// notifications ?
Expand All @@ -106,13 +102,13 @@ fn subjective_init(
store: &mut MemStore,
req: &RPCRequester,
) -> Result<(), Error> {
if store.get(height).is_ok() {
if store.get(height.value()).is_ok() {
// we already have this !
return Ok(());
}

// check that the val hash matches
let vals = req.validator_set(height)?;
let vals = req.validator_set(height.value())?;

if vals.hash() != vals_hash {
// TODO
Expand All @@ -123,11 +119,11 @@ fn subjective_init(

// TODO: validate signed_header.commit() with the vals ...

let next_vals = req.validator_set(height.increment())?;
let next_vals = req.validator_set(height.increment().value())?;

// TODO: check next_vals ...

let trusted_state = &State::new(&signed_header, &next_vals);
let trusted_state = State::new(&signed_header, &next_vals);

store.add(trusted_state)?;

Expand Down
25 changes: 10 additions & 15 deletions tendermint-lite/src/requester.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use tendermint::block;
use tendermint::lite;
use tendermint::block::signed_header::SignedHeader as TMCommit;
use tendermint::block::Header as TMHeader;
use tendermint::rpc;
use tendermint::validator;
use tendermint::{block, lite};

use core::future::Future;
use tendermint::lite::{Height, SignedHeader};
use tendermint::validator::Set;
use tokio::runtime::Builder;

/// RPCRequester wraps the Tendermint rpc::Client.
Expand All @@ -17,33 +20,26 @@ impl RPCRequester {
}
}

impl lite::types::Requester for RPCRequester {
type SignedHeader = block::signed_header::SignedHeader;
type ValidatorSet = validator::Set;
type TMSignedHeader = SignedHeader<TMCommit, TMHeader>;

impl lite::types::Requester<TMCommit, TMHeader> for RPCRequester {
/// Request the signed header at height h.
/// If h==0, request the latest signed header.
/// TODO: use an enum instead of h==0.
fn signed_header<H>(&self, h: H) -> Result<Self::SignedHeader, lite::Error>
where
H: Into<block::Height>,
{
fn signed_header(&self, h: Height) -> Result<TMSignedHeader, lite::Error> {
let height: block::Height = h.into();
let r = match height.value() {
0 => block_on(self.client.latest_commit()),
_ => block_on(self.client.commit(height)),
};
match r {
Ok(response) => Ok(response.signed_header),
Ok(response) => Ok(response.signed_header.into()),
Err(_error) => Err(lite::Error::RequestFailed),
}
}

/// Request the validator set at height h.
fn validator_set<H>(&self, h: H) -> Result<Self::ValidatorSet, lite::Error>
where
H: Into<block::Height>,
{
fn validator_set(&self, h: Height) -> Result<Set, lite::Error> {
let r = block_on(self.client.validators(h));
match r {
Ok(response) => Ok(validator::Set::new(response.validators)),
Expand All @@ -66,7 +62,6 @@ mod tests {
use super::*;
use tendermint::lite::types::Header as LiteHeader;
use tendermint::lite::types::Requester as LiteRequester;
use tendermint::lite::types::SignedHeader as LiteSignedHeader;
use tendermint::lite::types::ValidatorSet as LiteValSet;
use tendermint::rpc;

Expand Down
30 changes: 0 additions & 30 deletions tendermint-lite/src/state.rs

This file was deleted.

21 changes: 10 additions & 11 deletions tendermint-lite/src/store.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::state::State;
use tendermint::block::Height;
use tendermint::lite::{Error, Header, SignedHeader, Store, TrustedState};
use tendermint::lite::{Error, Header, Height, Store, TrustedState};

use std::collections::HashMap;
use tendermint::block;

pub type State = TrustedState<block::signed_header::SignedHeader, block::header::Header>;

#[derive(Default)]
pub struct MemStore {
Expand All @@ -13,25 +14,23 @@ pub struct MemStore {
impl MemStore {
pub fn new() -> MemStore {
MemStore {
height: Height::from(0),
height: 0,
store: HashMap::new(),
}
}
}

impl Store for MemStore {
type TrustedState = State;

fn add(&mut self, trusted: &Self::TrustedState) -> Result<(), Error> {
impl Store<block::signed_header::SignedHeader, block::header::Header> for MemStore {
fn add(&mut self, trusted: State) -> Result<(), Error> {
let height = trusted.last_header().header().height();
self.height = height;
self.store.insert(height, trusted.clone());
self.store.insert(height, trusted);
Ok(())
}

fn get(&self, h: Height) -> Result<&Self::TrustedState, Error> {
fn get(&self, h: Height) -> Result<&State, Error> {
let mut height = h;
if h.value() == 0 {
if h == 0 {
height = self.height
}
match self.store.get(&height) {
Expand Down
11 changes: 0 additions & 11 deletions tendermint-lite/src/threshold.rs

This file was deleted.

2 changes: 2 additions & 0 deletions tendermint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ zeroize = { version = "1.1", features = ["zeroize_derive"] }
[dev-dependencies]
serde_json = "1"
tokio = "0.2"
# Note: used in tests only:
tendermint-lite = {path = "../tendermint-lite"}
6 changes: 1 addition & 5 deletions tendermint/src/lite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@ pub mod verifier;

pub use self::types::*;

// TODO: don't expose this once the json tests
// switch to using one of the other functions
pub use self::verifier::verify_single;

pub use self::verifier::{verify_and_update_bisection, verify_and_update_single};
pub use self::verifier::{verify_bisection, verify_single};
Loading

0 comments on commit d0e99f9

Please sign in to comment.