Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Light client: further trait impls, improvements, and tests #84

Merged
merged 32 commits into from
Dec 16, 2019
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8604b57
merge in changes of #59 and simplify Header::hash
liamsi Nov 9, 2019
4070a59
Create a trait for with a blanket impl instead of new type
liamsi Nov 11, 2019
e128044
impl lite::Commit for commit::SignedHeader
yihuang Nov 13, 2019
8d150b4
Modify lite::Commit impl for SignedHeader to not include amino dep:
liamsi Nov 13, 2019
189f582
impl lite::ValidatorSetLookup
yihuang Nov 13, 2019
f6c8775
Add a few methods to tests and deduplicate code for fn hash of
liamsi Nov 13, 2019
3ea3dc4
Signing bytes need to encoded with encode_length_delimited
yihuang Nov 18, 2019
0946487
Represent optional hash and block id as Option
yihuang Nov 13, 2019
d3b632b
add mock testing for lite client
yihuang Nov 19, 2019
b3a790f
parse empty commit
yihuang Nov 25, 2019
b410066
utilities
yihuang Nov 13, 2019
6999382
Add TrustLevel as a trait; default behaviour is as before:
liamsi Dec 8, 2019
013e94b
minor clarifications: updated comments and clarified test-name
liamsi Dec 8, 2019
4593061
Add a verify method which is closer to the spec / the current golang …
liamsi Dec 9, 2019
55d91ff
remove unused unit return type
liamsi Dec 9, 2019
b9c419a
add `/validators` to rpc client
liamsi Dec 9, 2019
bd08d62
remove associated type (Vote) from SignedHeader
liamsi Dec 9, 2019
b6543c0
Fix a few minor issues from rebasing
liamsi Dec 10, 2019
904f9aa
make method for retrieving validators in rpc client async too
liamsi Dec 12, 2019
035df2b
rename byteslices -> fields_bytes
liamsi Dec 12, 2019
3d49482
Incorporate review comments, more tests, some renaming:
liamsi Dec 12, 2019
458b988
Refactor trait types to be slightly closer to the spec:
liamsi Dec 12, 2019
e6c3b15
Remove into_vec methods from Commit & ValidatorSet trait:
liamsi Dec 12, 2019
f3bdc3d
Add in a correctly formed (but invalid) hash instead of `[]byte("wron…
liamsi Dec 13, 2019
eeb5479
use associated types for SignedHeader instead of generics
liamsi Dec 13, 2019
a21a170
Remove dependency on tendermint's time implementation (use SystemTime…
liamsi Dec 13, 2019
443cf6a
Be closer to the current spec (and less confusing hopefully):
liamsi Dec 15, 2019
2f90679
Minor improvements on light client test:
liamsi Dec 16, 2019
a855701
From review: fix some comments (typo & stale comment)
liamsi Dec 16, 2019
d907da6
Remove lite::Vote altogether
liamsi Dec 16, 2019
71d2808
Optimize validator lookup: find() then clone() only clones the found …
liamsi Dec 16, 2019
5891bae
moved SignedHeader struct from `rpc::endpoint` to `block::signed_header`
liamsi Dec 16, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions tendermint/src/amino_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

pub mod block_id;
pub mod ed25519;
pub mod message;
pub mod ping;
pub mod proposal;
pub mod remote_error;
Expand Down
12 changes: 6 additions & 6 deletions tendermint/src/amino_types/block_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ impl block::ParseId for BlockId {

impl From<&block::Id> for BlockId {
fn from(bid: &block::Id) -> Self {
let bid_hash = bid.hash.as_bytes().unwrap().to_vec();
match &bid.parts {
Some(parts) => BlockId::new(bid_hash, Some(PartsSetHeader::from(parts))),
None => BlockId::new(bid_hash, None),
}
let bid_hash = bid.hash.as_bytes();
BlockId::new(
bid_hash.to_vec(),
bid.parts.as_ref().map(PartsSetHeader::from),
)
}
}

Expand Down Expand Up @@ -89,7 +89,7 @@ impl PartsSetHeader {

impl From<&parts::Header> for PartsSetHeader {
fn from(parts: &parts::Header) -> Self {
PartsSetHeader::new(parts.total as i64, parts.hash.as_bytes().unwrap().to_vec())
PartsSetHeader::new(parts.total as i64, parts.hash.as_bytes().to_vec())
}
}

Expand Down
39 changes: 39 additions & 0 deletions tendermint/src/amino_types/message.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use prost_amino::encoding::encoded_len_varint;
use std::convert::TryInto;

/// Extend the original prost::Message trait with a few helper functions in order to
/// reduce boiler-plate code (and without modifying the prost-amino dependency).
pub trait AminoMessage: prost_amino::Message {
/// Directly amino encode a prost-amino message into a freshly created Vec<u8>.
/// This can be useful when passing those bytes directly to a hasher, or,
/// to reduce boiler plate code when working with the encoded bytes.
///
/// Warning: Only use this method, if you are in control what will be encoded.
/// If there is an encoding error, this method will panic.
fn bytes_vec(&self) -> Vec<u8>
where
Self: Sized,
{
let mut res = Vec::with_capacity(self.encoded_len());
self.encode(&mut res).unwrap();
res
}

/// Encode prost-amino message as length delimited.
///
/// Warning: Only use this method, if you are in control what will be encoded.
/// If there is an encoding error, this method will panic.
fn bytes_vec_length_delimited(&self) -> Vec<u8>
where
Self: Sized,
{
let len = self.encoded_len();
let mut res =
Vec::with_capacity(len + encoded_len_varint(len.try_into().expect("length overflow")));
self.encode_length_delimited(&mut res).unwrap();
res
}
}
impl<M: prost_amino::Message> AminoMessage for M {
// blanket impl
}
26 changes: 8 additions & 18 deletions tendermint/src/amino_types/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
block::{self, ParseId},
chain, consensus,
error::Error,
vote, Hash,
vote,
};
use bytes::BufMut;
use prost::{error::EncodeError, Message};
Expand Down Expand Up @@ -59,14 +59,8 @@ impl From<&vote::Vote> for Vote {
height: vote.height.value() as i64, // TODO potential overflow :-/
round: vote.round as i64,
block_id: Some(BlockId {
hash: match vote.block_id.hash {
Hash::Sha256(h) => h.to_vec(),
_ => vec![],
},
parts_header: match &vote.block_id.parts {
Some(parts) => Some(PartsSetHeader::from(parts)),
None => None,
},
hash: vote.block_id.hash.as_bytes().to_vec(),
parts_header: vote.block_id.parts.as_ref().map(PartsSetHeader::from),
}),
timestamp: Some(TimeMsg::from(vote.timestamp)),
validator_address: vote.validator_address.as_bytes().to_vec(),
Expand Down Expand Up @@ -246,9 +240,9 @@ impl ConsensusMessage for Vote {
mod tests {
use super::super::PartsSetHeader;
use super::*;
use crate::amino_types::message::AminoMessage;
use crate::amino_types::SignedMsgType;
use chrono::{DateTime, Utc};
use prost::Message;

#[test]
fn test_vote_serialization() {
Expand Down Expand Up @@ -334,8 +328,7 @@ mod tests {
vt_precommit.vote_type = SignedMsgType::PreCommit.to_u32(); // precommit
println!("{:?}", vt_precommit);
let cv_precommit = CanonicalVote::new(vt_precommit, "");
got = vec![];
cv_precommit.encode(&mut got).unwrap();
let got = AminoMessage::bytes_vec(&cv_precommit);
let want = vec![
0x8, // (field_number << 3) | wire_type
0x2, // PrecommitType
Expand All @@ -356,10 +349,9 @@ mod tests {
vt_prevote.round = 1;
vt_prevote.vote_type = SignedMsgType::PreVote.to_u32();

got = vec![];
let cv_prevote = CanonicalVote::new(vt_prevote, "");

cv_prevote.encode(&mut got).unwrap();
let got = AminoMessage::bytes_vec(&cv_prevote);

let want = vec![
0x8, // (field_number << 3) | wire_type
Expand All @@ -380,9 +372,8 @@ mod tests {
vt_no_type.height = 1;
vt_no_type.round = 1;

got = vec![];
let cv = CanonicalVote::new(vt_no_type, "");
cv.encode(&mut got).unwrap();
let got = AminoMessage::bytes_vec(&cv);

let want = vec![
0x11, // (field_number << 3) | wire_type
Expand All @@ -401,8 +392,7 @@ mod tests {
no_vote_type2.round = 1;

let with_chain_id = CanonicalVote::new(no_vote_type2, "test_chain_id");
got = vec![];
with_chain_id.encode(&mut got).unwrap();
got = AminoMessage::bytes_vec(&with_chain_id);
let want = vec![
0x11, // (field_number << 3) | wire_type
0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, // height
Expand Down
31 changes: 27 additions & 4 deletions tendermint/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ pub mod parts;
mod size;

pub use self::{
commit::Commit,
header::Header,
commit::*,
header::{parse_non_empty_block_id, Header},
height::*,
id::{Id, ParseId},
meta::Meta,
size::Size,
};
use crate::{abci::transaction, evidence};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};

/// Blocks consist of a header, transactions, votes (the commit), and a list of
/// evidence of malfeasance (i.e. signing conflicting votes).
Expand All @@ -35,5 +35,28 @@ pub struct Block {
pub evidence: evidence::Data,

/// Last commit
pub last_commit: Commit,
#[serde(deserialize_with = "parse_non_empty_commit")]
pub last_commit: Option<Commit>,
}

pub(crate) fn parse_non_empty_commit<'de, D>(deserializer: D) -> Result<Option<Commit>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct TmpCommit {
#[serde(deserialize_with = "parse_non_empty_block_id")]
block_id: Option<Id>,
precommits: Option<Precommits>,
}

let commit = TmpCommit::deserialize(deserializer)?;
if commit.block_id.is_none() || commit.precommits.is_none() {
Ok(None)
} else {
Ok(Some(Commit {
block_id: commit.block_id.unwrap(),
precommits: commit.precommits.unwrap(),
}))
}
}
10 changes: 5 additions & 5 deletions tendermint/src/block/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,31 +19,31 @@ pub struct Commit {

/// Precommits which certify that a block is valid
#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct Precommits(Option<Vec<Option<Vote>>>);
pub struct Precommits(Vec<Option<Vote>>);

impl Precommits {
/// Create a new precommit collection
pub fn new<I>(into_precommits: I) -> Self
where
I: Into<Vec<Option<Vote>>>,
{
Self(Some(into_precommits.into()))
Self(into_precommits.into())
}

/// Convert this collection of precommits into a vector
pub fn into_vec(self) -> Vec<Option<Vote>> {
self.iter().cloned().collect()
self.0.clone()
}

/// Iterate over the precommits in the collection
pub fn iter(&self) -> slice::Iter<'_, Option<Vote>> {
self.as_ref().iter()
self.0.iter()
}
}

impl AsRef<[Option<Vote>]> for Precommits {
fn as_ref(&self) -> &[Option<Vote>] {
self.0.as_ref().map(Vec::as_slice).unwrap_or_else(|| &[])
self.0.as_slice()
}
}

Expand Down
Loading