Skip to content

Commit

Permalink
rpc: Add new dialect for v0.38 in order to fix changes in misbehaviou…
Browse files Browse the repository at this point in the history
…r evidence serialization (#1467)

* Add new dialect for v0.38 in order to fix changes in misbehaviour evidence serialization

* Add changelog entries

* Fix block-related queries to use compat mode

* Fix compilation error

* Remove unused serde with

---------

Co-authored-by: Luca Joss <luca@informal.systems>
  • Loading branch information
romac and ljoss17 authored Oct 23, 2024
1 parent 14fd628 commit db94695
Show file tree
Hide file tree
Showing 31 changed files with 831 additions and 86 deletions.
2 changes: 2 additions & 0 deletions .changelog/unreleased/breaking-changes/1467-v038-dialect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- [tendermint-rpc] Add new dialect for CometBFT v0.38.x
([\#1467](https://github.com/informalsystems/tendermint-rs/pull/1467))
3 changes: 3 additions & 0 deletions .changelog/unreleased/bug-fixes/1467-v038-evidence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- [tendermint-rpc] Fix serialization of misbehaviour `Evidence`
on CometBFT v0.38.x using the newly introduced dialect
([\#1467](https://github.com/informalsystems/tendermint-rs/pull/1467))
2 changes: 1 addition & 1 deletion proto/src/prost/v0_34/tendermint.abci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ pub struct ResponseCheckTx {
#[prost(int64, tag = "10")]
pub priority: i64,
/// mempool_error is set by CometBFT.
/// ABCI applications creating a ResponseCheckTX should not set mempool_error.
/// ABCI applictions creating a ResponseCheckTX should not set mempool_error.
#[prost(string, tag = "11")]
pub mempool_error: ::prost::alloc::string::String,
}
Expand Down
2 changes: 1 addition & 1 deletion proto/src/prost/v0_37/tendermint.abci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,7 @@ pub struct ResponseCheckTx {
#[prost(int64, tag = "10")]
pub priority: i64,
/// mempool_error is set by CometBFT.
/// ABCI applications creating a ResponseCheckTX should not set mempool_error.
/// ABCI applictions creating a ResponseCheckTX should not set mempool_error.
#[prost(string, tag = "11")]
pub mempool_error: ::prost::alloc::string::String,
}
Expand Down
2 changes: 1 addition & 1 deletion proto/src/prost/v0_38/tendermint.abci.rs
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ pub struct ResponseFinalizeBlock {
#[prost(message, repeated, tag = "1")]
pub events: ::prost::alloc::vec::Vec<Event>,
/// the result of executing each transaction including the events
/// the particular transaction emitted. This should match the order
/// the particular transction emitted. This should match the order
/// of the transactions delivered in the block itself
#[prost(message, repeated, tag = "2")]
pub tx_results: ::prost::alloc::vec::Vec<ExecTxResult>,
Expand Down
9 changes: 5 additions & 4 deletions proto/src/prost/v0_38/tendermint.types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,13 @@ pub struct Vote {
/// Vote extension provided by the application. Only valid for precommit
/// messages.
#[prost(bytes = "vec", tag = "9")]
#[serde(with = "crate::serializers::nullable")]
pub extension: ::prost::alloc::vec::Vec<u8>,
/// Vote extension signature by the validator if they participated in
/// consensus for the associated block.
/// Only valid for precommit messages.
#[prost(bytes = "vec", tag = "10")]
#[serde(with = "crate::serializers::nullable")]
pub extension_signature: ::prost::alloc::vec::Vec<u8>,
}
/// Commit contains the evidence that a block was committed by a set of validators.
Expand Down Expand Up @@ -418,18 +420,17 @@ pub struct DuplicateVoteEvidence {
#[prost(message, optional, tag = "2")]
pub vote_b: ::core::option::Option<Vote>,
#[prost(int64, tag = "3")]
#[serde(rename = "TotalVotingPower", with = "crate::serializers::from_str")]
#[serde(alias = "TotalVotingPower", with = "crate::serializers::from_str")]
pub total_voting_power: i64,
#[prost(int64, tag = "4")]
#[serde(rename = "ValidatorPower", with = "crate::serializers::from_str")]
#[serde(alias = "ValidatorPower", with = "crate::serializers::from_str")]
pub validator_power: i64,
#[prost(message, optional, tag = "5")]
#[serde(rename = "Timestamp")]
#[serde(alias = "Timestamp")]
pub timestamp: ::core::option::Option<crate::google::protobuf::Timestamp>,
}
/// LightClientAttackEvidence contains evidence of a set of validators attempting to mislead a light client.
#[derive(::serde::Deserialize, ::serde::Serialize)]
#[serde(rename_all = "PascalCase")]
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct LightClientAttackEvidence {
Expand Down
2 changes: 1 addition & 1 deletion proto/src/tendermint/v0_34.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ pub mod version {

pub mod meta {
pub const REPOSITORY: &str = "https://github.com/cometbft/cometbft";
pub const COMMITISH: &str = "v0.34.29";
pub const COMMITISH: &str = "v0.34.35";
}
2 changes: 1 addition & 1 deletion proto/src/tendermint/v0_37.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ pub mod version {

pub mod meta {
pub const REPOSITORY: &str = "https://github.com/cometbft/cometbft";
pub const COMMITISH: &str = "v0.37.2";
pub const COMMITISH: &str = "v0.37.11";
}
2 changes: 1 addition & 1 deletion proto/src/tendermint/v0_38.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ pub mod version {

pub mod meta {
pub const REPOSITORY: &str = "https://github.com/cometbft/cometbft";
pub const COMMITISH: &str = "v0.38.0";
pub const COMMITISH: &str = "v0.38.12";
}
15 changes: 10 additions & 5 deletions rpc/src/client/compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub enum CompatMode {
V0_34,
/// Use version 0.37 of the protocol.
V0_37,
/// Use version 0.38 of the protocol.
V0_38,
// NOTE: When adding a newer version, do not forget to update:
// - CompatMode::latest()
// - CompatMode::from_version()
Expand All @@ -34,7 +36,7 @@ impl Default for CompatMode {
impl CompatMode {
/// The latest supported version, selected by default.
pub const fn latest() -> Self {
Self::V0_37
Self::V0_38
}

/// Parse the Tendermint version string to determine
Expand All @@ -58,7 +60,7 @@ impl CompatMode {
match (version.major, version.minor) {
(0, 34) => Ok(CompatMode::V0_34),
(0, 37) => Ok(CompatMode::V0_37),
(0, 38) => Ok(CompatMode::V0_37),
(0, 38) => Ok(CompatMode::V0_38),
_ => Err(Error::unsupported_tendermint_version(version.to_string())),
}
}
Expand All @@ -69,6 +71,7 @@ impl fmt::Display for CompatMode {
match self {
CompatMode::V0_34 => f.write_str("v0.34"),
CompatMode::V0_37 => f.write_str("v0.37"),
CompatMode::V0_38 => f.write_str("v0.38"),
}
}
}
Expand All @@ -77,12 +80,13 @@ impl FromStr for CompatMode {
type Err = Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
const VALID_COMPAT_MODES: &str = "v0.34, v0.37";
const VALID_COMPAT_MODES: &str = "v0.34, v0.37, v0.38";

// Trim leading 'v', if present
match s.trim_start_matches('v') {
"0.34" => Ok(CompatMode::V0_34),
"0.37" => Ok(CompatMode::V0_37),
"0.38" => Ok(CompatMode::V0_38),
_ => Err(Error::invalid_compat_mode(
s.to_string(),
VALID_COMPAT_MODES,
Expand Down Expand Up @@ -139,7 +143,7 @@ mod tests {
);
assert_eq!(
CompatMode::from_version(parse_version("v0.38.0")).unwrap(),
CompatMode::V0_37
CompatMode::V0_38
);
let res = CompatMode::from_version(parse_version("v0.39.0"));
assert!(res.is_err());
Expand All @@ -153,10 +157,11 @@ mod tests {
fn test_from_str() {
assert_eq!("0.34".parse::<CompatMode>().unwrap(), CompatMode::V0_34);
assert_eq!("0.37".parse::<CompatMode>().unwrap(), CompatMode::V0_37);
assert_eq!("0.38".parse::<CompatMode>().unwrap(), CompatMode::V0_38);

let res = "0.33".parse::<CompatMode>();
assert!(res.is_err());
let res = "0.38".parse::<CompatMode>();
let res = "0.39".parse::<CompatMode>();
assert!(res.is_err());
let res = "foobar".parse::<CompatMode>();
assert!(res.is_err());
Expand Down
5 changes: 5 additions & 0 deletions rpc/src/client/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ macro_rules! perform_with_compat {
($self:expr, $request:expr) => {{
let request = $request;
match $self.compat {
CompatMode::V0_38 => {
$self
.perform_with_dialect(request, crate::dialect::v0_38::Dialect)
.await
},
CompatMode::V0_37 => {
$self
.perform_with_dialect(request, crate::dialect::v0_37::Dialect)
Expand Down
94 changes: 77 additions & 17 deletions rpc/src/client/transport/http.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
//! HTTP-based transport for Tendermint RPC Client.
use core::str::FromStr;
use core::time::Duration;

use async_trait::async_trait;
use reqwest::{header, Proxy};
use std::time::Duration;

use tendermint::{block::Height, evidence::Evidence, Hash};
use tendermint_config::net;

use super::auth;
use crate::client::{Client, CompatMode};
use crate::dialect::{v0_34, v0_37, v0_38, Dialect, LatestDialect};
use crate::endpoint;
use crate::prelude::*;
use crate::{
client::{Client, CompatMode},
dialect::{v0_34, Dialect, LatestDialect},
endpoint,
query::Query,
request::RequestMessage,
response::Response,
Error, Order, Scheme, SimpleRequest, Url,
};
use crate::query::Query;
use crate::request::RequestMessage;
use crate::response::Response;
use crate::{Error, Order, Scheme, SimpleRequest, Url};

use super::auth;

const USER_AGENT: &str = concat!("tendermint.rs/", env!("CARGO_PKG_VERSION"));

Expand Down Expand Up @@ -258,6 +257,24 @@ impl Client for HttpClient {
self.perform_with_dialect(request, LatestDialect).await
}

async fn block<H>(&self, height: H) -> Result<endpoint::block::Response, Error>
where
H: Into<Height> + Send,
{
perform_with_compat!(self, endpoint::block::Request::new(height.into()))
}

async fn block_by_hash(
&self,
hash: tendermint::Hash,
) -> Result<endpoint::block_by_hash::Response, Error> {
perform_with_compat!(self, endpoint::block_by_hash::Request::new(hash))
}

async fn latest_block(&self) -> Result<endpoint::block::Response, Error> {
perform_with_compat!(self, endpoint::block::Request::default())
}

async fn block_results<H>(&self, height: H) -> Result<endpoint::block_results::Response, Error>
where
H: Into<Height> + Send,
Expand All @@ -269,13 +286,33 @@ impl Client for HttpClient {
perform_with_compat!(self, endpoint::block_results::Request::default())
}

async fn block_search(
&self,
query: Query,
page: u32,
per_page: u8,
order: Order,
) -> Result<endpoint::block_search::Response, Error> {
perform_with_compat!(
self,
endpoint::block_search::Request::new(query, page, per_page, order)
)
}

async fn header<H>(&self, height: H) -> Result<endpoint::header::Response, Error>
where
H: Into<Height> + Send,
{
let height = height.into();
match self.compat {
CompatMode::V0_37 => self.perform(endpoint::header::Request::new(height)).await,
CompatMode::V0_38 => {
self.perform_with_dialect(endpoint::header::Request::new(height), v0_38::Dialect)
.await
},
CompatMode::V0_37 => {
self.perform_with_dialect(endpoint::header::Request::new(height), v0_37::Dialect)
.await
},
CompatMode::V0_34 => {
// Back-fill with a request to /block endpoint and
// taking just the header from the response.
Expand All @@ -292,9 +329,19 @@ impl Client for HttpClient {
hash: Hash,
) -> Result<endpoint::header_by_hash::Response, Error> {
match self.compat {
CompatMode::V0_38 => {
self.perform_with_dialect(
endpoint::header_by_hash::Request::new(hash),
v0_38::Dialect,
)
.await
},
CompatMode::V0_37 => {
self.perform(endpoint::header_by_hash::Request::new(hash))
.await
self.perform_with_dialect(
endpoint::header_by_hash::Request::new(hash),
v0_37::Dialect,
)
.await
},
CompatMode::V0_34 => {
// Back-fill with a request to /block_by_hash endpoint and
Expand All @@ -311,11 +358,24 @@ impl Client for HttpClient {
}

/// `/broadcast_evidence`: broadcast an evidence.
async fn broadcast_evidence(&self, e: Evidence) -> Result<endpoint::evidence::Response, Error> {
async fn broadcast_evidence(
&self,
evidence: Evidence,
) -> Result<endpoint::evidence::Response, Error> {
match self.compat {
CompatMode::V0_37 => self.perform(endpoint::evidence::Request::new(e)).await,
CompatMode::V0_38 => {
let request = endpoint::evidence::Request::new(evidence);
self.perform_with_dialect(request, crate::dialect::v0_38::Dialect)
.await
},
CompatMode::V0_37 => {
let request = endpoint::evidence::Request::new(evidence);
self.perform_with_dialect(request, crate::dialect::v0_37::Dialect)
.await
},
CompatMode::V0_34 => {
self.perform_with_dialect(endpoint::evidence::Request::new(e), v0_34::Dialect)
let request = endpoint::evidence::Request::new(evidence);
self.perform_with_dialect(request, crate::dialect::v0_34::Dialect)
.await
},
}
Expand Down
4 changes: 2 additions & 2 deletions rpc/src/client/transport/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use alloc::collections::BTreeMap as HashMap;

use async_trait::async_trait;

use crate::dialect::{v0_37, Dialect};
use crate::dialect::{v0_38, Dialect};
use crate::{
client::{
subscription::SubscriptionTx,
Expand Down Expand Up @@ -65,7 +65,7 @@ pub struct MockClient<M: MockRequestMatcher> {
impl<M: MockRequestMatcher> Client for MockClient<M> {
async fn perform<R>(&self, request: R) -> Result<R::Output, Error>
where
R: SimpleRequest<v0_37::Dialect>,
R: SimpleRequest<v0_38::Dialect>,
{
self.matcher
.response_for(request)
Expand Down
Loading

0 comments on commit db94695

Please sign in to comment.