Skip to content

Commit

Permalink
Tendermint v0.34 signing compatibility
Browse files Browse the repository at this point in the history
Adds initial (quick-and-dirty) support for Protobuf signing.

Based on this branch:

https://github.com/tomtau/tmkms/tree/fix/tmkms-alpha-proto

Co-authored-by: Tomas Tauber <[email protected]>
  • Loading branch information
tony-iqlusion and tomtau committed Nov 9, 2020
1 parent 2c5537d commit 51cc5c4
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 46 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ prerequisites for support.

You will need the following prerequisites:

- **Rust** (stable; **1.41+**): https://rustup.rs/
- **Rust** (stable; **1.44+**): https://rustup.rs/
- **C compiler**: e.g. gcc, clang
- **pkg-config**
- **libusb** (1.0+). Install instructions for common platforms:
Expand Down
81 changes: 59 additions & 22 deletions src/amino_types/proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@ use super::{
validate::{self, ConsensusMessage, Error::*},
TendermintRequest,
};
use crate::rpc;
use crate::{config::validator::ProtocolVersion, rpc};
use bytes::BufMut;
use ed25519_dalek as ed25519;
use once_cell::sync::Lazy;
use prost::Message as _;
use prost_amino::{EncodeError, Message};
use prost_amino_derive::Message;
use std::convert::TryFrom;
use tendermint::{
block::{self, ParseId},
chain, consensus, error,
};
use tendermint_proto::types as proto_types;

#[derive(Clone, PartialEq, Message)]
pub struct Proposal {
Expand Down Expand Up @@ -95,7 +97,12 @@ pub struct SignedProposalResponse {
}

impl SignableMsg for SignProposalRequest {
fn sign_bytes<B>(&self, chain_id: chain::Id, sign_bytes: &mut B) -> Result<bool, EncodeError>
fn sign_bytes<B>(
&self,
chain_id: chain::Id,
protocol_version: ProtocolVersion,
sign_bytes: &mut B,
) -> Result<bool, EncodeError>
where
B: BufMut,
{
Expand All @@ -104,29 +111,59 @@ impl SignableMsg for SignProposalRequest {
pr.signature = vec![];
}
let proposal = spr.proposal.unwrap();
let cp = CanonicalProposal {
chain_id: chain_id.to_string(),
msg_type: SignedMsgType::Proposal.to_u32(),
height: proposal.height,
block_id: match proposal.block_id {
Some(bid) => Some(CanonicalBlockId {
hash: bid.hash,
parts_header: match bid.parts_header {
Some(psh) => Some(CanonicalPartSetHeader {
hash: psh.hash,
total: psh.total,
}),
None => None,
},

if protocol_version.is_protobuf() {
let block_id = match proposal.block_id.as_ref() {
Some(x) if x.hash.is_empty() => None,
Some(x) => Some(proto_types::CanonicalBlockId {
hash: x.hash.clone(),
part_set_header: x.parts_header.as_ref().map(|y| {
proto_types::CanonicalPartSetHeader {
total: y.total as u32,
hash: y.hash.clone(),
}
}),
}),
None => None,
},
pol_round: proposal.pol_round,
round: proposal.round,
timestamp: proposal.timestamp,
};
};

let cp = proto_types::CanonicalProposal {
chain_id: chain_id.to_string(),
r#type: SignedMsgType::Proposal.to_u32() as i32,
height: proposal.height,
block_id,
pol_round: proposal.pol_round,
round: proposal.round,
timestamp: proposal.timestamp.map(Into::into),
};

cp.encode_length_delimited(sign_bytes).unwrap();
} else {
let cp = CanonicalProposal {
chain_id: chain_id.to_string(),
msg_type: SignedMsgType::Proposal.to_u32(),
height: proposal.height,
block_id: match proposal.block_id {
Some(bid) => Some(CanonicalBlockId {
hash: bid.hash,
parts_header: match bid.parts_header {
Some(psh) => Some(CanonicalPartSetHeader {
hash: psh.hash,
total: psh.total,
}),
None => None,
},
}),
None => None,
},
pol_round: proposal.pol_round,
round: proposal.round,
timestamp: proposal.timestamp,
};

cp.encode_length_delimited(sign_bytes)?;
}

cp.encode_length_delimited(sign_bytes)?;
Ok(true)
}
fn set_signature(&mut self, sig: &ed25519::Signature) {
Expand Down
2 changes: 2 additions & 0 deletions src/amino_types/signature.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::validate;
use crate::config::validator::ProtocolVersion;
use bytes::BufMut;
use ed25519_dalek as ed25519;
use prost_amino::{DecodeError, EncodeError};
Expand All @@ -10,6 +11,7 @@ pub trait SignableMsg {
fn sign_bytes<B: BufMut>(
&self,
chain_id: chain::Id,
version: ProtocolVersion,
sign_bytes: &mut B,
) -> Result<bool, EncodeError>;

Expand Down
43 changes: 39 additions & 4 deletions src/amino_types/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ use super::{
validate::{self, ConsensusMessage, Error::*},
PartsSetHeader, SignedMsgType, TendermintRequest,
};
use crate::rpc;
use crate::{config::validator::ProtocolVersion, rpc};
use bytes::BufMut;
use ed25519_dalek as ed25519;
use once_cell::sync::Lazy;
use prost::Message as _;
use prost_amino::{error::EncodeError, Message};
use prost_amino_derive::Message;
use std::convert::TryFrom;
Expand All @@ -20,6 +21,7 @@ use tendermint::{
error::Error,
vote,
};
use tendermint_proto::types as proto_types;

const VALIDATOR_ADDR_SIZE: usize = 20;

Expand Down Expand Up @@ -176,18 +178,51 @@ impl CanonicalVote {
}

impl SignableMsg for SignVoteRequest {
fn sign_bytes<B>(&self, chain_id: chain::Id, sign_bytes: &mut B) -> Result<bool, EncodeError>
fn sign_bytes<B>(
&self,
chain_id: chain::Id,
protocol_version: ProtocolVersion,
sign_bytes: &mut B,
) -> Result<bool, EncodeError>
where
B: BufMut,
{
let mut svr = self.clone();

if let Some(ref mut vo) = svr.vote {
vo.signature = vec![];
}

let vote = svr.vote.unwrap();
let cv = CanonicalVote::new(vote, chain_id.as_str());

cv.encode_length_delimited(sign_bytes)?;
if protocol_version.is_protobuf() {
let block_id = match vote.block_id.as_ref() {
Some(x) if x.hash.is_empty() => None,
Some(x) => Some(proto_types::CanonicalBlockId {
hash: x.hash.clone(),
part_set_header: x.parts_header.as_ref().map(|y| {
proto_types::CanonicalPartSetHeader {
total: y.total as u32,
hash: y.hash.clone(),
}
}),
}),
None => None,
};

let cv = proto_types::CanonicalVote {
r#type: vote.vote_type as i32,
height: vote.height,
round: vote.round as i64,
block_id,
timestamp: vote.timestamp.map(Into::into),
chain_id: chain_id.to_string(),
};
cv.encode_length_delimited(sign_bytes).unwrap();
} else {
let cv = CanonicalVote::new(vote, chain_id.as_str());
cv.encode_length_delimited(sign_bytes)?;
}

Ok(true)
}
Expand Down
7 changes: 6 additions & 1 deletion src/commands/ledger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use crate::{
SignableMsg, SignedMsgType,
},
chain,
config::validator::ProtocolVersion,
prelude::*,
};
use abscissa_core::{Command, Options, Runnable};
Expand Down Expand Up @@ -64,7 +65,11 @@ impl Runnable for InitCommand {
let sign_vote_req = SignVoteRequest { vote: Some(vote) };
let mut to_sign = vec![];
sign_vote_req
.sign_bytes(config.validator[0].chain_id, &mut to_sign)
.sign_bytes(
config.validator[0].chain_id,
ProtocolVersion::Legacy,
&mut to_sign,
)
.unwrap();

let _sig = chain.keyring.sign_ed25519(None, &to_sign).unwrap();
Expand Down
36 changes: 35 additions & 1 deletion src/config/validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,41 @@ pub struct ValidatorConfig {
pub max_height: Option<tendermint::block::Height>,

/// Version of Secret Connection protocol to use when connecting
pub protocol_version: secret_connection::Version,
pub protocol_version: ProtocolVersion,
}

/// Protocol version (based on the Tendermint version)
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[allow(non_camel_case_types)]
pub enum ProtocolVersion {
/// Tendermint v0.34
#[serde(rename = "v0.34")]
V0_34,

/// Tendermint v0.33
#[serde(rename = "v0.33")]
V0_33,

/// Pre-Tendermint v0.33
#[serde(rename = "legacy")]
Legacy,
}

impl ProtocolVersion {
/// Are messages encoded using Protocol Buffers?
pub fn is_protobuf(self) -> bool {
!matches!(self, ProtocolVersion::V0_33 | ProtocolVersion::Legacy)
}
}

impl From<ProtocolVersion> for secret_connection::Version {
fn from(version: ProtocolVersion) -> secret_connection::Version {
match version {
ProtocolVersion::V0_34 => secret_connection::Version::V0_34,
ProtocolVersion::V0_33 => secret_connection::Version::V0_33,
ProtocolVersion::Legacy => secret_connection::Version::Legacy,
}
}
}

/// Default value for the `ValidatorConfig` reconnect field
Expand Down
6 changes: 1 addition & 5 deletions src/connection/secret_connection/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::{
use ed25519_dalek as ed25519;
use prost::Message as _;
use prost_amino::Message as _;
use serde::{Deserialize, Serialize};
use std::convert::TryInto;
use tendermint_proto as proto;
use x25519_dalek::PublicKey as EphemeralPublic;
Expand All @@ -17,19 +16,16 @@ use x25519_dalek::PublicKey as EphemeralPublic;
const PUBLIC_KEY_SIZE: usize = 32;

/// Protocol version (based on the Tendermint version)
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
#[allow(non_camel_case_types)]
pub enum Version {
/// Tendermint v0.34
#[serde(rename = "v0.34")]
V0_34,

/// Tendermint v0.33
#[serde(rename = "v0.33")]
V0_33,

/// Pre-Tendermint v0.33
#[serde(rename = "legacy")]
Legacy,
}

Expand Down
7 changes: 4 additions & 3 deletions src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

use crate::{
amino_types,
connection::secret_connection::{Version, DATA_MAX_SIZE},
config::validator::ProtocolVersion,
connection::secret_connection::DATA_MAX_SIZE,
error::{Error, ErrorKind},
prelude::*,
};
Expand All @@ -29,7 +30,7 @@ pub enum Request {

impl Request {
/// Read a request from the given readable
pub fn read(conn: &mut impl Read, protocol_version: Version) -> Result<Self, Error> {
pub fn read(conn: &mut impl Read, protocol_version: ProtocolVersion) -> Result<Self, Error> {
let msg = read_msg(conn)?;

if protocol_version.is_protobuf() {
Expand Down Expand Up @@ -117,7 +118,7 @@ pub enum Response {

impl Response {
/// Encode response to bytes
pub fn encode(self, protocol_version: Version) -> Result<Vec<u8>, Error> {
pub fn encode(self, protocol_version: ProtocolVersion) -> Result<Vec<u8>, Error> {
if protocol_version.is_protobuf() {
let mut buf = Vec::new();

Expand Down
8 changes: 6 additions & 2 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ impl Session {
&config.secret_key,
peer_id,
config.timeout,
config.protocol_version,
config.protocol_version.into(),
)?;

info!(
Expand Down Expand Up @@ -146,7 +146,11 @@ impl Session {
}

let mut to_sign = vec![];
request.sign_bytes(self.config.chain_id, &mut to_sign)?;
request.sign_bytes(
self.config.chain_id,
self.config.protocol_version,
&mut to_sign,
)?;

let started_at = Instant::now();

Expand Down
Loading

0 comments on commit 51cc5c4

Please sign in to comment.