From b7e9e46bf5313a90941dbaf849a5511c1aaa62f6 Mon Sep 17 00:00:00 2001 From: Ismail Khoffi Date: Thu, 26 Sep 2019 18:24:47 +0200 Subject: [PATCH] implement lite::Vote trait --- tendermint/src/amino_types/vote.rs | 28 +++++++++++++++++++++++++- tendermint/src/lite/types.rs | 5 ++++- tendermint/src/lite/verifier.rs | 8 ++++++-- tendermint/src/signature.rs | 8 ++++++++ tendermint/src/validator.rs | 2 -- tendermint/src/vote.rs | 32 +++++++++++++++++++++++++++++- 6 files changed, 76 insertions(+), 7 deletions(-) diff --git a/tendermint/src/amino_types/vote.rs b/tendermint/src/amino_types/vote.rs index cd5bc3325..4e7cc91f5 100644 --- a/tendermint/src/amino_types/vote.rs +++ b/tendermint/src/amino_types/vote.rs @@ -6,10 +6,12 @@ use super::{ validate::{ConsensusMessage, ValidationError, ValidationErrorKind::*}, SignedMsgType, }; +use crate::amino_types::PartsSetHeader; use crate::{ block::{self, ParseId}, chain, consensus, error::Error, + vote, Hash, }; use bytes::BufMut; use prost::{error::EncodeError, Message}; @@ -49,6 +51,30 @@ impl Vote { } } +impl From<&vote::Vote> for Vote { + fn from(vote: &vote::Vote) -> Self { + Vote { + vote_type: vote.vote_type.to_u8() as u32, + height: vote.height.value() as i64, // TODO potential overflow :-/ + 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, + }, + }), + round: vote.round as i64, + timestamp: Some(TimeMsg::from(vote.timestamp)), + validator_address: vote.validator_address.as_bytes().to_vec(), + validator_index: vote.validator_index as i64, // TODO potential overflow :-/ + signature: vote.signature.as_bytes().to_vec(), + } + } +} + impl block::ParseHeight for Vote { fn parse_block_height(&self) -> Result { block::Height::try_from_i64(self.height) @@ -102,7 +128,7 @@ impl block::ParseHeight for CanonicalVote { } impl CanonicalVote { - fn new(vote: Vote, chain_id: &str) -> CanonicalVote { + pub fn new(vote: Vote, chain_id: &str) -> CanonicalVote { CanonicalVote { vote_type: vote.vote_type, chain_id: chain_id.to_string(), diff --git a/tendermint/src/lite/types.rs b/tendermint/src/lite/types.rs index 85cb84f07..e3fa21c4d 100644 --- a/tendermint/src/lite/types.rs +++ b/tendermint/src/lite/types.rs @@ -2,6 +2,7 @@ use crate::account::Id; use crate::block::Height; use crate::Hash; use crate::Time; +use bytes::BufMut; /// TrustedState stores the latest state trusted by a lite client, /// including the last header and the validator set to use to verify @@ -86,7 +87,9 @@ pub trait Commit { /// Note the Vote must also know which validator it is from. pub trait Vote { fn validator_id(&self) -> Id; - fn sign_bytes(&self) -> &[u8]; + fn sign_bytes(&self, sign_bytes: &mut B) + where + B: BufMut; fn signature(&self) -> &[u8]; } diff --git a/tendermint/src/lite/verifier.rs b/tendermint/src/lite/verifier.rs index 25068c820..acd624414 100644 --- a/tendermint/src/lite/verifier.rs +++ b/tendermint/src/lite/verifier.rs @@ -127,7 +127,9 @@ where }; // check vote is valid from validator - if !val.verify_signature(vote.sign_bytes(), vote.signature()) { + let mut sign_bytes = vec![]; + vote.sign_bytes(&mut sign_bytes); + if !val.verify_signature(&sign_bytes, vote.signature()) { return Err(Error::InvalidSignature); } signed_power += val.power(); @@ -172,7 +174,9 @@ where }; // check vote is valid from validator - if !val.verify_signature(vote.sign_bytes(), vote.signature()) { + let mut sign_bytes = vec![]; + vote.sign_bytes(&mut sign_bytes); + if !val.verify_signature(&sign_bytes, vote.signature()) { return Err(Error::InvalidSignature); } signed_power += val.power(); diff --git a/tendermint/src/signature.rs b/tendermint/src/signature.rs index 07d7a0101..97f3acd53 100644 --- a/tendermint/src/signature.rs +++ b/tendermint/src/signature.rs @@ -18,6 +18,14 @@ impl Signature { Signature::Ed25519(_) => Algorithm::Ed25519, } } + + /// Return the raw bytes of this signature + pub fn as_bytes(&self) -> &[u8] { + let sig_bytes = match self { + Signature::Ed25519(sig) => sig.as_bytes(), + }; + sig_bytes + } } impl<'de> Deserialize<'de> for Signature { diff --git a/tendermint/src/validator.rs b/tendermint/src/validator.rs index c00a14d3f..0dae48730 100644 --- a/tendermint/src/validator.rs +++ b/tendermint/src/validator.rs @@ -59,8 +59,6 @@ impl lite::ValidatorSet for Set { self.validators.iter().fold(0u64, |total, val_info| { total + val_info.voting_power.value() }) - - // TODO cache this } fn into_vec(&self) -> Vec { diff --git a/tendermint/src/vote.rs b/tendermint/src/vote.rs index 32a39ae9e..b8983f4b8 100644 --- a/tendermint/src/vote.rs +++ b/tendermint/src/vote.rs @@ -3,7 +3,11 @@ mod power; pub use self::power::Power; -use crate::{account, block, Signature, Time}; +use crate::amino_types::vote::CanonicalVote; +use crate::amino_types::vote::Vote as AminoVote; +use crate::prost::Message; +use crate::{account, block, lite, Signature, Time}; +use bytes::BufMut; use { crate::serializers, serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer}, @@ -67,6 +71,32 @@ impl Vote { } } +impl lite::Vote for Vote { + fn validator_id(&self) -> account::Id { + self.validator_address + } + + fn sign_bytes(&self, mut sign_bytes: &mut B) + where + B: BufMut, + { + // TODO: 1) everytime we encode sth. an error can occur. Change the trait to return a result + // instead to enable proper error handling. + // 2) Figure out where the chain_id should come from (if sign_bytes remains on Vote, the + // sign_bytes method will need a chain_id. + CanonicalVote::new(AminoVote::from(self), "TODO") + .encode(&mut sign_bytes) + .unwrap(); + } + + fn signature(&self) -> &[u8] { + let sig_bytes = match &self.signature { + Signature::Ed25519(sig) => sig.as_bytes(), + }; + sig_bytes + } +} + /// Types of votes #[repr(u8)] #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]