Skip to content

Commit

Permalink
Merge branch 'master' into empty-block-id-in-vote
Browse files Browse the repository at this point in the history
  • Loading branch information
liamsi authored Jan 10, 2020
2 parents bd8eea7 + ede8a9d commit 7cc70f7
Show file tree
Hide file tree
Showing 28 changed files with 1,372 additions and 363 deletions.
12 changes: 12 additions & 0 deletions .rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
unstable_features = true

# comments
comment_width = 100
wrap_comments = true

# imports
reorder_imports = true

# strings
format_strings = false
max_width = 100
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

members = [
"tendermint",
"tendermint-lite",
]
11 changes: 11 additions & 0 deletions tendermint-lite/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "tendermint-lite"
version = "0.1.0"
authors = ["Ethan Buchman <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
tendermint = { path = "../tendermint" }
tokio = "0.2"
4 changes: 4 additions & 0 deletions tendermint-lite/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod requester;
pub mod state;
pub mod store;
pub mod threshold;
135 changes: 135 additions & 0 deletions tendermint-lite/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
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::rpc;
use tendermint::{block::Height, Hash};

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

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

// TODO: these should be config/args
static SUBJECTIVE_HEIGHT: u64 = 1;
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()
.enable_all()
.build()
.unwrap()
.block_on(future)
}

fn main() {
// TODO: this should be config
let trusting_period = Duration::new(6000, 0);

// setup requester for primary peer
let client = block_on(rpc::Client::new(&RPC_ADDR.parse().unwrap())).unwrap();
let req = RPCRequester::new(client);
let mut store = MemStore::new();

let vals_hash =
Hash::from_hex_upper(hash::Algorithm::Sha256, SUBJECTIVE_VALS_HASH_HEX).unwrap();

subjective_init(Height::from(SUBJECTIVE_HEIGHT), vals_hash, &mut store, &req).unwrap();

loop {
let latest = (&req).signed_header(0).unwrap();
let latest_peer_height = latest.header().height();

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

// only bisect to higher heights
if latest_peer_height <= latest_height {
std::thread::sleep(Duration::new(1, 0));
continue;
}

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

let now = &SystemTime::now();
lite::verify_and_update_bisection(
latest_peer_height,
THRESHOLD,
&trusting_period,
now,
&req,
&mut store,
)
.unwrap();

println!("Succeeded bisecting!");

// notifications ?

// sleep for a few secs ?
}
}

/*
* The following is initialization logic that should have a
* function in the lite crate like:
* `subjective_init(height, vals_hash, store, requester) -> Result<(), Error`
* it would fetch the initial header/vals from the requester and populate a
* trusted state and store it in the store ...
* TODO: this should take traits ... but how to deal with the State ?
* TODO: better name ?
*/
fn subjective_init(
height: Height,
vals_hash: Hash,
store: &mut MemStore,
req: &RPCRequester,
) -> Result<(), Error> {
if store.get(height).is_ok() {
// we already have this !
return Ok(());
}

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

if vals.hash() != vals_hash {
// TODO
panic!("vals hash dont match")
}

let signed_header = req.signed_header(SUBJECTIVE_HEIGHT)?;

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

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

// TODO: check next_vals ...

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

store.add(trusted_state)?;

Ok(())
}
83 changes: 83 additions & 0 deletions tendermint-lite/src/requester.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
use tendermint::block;
use tendermint::lite;
use tendermint::rpc;
use tendermint::validator;

use core::future::Future;
use tokio::runtime::Builder;

/// RPCRequester wraps the Tendermint rpc::Client.
pub struct RPCRequester {
client: rpc::Client,
}

impl RPCRequester {
pub fn new(client: rpc::Client) -> Self {
RPCRequester { client }
}
}

impl lite::types::Requester for RPCRequester {
type SignedHeader = block::signed_header::SignedHeader;
type ValidatorSet = validator::Set;

/// 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>,
{
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),
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>,
{
let r = block_on(self.client.validators(h));
match r {
Ok(response) => Ok(validator::Set::new(response.validators)),
Err(_error) => Err(lite::Error::RequestFailed),
}
}
}

pub fn block_on<F: Future>(future: F) -> F::Output {
Builder::new()
.basic_scheduler()
.enable_all()
.build()
.unwrap()
.block_on(future)
}

#[cfg(test)]
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;

// TODO: integration test
#[test]
#[ignore]
fn test_val_set() {
let client = block_on(rpc::Client::new(&"localhost:26657".parse().unwrap())).unwrap();
let req = RPCRequester::new(client);
let r1 = req.validator_set(5).unwrap();
let r2 = req.signed_header(5).unwrap();
assert_eq!(r1.hash(), r2.header().validators_hash());
}
}
30 changes: 30 additions & 0 deletions tendermint-lite/src/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use tendermint::lite::TrustedState;
use tendermint::{block::signed_header::SignedHeader, validator::Set};

#[derive(Clone)]
pub struct State {
last_header: SignedHeader,
vals: Set,
}

impl TrustedState for State {
type LastHeader = SignedHeader;
type ValidatorSet = Set;

fn new(last_header: &Self::LastHeader, vals: &Self::ValidatorSet) -> Self {
State {
last_header: last_header.clone(),
vals: vals.clone(),
}
}

// height H-1
fn last_header(&self) -> &Self::LastHeader {
&self.last_header
}

// height H
fn validators(&self) -> &Self::ValidatorSet {
&self.vals
}
}
42 changes: 42 additions & 0 deletions tendermint-lite/src/store.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use crate::state::State;
use tendermint::block::Height;
use tendermint::lite::{Error, Header, SignedHeader, Store, TrustedState};

use std::collections::HashMap;

#[derive(Default)]
pub struct MemStore {
height: Height,
store: HashMap<Height, State>,
}

impl MemStore {
pub fn new() -> MemStore {
MemStore {
height: Height::from(0),
store: HashMap::new(),
}
}
}

impl Store for MemStore {
type TrustedState = State;

fn add(&mut self, trusted: &Self::TrustedState) -> Result<(), Error> {
let height = trusted.last_header().header().height();
self.height = height;
self.store.insert(height, trusted.clone());
Ok(())
}

fn get(&self, h: Height) -> Result<&Self::TrustedState, Error> {
let mut height = h;
if h.value() == 0 {
height = self.height
}
match self.store.get(&height) {
Some(state) => Ok(state),
None => Err(Error::RequestFailed),
}
}
}
11 changes: 11 additions & 0 deletions tendermint-lite/src/threshold.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use tendermint::lite::TrustThreshold;

pub struct TrustThresholdOneThird {}
impl TrustThreshold for TrustThresholdOneThird {}

pub struct TrustThresholdTwoThirds {}
impl TrustThreshold for TrustThresholdTwoThirds {
fn is_enough_power(&self, signed_voting_power: u64, total_voting_power: u64) -> bool {
signed_voting_power * 3 > total_voting_power * 2
}
}
3 changes: 2 additions & 1 deletion tendermint/src/amino_types/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ mod tests {
// var pubKey [32]byte
// copy(pubKey[:],[]byte{0x79, 0xce, 0xd, 0xe0, 0x43, 0x33, 0x4a, 0xec, 0xe0, 0x8b, 0x7b,
// 0xb5, 0x61, 0xbc, 0xe7, 0xc1,
// 0xd4, 0x69, 0xc3, 0x44, 0x26, 0xec, 0xef, 0xc0, 0x72, 0xa, 0x52, 0x4d, 0x37, 0x32, 0xef, 0xed})
// 0xd4, 0x69, 0xc3, 0x44, 0x26, 0xec, 0xef, 0xc0, 0x72, 0xa, 0x52, 0x4d, 0x37, 0x32, 0xef,
// 0xed})
//
// b, _ = cdc.MarshalBinary(&privval.PubKeyResponse{PubKey: crypto.PubKeyEd25519(pubKey)})
// fmt.Printf("%#v\n\n", b)
Expand Down
7 changes: 4 additions & 3 deletions tendermint/src/amino_types/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ pub struct SignProposalRequest {
#[derive(Clone, PartialEq, Message)]
struct CanonicalProposal {
#[prost(uint32, tag = "1")]
msg_type: u32, // this is a byte in golang, which is a varint encoded UInt8 (using amino's EncodeUvarint)
msg_type: u32, /* this is a byte in golang, which is a varint encoded UInt8 (using amino's
* EncodeUvarint) */
#[prost(sfixed64)]
height: i64,
#[prost(sfixed64)]
Expand Down Expand Up @@ -228,8 +229,8 @@ mod tests {
// cdc := amino.NewCodec()
// privval.RegisterRemoteSignerMsg(cdc)
// stamp, _ := time.Parse(time.RFC3339Nano, "2018-02-11T07:09:22.765Z")
// data, _ := cdc.MarshalBinaryLengthPrefixed(privval.SignProposalRequest{Proposal: &types.Proposal{
// Type: types.ProposalType, // 0x20
// data, _ := cdc.MarshalBinaryLengthPrefixed(privval.SignProposalRequest{Proposal:
// &types.Proposal{ Type: types.ProposalType, // 0x20
// Height: 12345,
// Round: 23456,
// POLRound: -1,
Expand Down
11 changes: 7 additions & 4 deletions tendermint/src/amino_types/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,10 @@ mod tests {
],
validator_index: 56789,
signature: vec![],
//signature: vec![130u8, 246, 183, 50, 153, 248, 28, 57, 51, 142, 55, 217, 194, 24, 134, 212, 233, 100, 211, 10, 24, 174, 179, 117, 41, 65, 141, 134, 149, 239, 65, 174, 217, 42, 6, 184, 112, 17, 7, 97, 255, 221, 252, 16, 60, 144, 30, 212, 167, 39, 67, 35, 118, 192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10],
/* signature: vec![130u8, 246, 183, 50, 153, 248, 28, 57, 51, 142, 55, 217, 194, 24,
* 134, 212, 233, 100, 211, 10, 24, 174, 179, 117, 41, 65, 141, 134, 149, 239, 65,
* 174, 217, 42, 6, 184, 112, 17, 7, 97, 255, 221, 252, 16, 60, 144, 30, 212, 167,
* 39, 67, 35, 118, 192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10], */
};
let sign_vote_msg = SignVoteRequest { vote: Some(vote) };
let mut got = vec![];
Expand All @@ -292,9 +295,9 @@ mod tests {
// Hash: []byte("parts_hash"),
// },
// },
// ValidatorAddress: []byte{0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21, 0xf2, 0x48, 0x2a, 0xf4, 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35},
// ValidatorIndex: 56789,
// }})
// ValidatorAddress: []byte{0xa3, 0xb2, 0xcc, 0xdd, 0x71, 0x86, 0xf1, 0x68, 0x5f, 0x21,
// 0xf2, 0x48, 0x2a, 0xf4, 0xfb, 0x34, 0x46, 0xa8, 0x4b, 0x35}, ValidatorIndex:
// 56789, }})
// fmt.Println(strings.Join(strings.Split(fmt.Sprintf("%v",data), " "), ", "))

let want = vec![
Expand Down
Loading

0 comments on commit 7cc70f7

Please sign in to comment.