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

Support for CometBFT proto 0.38 #1312

Merged
merged 37 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
3f2dfb2
Generate protos for v0_38
mzabaluev Apr 24, 2023
eba4066
proto: add serializers for v0_38::types::Evidence
mzabaluev Apr 24, 2023
b5273a1
p2p: switch tendermint-proto imports to v0_38
mzabaluev Apr 24, 2023
7afb61f
tendermint: domain type for AbciParams
mzabaluev Apr 25, 2023
71b833b
tendermint: BlockIdFlag as a domain type
mzabaluev Apr 27, 2023
6f51d23
Extend VoteInfo to support 0.38 data
mzabaluev Apr 27, 2023
ad1f3f0
Rename Signature::to_bytes
mzabaluev Apr 27, 2023
10ac41b
tendermint: v0_38 serialization for Vote
mzabaluev Apr 27, 2023
4d6247d
proto: use v0_38 in BlockId unit tests
mzabaluev Apr 27, 2023
039a773
tendermint: v0_38 serialization for block::Size
mzabaluev Apr 27, 2023
bfdc346
tendermint: v0_38 conversions for abci::Event
mzabaluev Apr 28, 2023
df3abf0
Extend tendermint_pb_modules to v0_38
mzabaluev Apr 27, 2023
b063c47
abci: Update to ABCI 0.38
mzabaluev Apr 27, 2023
0176408
abci: temporarily fudge tests for proto 0_38
mzabaluev May 2, 2023
2601aac
light-client-verifier: adapt to new Vote fields
mzabaluev May 2, 2023
87fd393
rpc: ignore legacy CheckTx fields
mzabaluev May 2, 2023
06703cc
test: fix proto import in p2p/secret_connection
mzabaluev May 2, 2023
913a902
testgen: default the new fields for 0.38
mzabaluev May 2, 2023
1a41d12
CI: update buf and protoc to latest versions
mzabaluev May 2, 2023
82bba88
CI: diff between generated and checked-in files
mzabaluev May 3, 2023
3619b7e
Restore serde derives on PublicKey
mzabaluev May 3, 2023
a060aa3
Regenerate protos from latest release tags
mzabaluev May 2, 2023
9618fd1
tendermint: v0_38 proto support for request::Info
mzabaluev May 4, 2023
431db0f
tendermint: support 0.38 extensions for VoteInfo
mzabaluev May 4, 2023
36eca7a
tendermint: v0.38 ABCI requests and responses
mzabaluev May 4, 2023
b4e7779
Fix redundant closure lints
mzabaluev May 5, 2023
c08249f
tendermint: version-specific kinded response enums
mzabaluev May 8, 2023
f169a93
abci: crude logic and tests for finalize_block
mzabaluev May 9, 2023
0da192b
tendermint: Re-export v0_38 kinded ABCI enums
mzabaluev May 9, 2023
58b4dc5
Changelog entries for #1312
mzabaluev May 9, 2023
fe0c542
tendermint: domain type for ExtendedVoteInfo
mzabaluev May 10, 2023
43ebace
Fix formatting of changelog entries
mzabaluev May 12, 2023
6a19f6c
tendermint: 0.38 version notes on domain types
mzabaluev May 12, 2023
ea7cd5f
Update buf to 1.18 in CI
mzabaluev May 12, 2023
1f5688d
Restore legacy fields on CheckTx
mzabaluev May 12, 2023
3914320
tendermint: restore data field in Commit response
mzabaluev May 15, 2023
483a1da
Update changelog for #1312
mzabaluev May 15, 2023
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
152 changes: 127 additions & 25 deletions tendermint/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ use core::{fmt, str::FromStr};

use bytes::BufMut;
use serde::{Deserialize, Serialize};
use tendermint_proto::v0_37::types::{CanonicalVote as RawCanonicalVote, Vote as RawVote};
use tendermint_proto::v0_38::types::{CanonicalVote as RawCanonicalVote, Vote as RawVote};
use tendermint_proto::{Error as ProtobufError, Protobuf};

pub use self::{
canonical_vote::CanonicalVote, power::Power, sign_vote::*, validator_index::ValidatorIndex,
};
use crate::{
account, block, chain::Id as ChainId, consensus::State, error::Error, hash, prelude::*,
signature::Ed25519Signature, Signature, Time,
Signature, Time,
};

/// Votes are signed messages from validators for a particular block which
Expand Down Expand Up @@ -50,12 +50,76 @@ pub struct Vote {

/// Signature
pub signature: Option<Signature>,

/// Vote extension provided by the application.
/// Only valid for precommit messages.
pub extension: Vec<u8>,

/// Vote extension signature by the validator
/// Only valid for precommit messages.
pub extension_signature: Option<Signature>,
mzabaluev marked this conversation as resolved.
Show resolved Hide resolved
}

// =============================================================================
// Protobuf conversions
// =============================================================================

mod v0_34 {
use super::Vote;
use crate::{block, prelude::*, Error, Signature};
use tendermint_proto::v0_34::types::Vote as RawVote;
use tendermint_proto::Protobuf;

impl Protobuf<RawVote> for Vote {}

impl TryFrom<RawVote> for Vote {
type Error = Error;

fn try_from(value: RawVote) -> Result<Self, Self::Error> {
if value.timestamp.is_none() {
return Err(Error::missing_timestamp());
}
Ok(Vote {
vote_type: value.r#type.try_into()?,
height: value.height.try_into()?,
round: value.round.try_into()?,
// block_id can be nil in the Go implementation
block_id: value
.block_id
.map(TryInto::try_into)
.transpose()?
.filter(|i| i != &block::Id::default()),
timestamp: value.timestamp.map(|t| t.try_into()).transpose()?,
validator_address: value.validator_address.try_into()?,
validator_index: value.validator_index.try_into()?,
signature: Signature::new(value.signature)?,
extension: Default::default(),
extension_signature: None,
})
}
}

impl From<Vote> for RawVote {
fn from(value: Vote) -> Self {
RawVote {
r#type: value.vote_type.into(),
height: value.height.into(),
round: value.round.into(),
block_id: value.block_id.map(Into::into),
timestamp: value.timestamp.map(Into::into),
validator_address: value.validator_address.into(),
validator_index: value.validator_index.into(),
signature: value.signature.map(|s| s.into_bytes()).unwrap_or_default(),
}
}
}
}

tendermint_pb_modules! {
mod v0_37 {
use super::Vote;
use crate::{prelude::*, block, Error, Signature};
use pb::types::Vote as RawVote;
use crate::{block, prelude::*, Error, Signature};
use tendermint_proto::v0_37::types::Vote as RawVote;
use tendermint_proto::Protobuf;

impl Protobuf<RawVote> for Vote {}

Expand All @@ -80,6 +144,8 @@ tendermint_pb_modules! {
validator_address: value.validator_address.try_into()?,
validator_index: value.validator_index.try_into()?,
signature: Signature::new(value.signature)?,
extension: Default::default(),
extension_signature: None,
})
}
}
Expand All @@ -100,6 +166,62 @@ tendermint_pb_modules! {
}
}

mod v0_38 {
use super::Vote;
use crate::{block, prelude::*, Error, Signature};
use tendermint_proto::v0_38::types::Vote as RawVote;
use tendermint_proto::Protobuf;

impl Protobuf<RawVote> for Vote {}

impl TryFrom<RawVote> for Vote {
type Error = Error;

fn try_from(value: RawVote) -> Result<Self, Self::Error> {
if value.timestamp.is_none() {
return Err(Error::missing_timestamp());
}
Ok(Vote {
vote_type: value.r#type.try_into()?,
height: value.height.try_into()?,
round: value.round.try_into()?,
// block_id can be nil in the Go implementation
block_id: value
.block_id
.map(TryInto::try_into)
.transpose()?
.filter(|i| i != &block::Id::default()),
timestamp: value.timestamp.map(|t| t.try_into()).transpose()?,
validator_address: value.validator_address.try_into()?,
validator_index: value.validator_index.try_into()?,
signature: Signature::new(value.signature)?,
extension: value.extension,
extension_signature: Signature::new(value.extension_signature)?,
})
}
}

impl From<Vote> for RawVote {
fn from(value: Vote) -> Self {
RawVote {
r#type: value.vote_type.into(),
height: value.height.into(),
round: value.round.into(),
block_id: value.block_id.map(Into::into),
timestamp: value.timestamp.map(Into::into),
validator_address: value.validator_address.into(),
validator_index: value.validator_index.into(),
signature: value.signature.map(|s| s.into_bytes()).unwrap_or_default(),
extension: value.extension,
extension_signature: value
.extension_signature
.map(|s| s.into_bytes())
.unwrap_or_default(),
}
}
}
}

impl Vote {
/// Is this vote a prevote?
pub fn is_prevote(&self) -> bool {
Expand Down Expand Up @@ -157,26 +279,6 @@ impl Vote {
}
}

/// Default trait. Used in tests.
// FIXME: Does it need to be in public crate API? If not, replace with a helper fn in crate::test?
impl Default for Vote {
fn default() -> Self {
Vote {
vote_type: Type::Prevote,
height: Default::default(),
round: Default::default(),
block_id: None,
timestamp: Some(Time::unix_epoch()),
validator_address: account::Id::new([0; account::LENGTH]),
validator_index: ValidatorIndex::try_from(0_i32).unwrap(),
// Could have reused crate::test::dummy_signature, except that
// this Default impl is defined outside of #[cfg(test)].
signature: Some(Signature::from(Ed25519Signature::from_bytes(
&[0; Ed25519Signature::BYTE_SIZE],
))),
}
}
}
/// SignedVote is the union of a canonicalized vote, the signature on
/// the sign bytes of that vote and the id of the validator who signed it.
pub struct SignedVote {
Expand Down
41 changes: 37 additions & 4 deletions tendermint/src/vote/sign_vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ mod tests {
chain::Id as ChainId,
hash::Algorithm,
prelude::*,
signature::{Ed25519Signature, Signature},
signature::Signature,
vote::{CanonicalVote, SignVoteRequest, Type, ValidatorIndex},
Hash, Vote,
};
Expand Down Expand Up @@ -144,6 +144,9 @@ mod tests {
192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10,
])
.unwrap(),
// TODO: test serialization of extensions
extension: vec![],
extension_signature: None,
};

let mut got = vec![];
Expand Down Expand Up @@ -228,6 +231,9 @@ mod tests {
192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10,
])
.unwrap(),
// TODO: test serialization of extensions
extension: vec![],
extension_signature: None,
};

let request = SignVoteRequest {
Expand Down Expand Up @@ -278,10 +284,31 @@ mod tests {
tendermint_pb_modules! {
use super::*;
use pb::types::CanonicalVote as RawCanonicalVote;
use crate::{Time, account, signature::Ed25519Signature};

/// Returns a dummy value to be used in tests.
pub fn dummy_vote() -> Vote {
Vote {
vote_type: Type::Prevote,
height: Default::default(),
round: Default::default(),
block_id: None,
timestamp: Some(Time::unix_epoch()),
validator_address: account::Id::new([0; account::LENGTH]),
validator_index: ValidatorIndex::try_from(0_i32).unwrap(),
// Could have reused crate::test::dummy_signature, except that
// this Default impl is defined outside of #[cfg(test)].
signature: Some(Signature::from(Ed25519Signature::from_bytes(
&[0; Ed25519Signature::BYTE_SIZE],
))),
extension: Default::default(),
extension_signature: None,
}
}

#[test]
fn test_sign_bytes_compatibility() {
let cv = CanonicalVote::new(Vote::default(), ChainId::try_from("A").unwrap());
let cv = CanonicalVote::new(dummy_vote(), ChainId::try_from("A").unwrap());
let mut got = vec![];
// SignBytes are encoded using MarshalBinary and not MarshalBinaryBare
Protobuf::<RawCanonicalVote>::encode_length_delimited(&cv, &mut got).unwrap();
Expand All @@ -297,7 +324,7 @@ mod tests {
height: Height::from(1_u32),
round: Round::from(1_u16),
vote_type: Type::Precommit,
..Default::default()
..dummy_vote()
};
println!("{vt_precommit:?}");
let cv_precommit = CanonicalVote::new(vt_precommit, ChainId::try_from("A").unwrap());
Expand All @@ -323,7 +350,7 @@ mod tests {
height: Height::from(1_u32),
round: Round::from(1_u16),
vote_type: Type::Prevote,
..Default::default()
..dummy_vote()
};

let cv_prevote = CanonicalVote::new(vt_prevote, ChainId::try_from("A").unwrap());
Expand Down Expand Up @@ -384,6 +411,9 @@ mod tests {
.unwrap(),
}),
signature: Signature::new(vec![1; Ed25519Signature::BYTE_SIZE]).unwrap(),
// TODO: test deserialization of extensions in 0.38
extension: vec![],
extension_signature: None,
};
let want = SignVoteRequest {
vote,
Expand Down Expand Up @@ -428,6 +458,9 @@ mod tests {
192, 133, 130, 193, 115, 32, 206, 152, 91, 173, 10,
])
.unwrap(),
// TODO: test deserialization of extensions in 0.38
extension: vec![],
extension_signature: None,
};
let got = Protobuf::<pb::types::Vote>::encode_vec(&vote).unwrap();
let v = <Vote as Protobuf::<pb::types::Vote>>::decode_vec(&got).unwrap();
Expand Down