Skip to content

Commit

Permalink
Vendor amino_types (#203)
Browse files Browse the repository at this point in the history
Vendors all Amino types from the `tendermint` crate, so we can continue
supporting Amino even though it's been removed from the upstream crate
in favor of Protobufs.
  • Loading branch information
tony-iqlusion authored Nov 2, 2020
1 parent 77fbc00 commit c2bb765
Show file tree
Hide file tree
Showing 17 changed files with 1,535 additions and 129 deletions.
62 changes: 62 additions & 0 deletions src/amino_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//! Legacy message types serialized using the Amino serialization format
//! <https://github.com/tendermint/amino_rs>
#![allow(missing_docs)]

pub mod block_id;
pub mod ed25519;
pub mod message;
pub mod ping;
pub mod proposal;
pub mod remote_error;
pub mod signature;
pub mod time;
pub mod validate;
pub mod version;
pub mod vote;

pub use self::{
block_id::{BlockId, CanonicalBlockId, CanonicalPartSetHeader, PartsSetHeader},
ed25519::{
PubKeyRequest, PubKeyResponse, AMINO_NAME as PUBKEY_AMINO_NAME,
AMINO_PREFIX as PUBKEY_PREFIX,
},
ping::{PingRequest, PingResponse, AMINO_NAME as PING_AMINO_NAME, AMINO_PREFIX as PING_PREFIX},
proposal::{
Proposal, SignProposalRequest, SignedProposalResponse, AMINO_NAME as PROPOSAL_AMINO_NAME,
AMINO_PREFIX as PROPOSAL_PREFIX,
},
remote_error::RemoteError,
signature::{SignableMsg, SignedMsgType},
time::TimeMsg,
validate::ConsensusMessage,
version::ConsensusVersion,
vote::{
SignVoteRequest, SignedVoteResponse, Vote, AMINO_NAME as VOTE_AMINO_NAME,
AMINO_PREFIX as VOTE_PREFIX,
},
};

use crate::rpc;
use sha2::{Digest, Sha256};

/// Tendermint requests
pub trait TendermintRequest: SignableMsg {
fn build_response(self, error: Option<RemoteError>) -> rpc::Response;
}

/// Compute the Amino prefix for the given registered type name
pub fn compute_prefix(name: &str) -> Vec<u8> {
let mut sh = Sha256::default();
sh.update(name.as_bytes());
let output = sh.finalize();

output
.iter()
.filter(|&x| *x != 0x00)
.skip(3)
.filter(|&x| *x != 0x00)
.cloned()
.take(4)
.collect()
}
156 changes: 156 additions & 0 deletions src/amino_types/block_id.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
use super::validate::{self, ConsensusMessage, Error::*};
use crate::proto_types;
use prost_amino_derive::Message;
use tendermint::{
block::{self, parts},
error::Error,
hash,
hash::{Hash, SHA256_HASH_SIZE},
};

#[derive(Clone, PartialEq, Message)]
pub struct BlockId {
#[prost_amino(bytes, tag = "1")]
pub hash: Vec<u8>,
#[prost_amino(message, tag = "2")]
pub parts_header: Option<PartsSetHeader>,
}

impl BlockId {
pub fn new(hash: Vec<u8>, parts_header: Option<PartsSetHeader>) -> Self {
BlockId { hash, parts_header }
}
}

impl block::ParseId for BlockId {
fn parse_block_id(&self) -> Result<block::Id, Error> {
let hash = Hash::new(hash::Algorithm::Sha256, &self.hash)?;
let parts_header = self
.parts_header
.as_ref()
.and_then(PartsSetHeader::parse_parts_header);
Ok(block::Id::new(hash, parts_header))
}
}

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

impl From<proto_types::BlockId> for BlockId {
fn from(block_id: proto_types::BlockId) -> BlockId {
BlockId::new(
block_id.hash,
block_id.part_set_header.map(|psh| PartsSetHeader {
total: psh.total as i64,
hash: psh.hash,
}),
)
}
}

impl From<BlockId> for proto_types::BlockId {
fn from(block_id: BlockId) -> proto_types::BlockId {
proto_types::BlockId {
hash: block_id.hash,
part_set_header: block_id.parts_header.map(|psh| proto_types::PartSetHeader {
total: psh.total as u32,
hash: psh.hash,
}),
}
}
}

impl ConsensusMessage for BlockId {
fn validate_basic(&self) -> Result<(), validate::Error> {
// Hash can be empty in case of POLBlockID in Proposal.
if !self.hash.is_empty() && self.hash.len() != SHA256_HASH_SIZE {
return Err(InvalidHashSize);
}
self.parts_header
.as_ref()
.map_or(Ok(()), ConsensusMessage::validate_basic)
}
}

#[derive(Clone, PartialEq, Message)]
pub struct CanonicalBlockId {
#[prost_amino(bytes, tag = "1")]
pub hash: Vec<u8>,
#[prost_amino(message, tag = "2")]
pub parts_header: Option<CanonicalPartSetHeader>,
}

impl block::ParseId for CanonicalBlockId {
fn parse_block_id(&self) -> Result<block::Id, Error> {
let hash = Hash::new(hash::Algorithm::Sha256, &self.hash)?;
let parts_header = self
.parts_header
.as_ref()
.and_then(CanonicalPartSetHeader::parse_parts_header);
Ok(block::Id::new(hash, parts_header))
}
}

#[derive(Clone, PartialEq, Message)]
pub struct PartsSetHeader {
#[prost_amino(int64, tag = "1")]
pub total: i64,
#[prost_amino(bytes, tag = "2")]
pub hash: Vec<u8>,
}

impl PartsSetHeader {
pub fn new(total: i64, hash: Vec<u8>) -> Self {
PartsSetHeader { total, hash }
}
}

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

impl PartsSetHeader {
fn parse_parts_header(&self) -> Option<block::parts::Header> {
Hash::new(hash::Algorithm::Sha256, &self.hash)
.map(|hash| block::parts::Header::new(self.total as u64, hash))
.ok()
}
}

impl ConsensusMessage for PartsSetHeader {
fn validate_basic(&self) -> Result<(), validate::Error> {
if self.total < 0 {
return Err(NegativeTotal);
}
// Hash can be empty in case of POLBlockID.PartsHeader in Proposal.
if !self.hash.is_empty() && self.hash.len() != SHA256_HASH_SIZE {
return Err(InvalidHashSize);
}
Ok(())
}
}

#[derive(Clone, PartialEq, Message)]
pub struct CanonicalPartSetHeader {
#[prost_amino(bytes, tag = "1")]
pub hash: Vec<u8>,
#[prost_amino(int64, tag = "2")]
pub total: i64,
}

impl CanonicalPartSetHeader {
fn parse_parts_header(&self) -> Option<block::parts::Header> {
Hash::new(hash::Algorithm::Sha256, &self.hash)
.map(|hash| block::parts::Header::new(self.total as u64, hash))
.ok()
}
}
Loading

0 comments on commit c2bb765

Please sign in to comment.